Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9069218d authored by Chris Mason's avatar Chris Mason
Browse files

Btrfs: Fix i_blocks accounting



Now that delayed allocation accounting works, i_blocks accounting is changed
to only modify i_blocks when extents inserted or removed.

The fillattr call is changed to include the delayed allocation byte count
in the i_blocks result.

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent a86c12c7
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ struct btrfs_inode {
	 * transid of the trans_handle that last modified this inode
	 */
	u64 last_trans;
	u64 delalloc_bytes;
	u32 flags;
};
static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
+9 −0
Original line number Diff line number Diff line
@@ -1161,6 +1161,15 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
			struct btrfs_root *root, struct btrfs_path *path,
			u64 isize);
/* inode.c */
static inline void dec_i_blocks(struct inode *inode, u64 dec)
{
	dec = dec >> 9;
	if (dec <= inode->i_blocks)
		inode->i_blocks -= dec;
	else
		inode->i_blocks = 0;
}

unsigned long btrfs_force_ra(struct address_space *mapping,
			      struct file_ra_state *ra, struct file *file,
			      pgoff_t offset, pgoff_t last_index);
+11 −6
Original line number Diff line number Diff line
@@ -175,6 +175,7 @@ static int noinline insert_inline_extent(struct btrfs_trans_handle *trans,
			leaf = path->nodes[0];
			ei = btrfs_item_ptr(leaf, path->slots[0],
					    struct btrfs_file_extent_item);
			inode->i_blocks += (offset + size - found_end) >> 9;
		}
		if (found_end < offset) {
			ptr = btrfs_file_extent_inline_start(ei) + found_size;
@@ -184,6 +185,7 @@ static int noinline insert_inline_extent(struct btrfs_trans_handle *trans,
insert:
		btrfs_release_path(root, path);
		datasize = offset + size - key.offset;
		inode->i_blocks += datasize >> 9;
		datasize = btrfs_file_extent_calc_inline_size(datasize);
		ret = btrfs_insert_empty_item(trans, root, path, &key,
					      datasize);
@@ -256,7 +258,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
		goto out_unlock;
	}
	btrfs_set_trans_block_group(trans, inode);
	inode->i_blocks += num_bytes >> 9;
	hint_byte = 0;

	if ((end_of_last_block & 4095) == 0) {
@@ -410,7 +411,7 @@ int btrfs_check_file(struct btrfs_root *root, struct inode *inode)
		if (found_key.type != BTRFS_EXTENT_DATA_KEY)
			goto out;

		if (found_key.offset != last_offset) {
		if (found_key.offset < last_offset) {
			WARN_ON(1);
			btrfs_print_leaf(root, leaf);
			printk("inode %lu found offset %Lu expected %Lu\n",
@@ -435,7 +436,7 @@ int btrfs_check_file(struct btrfs_root *root, struct inode *inode)
		last_offset = extent_end;
		path->slots[0]++;
	}
	if (last_offset < inode->i_size) {
	if (0 && last_offset < inode->i_size) {
		WARN_ON(1);
		btrfs_print_leaf(root, leaf);
		printk("inode %lu found offset %Lu size %Lu\n", inode->i_ino,
@@ -608,8 +609,7 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
								      extent);
				if (btrfs_file_extent_disk_bytenr(leaf,
								  extent)) {
					inode->i_blocks -=
						(old_num - new_num) >> 9;
					dec_i_blocks(inode, old_num - new_num);
				}
				btrfs_set_file_extent_num_bytes(leaf, extent,
								new_num);
@@ -620,6 +620,8 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
				u32 new_size;
				new_size = btrfs_file_extent_calc_inline_size(
						   inline_limit - key.offset);
				dec_i_blocks(inode, (extent_end - key.offset) -
					(inline_limit - key.offset));
				btrfs_truncate_item(trans, root, path,
						    new_size, 1);
			}
@@ -653,7 +655,7 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
			btrfs_release_path(root, path);
			extent = NULL;
			if (found_extent && disk_bytenr != 0) {
				inode->i_blocks -= extent_num_bytes >> 9;
				dec_i_blocks(inode, extent_num_bytes);
				ret = btrfs_free_extent(trans, root,
						disk_bytenr,
						disk_num_bytes,
@@ -674,6 +676,8 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
			u32 new_size;
			new_size = btrfs_file_extent_calc_inline_size(
						   extent_end - end);
			dec_i_blocks(inode, (extent_end - key.offset) -
					(extent_end - end));
			btrfs_truncate_item(trans, root, path, new_size, 0);
		}
		/* create bookend, splitting the extent in two */
@@ -718,6 +722,7 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
	}
out:
	btrfs_free_path(path);
	btrfs_check_file(root, inode);
	return ret;
}

+29 −14
Original line number Diff line number Diff line
@@ -134,6 +134,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
		ret = btrfs_insert_file_extent(trans, root, inode->i_ino,
					       start, ins.objectid, ins.offset,
					       ins.offset);
		inode->i_blocks += ins.offset >> 9;
		btrfs_check_file(root, inode);
		num_bytes -= cur_alloc_size;
		alloc_hint = ins.objectid + ins.offset;
@@ -142,6 +143,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
	btrfs_drop_extent_cache(inode, orig_start,
				orig_start + orig_num_bytes - 1);
	btrfs_add_ordered_inode(inode);
	btrfs_update_inode(trans, root, inode);
out:
	btrfs_end_transaction(trans, root);
	return ret;
@@ -265,6 +267,7 @@ int btrfs_set_bit_hook(struct inode *inode, u64 start, u64 end,
	if (!(old & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
		struct btrfs_root *root = BTRFS_I(inode)->root;
		spin_lock(&root->fs_info->delalloc_lock);
		BTRFS_I(inode)->delalloc_bytes += end - start + 1;
		root->fs_info->delalloc_bytes += end - start + 1;
		spin_unlock(&root->fs_info->delalloc_lock);
	}
@@ -281,8 +284,10 @@ int btrfs_clear_bit_hook(struct inode *inode, u64 start, u64 end,
			printk("warning: delalloc account %Lu %Lu\n",
			       end - start + 1, root->fs_info->delalloc_bytes);
			root->fs_info->delalloc_bytes = 0;
			BTRFS_I(inode)->delalloc_bytes = 0;
		} else {
			root->fs_info->delalloc_bytes -= end - start + 1;
			BTRFS_I(inode)->delalloc_bytes -= end - start + 1;
		}
		spin_unlock(&root->fs_info->delalloc_lock);
	}
@@ -833,32 +838,37 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
				btrfs_set_file_extent_num_bytes(leaf, fi,
							 extent_num_bytes);
				num_dec = (orig_num_bytes -
					   extent_num_bytes) >> 9;
				if (extent_start != 0) {
					inode->i_blocks -= num_dec;
				}
					   extent_num_bytes);
				if (extent_start != 0)
					dec_i_blocks(inode, num_dec);
				btrfs_mark_buffer_dirty(leaf);
			} else {
				extent_num_bytes =
					btrfs_file_extent_disk_num_bytes(leaf,
									 fi);
				/* FIXME blocksize != 4096 */
				num_dec = btrfs_file_extent_num_bytes(leaf,
								       fi) >> 9;
				num_dec = btrfs_file_extent_num_bytes(leaf, fi);
				if (extent_start != 0) {
					found_extent = 1;
					inode->i_blocks -= num_dec;
					dec_i_blocks(inode, num_dec);
				}
				root_gen = btrfs_header_generation(leaf);
				root_owner = btrfs_header_owner(leaf);
			}
		} else if (extent_type == BTRFS_FILE_EXTENT_INLINE &&
			   !del_item) {
		} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
			if (!del_item) {
				u32 newsize = inode->i_size - found_key.offset;
			newsize = btrfs_file_extent_calc_inline_size(newsize);
				dec_i_blocks(inode, item_end + 1 -
					    found_key.offset - newsize);
				newsize =
				    btrfs_file_extent_calc_inline_size(newsize);
				ret = btrfs_truncate_item(trans, root, path,
							  newsize, 1);
				BUG_ON(ret);
			} else {
				dec_i_blocks(inode, item_end + 1 -
					     found_key.offset);
			}
		}
delete:
		if (del_item) {
@@ -1222,6 +1232,7 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p)
	struct btrfs_iget_args *args = p;
	inode->i_ino = args->ino;
	BTRFS_I(inode)->root = args->root;
	BTRFS_I(inode)->delalloc_bytes = 0;
	extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
	extent_io_tree_init(&BTRFS_I(inode)->io_tree,
			     inode->i_mapping, GFP_NOFS);
@@ -1528,6 +1539,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
	extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
	extent_io_tree_init(&BTRFS_I(inode)->io_tree,
			     inode->i_mapping, GFP_NOFS);
	BTRFS_I(inode)->delalloc_bytes = 0;
	BTRFS_I(inode)->root = root;

	if (mode & S_IFDIR)
@@ -1746,6 +1758,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
		extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
		extent_io_tree_init(&BTRFS_I(inode)->io_tree,
				     inode->i_mapping, GFP_NOFS);
		BTRFS_I(inode)->delalloc_bytes = 0;
		BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
	}
	dir->i_sb->s_dirt = 1;
@@ -2797,6 +2810,7 @@ static int btrfs_getattr(struct vfsmount *mnt,
	struct inode *inode = dentry->d_inode;
	generic_fillattr(inode, stat);
	stat->blksize = PAGE_CACHE_SIZE;
	stat->blocks = inode->i_blocks + (BTRFS_I(inode)->delalloc_bytes >> 9);
	return 0;
}

@@ -2912,6 +2926,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
		extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
		extent_io_tree_init(&BTRFS_I(inode)->io_tree,
				     inode->i_mapping, GFP_NOFS);
		BTRFS_I(inode)->delalloc_bytes = 0;
		BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
	}
	dir->i_sb->s_dirt = 1;