Reviewed-and-Tested-by: Goldwyn Rodrigues <rgold...@suse.com> On 10/17/2016 08:31 PM, Qu Wenruo wrote: > Move account_shared_subtree() to qgroup.c and rename it to > btrfs_qgroup_trace_subtree(). > > Do the same thing for account_leaf_items() and rename it to > btrfs_qgroup_trace_leaf_items(). > > Since all these functions are only for qgroup, move them to qgroup.c and > export them is more appropriate. > > Signed-off-by: Qu Wenruo <quwen...@cn.fujitsu.com> > --- > fs/btrfs/extent-tree.c | 220 > +------------------------------------------------ > fs/btrfs/qgroup.c | 211 +++++++++++++++++++++++++++++++++++++++++++++++ > fs/btrfs/qgroup.h | 23 ++++++ > 3 files changed, 237 insertions(+), 217 deletions(-) > > diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c > index 024eb5d..f7aa49d 100644 > --- a/fs/btrfs/extent-tree.c > +++ b/fs/btrfs/extent-tree.c > @@ -8535,220 +8535,6 @@ reada: > wc->reada_slot = slot; > } > > -static int account_leaf_items(struct btrfs_trans_handle *trans, > - struct btrfs_root *root, > - struct extent_buffer *eb) > -{ > - int nr = btrfs_header_nritems(eb); > - int i, extent_type, ret; > - struct btrfs_key key; > - struct btrfs_file_extent_item *fi; > - u64 bytenr, num_bytes; > - > - /* We can be called directly from walk_up_proc() */ > - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags)) > - return 0; > - > - for (i = 0; i < nr; i++) { > - btrfs_item_key_to_cpu(eb, &key, i); > - > - if (key.type != BTRFS_EXTENT_DATA_KEY) > - continue; > - > - fi = btrfs_item_ptr(eb, i, struct btrfs_file_extent_item); > - /* filter out non qgroup-accountable extents */ > - extent_type = btrfs_file_extent_type(eb, fi); > - > - if (extent_type == BTRFS_FILE_EXTENT_INLINE) > - continue; > - > - bytenr = btrfs_file_extent_disk_bytenr(eb, fi); > - if (!bytenr) > - continue; > - > - num_bytes = btrfs_file_extent_disk_num_bytes(eb, fi); > - > - ret = btrfs_qgroup_trace_extent(trans, root->fs_info, > - bytenr, num_bytes, GFP_NOFS); > - if (ret) > - return ret; > - } > - return 0; > -} > - > -/* > - * Walk up the tree from the bottom, freeing leaves and any interior > - * nodes which have had all slots visited. If a node (leaf or > - * interior) is freed, the node above it will have it's slot > - * incremented. The root node will never be freed. > - * > - * At the end of this function, we should have a path which has all > - * slots incremented to the next position for a search. If we need to > - * read a new node it will be NULL and the node above it will have the > - * correct slot selected for a later read. > - * > - * If we increment the root nodes slot counter past the number of > - * elements, 1 is returned to signal completion of the search. > - */ > -static int adjust_slots_upwards(struct btrfs_root *root, > - struct btrfs_path *path, int root_level) > -{ > - int level = 0; > - int nr, slot; > - struct extent_buffer *eb; > - > - if (root_level == 0) > - return 1; > - > - while (level <= root_level) { > - eb = path->nodes[level]; > - nr = btrfs_header_nritems(eb); > - path->slots[level]++; > - slot = path->slots[level]; > - if (slot >= nr || level == 0) { > - /* > - * Don't free the root - we will detect this > - * condition after our loop and return a > - * positive value for caller to stop walking the tree. > - */ > - if (level != root_level) { > - btrfs_tree_unlock_rw(eb, path->locks[level]); > - path->locks[level] = 0; > - > - free_extent_buffer(eb); > - path->nodes[level] = NULL; > - path->slots[level] = 0; > - } > - } else { > - /* > - * We have a valid slot to walk back down > - * from. Stop here so caller can process these > - * new nodes. > - */ > - break; > - } > - > - level++; > - } > - > - eb = path->nodes[root_level]; > - if (path->slots[root_level] >= btrfs_header_nritems(eb)) > - return 1; > - > - return 0; > -} > - > -/* > - * root_eb is the subtree root and is locked before this function is called. > - */ > -static int account_shared_subtree(struct btrfs_trans_handle *trans, > - struct btrfs_root *root, > - struct extent_buffer *root_eb, > - u64 root_gen, > - int root_level) > -{ > - int ret = 0; > - int level; > - struct extent_buffer *eb = root_eb; > - struct btrfs_path *path = NULL; > - > - BUG_ON(root_level < 0 || root_level > BTRFS_MAX_LEVEL); > - BUG_ON(root_eb == NULL); > - > - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags)) > - return 0; > - > - if (!extent_buffer_uptodate(root_eb)) { > - ret = btrfs_read_buffer(root_eb, root_gen); > - if (ret) > - goto out; > - } > - > - if (root_level == 0) { > - ret = account_leaf_items(trans, root, root_eb); > - goto out; > - } > - > - path = btrfs_alloc_path(); > - if (!path) > - return -ENOMEM; > - > - /* > - * Walk down the tree. Missing extent blocks are filled in as > - * we go. Metadata is accounted every time we read a new > - * extent block. > - * > - * When we reach a leaf, we account for file extent items in it, > - * walk back up the tree (adjusting slot pointers as we go) > - * and restart the search process. > - */ > - extent_buffer_get(root_eb); /* For path */ > - path->nodes[root_level] = root_eb; > - path->slots[root_level] = 0; > - path->locks[root_level] = 0; /* so release_path doesn't try to unlock */ > -walk_down: > - level = root_level; > - while (level >= 0) { > - if (path->nodes[level] == NULL) { > - int parent_slot; > - u64 child_gen; > - u64 child_bytenr; > - > - /* We need to get child blockptr/gen from > - * parent before we can read it. */ > - eb = path->nodes[level + 1]; > - parent_slot = path->slots[level + 1]; > - child_bytenr = btrfs_node_blockptr(eb, parent_slot); > - child_gen = btrfs_node_ptr_generation(eb, parent_slot); > - > - eb = read_tree_block(root, child_bytenr, child_gen); > - if (IS_ERR(eb)) { > - ret = PTR_ERR(eb); > - goto out; > - } else if (!extent_buffer_uptodate(eb)) { > - free_extent_buffer(eb); > - ret = -EIO; > - goto out; > - } > - > - path->nodes[level] = eb; > - path->slots[level] = 0; > - > - btrfs_tree_read_lock(eb); > - btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); > - path->locks[level] = BTRFS_READ_LOCK_BLOCKING; > - > - ret = btrfs_qgroup_trace_extent(trans, > - root->fs_info, child_bytenr, > - root->nodesize, GFP_NOFS); > - if (ret) > - goto out; > - } > - > - if (level == 0) { > - ret = account_leaf_items(trans, root, > path->nodes[level]); > - if (ret) > - goto out; > - > - /* Nonzero return here means we completed our search */ > - ret = adjust_slots_upwards(root, path, root_level); > - if (ret) > - break; > - > - /* Restart search with new slots */ > - goto walk_down; > - } > - > - level--; > - } > - > - ret = 0; > -out: > - btrfs_free_path(path); > - > - return ret; > -} > - > /* > * helper to process tree block while walking down the tree. > * > @@ -8977,8 +8763,8 @@ skip: > } > > if (need_account) { > - ret = account_shared_subtree(trans, root, next, > - generation, level - 1); > + ret = btrfs_qgroup_trace_subtree(trans, root, next, > + generation, level - 1); > if (ret) { > btrfs_err_rl(root->fs_info, > "Error %d accounting shared > subtree. Quota is out of sync, rescan required.", > @@ -9075,7 +8861,7 @@ static noinline int walk_up_proc(struct > btrfs_trans_handle *trans, > else > ret = btrfs_dec_ref(trans, root, eb, 0); > BUG_ON(ret); /* -ENOMEM */ > - ret = account_leaf_items(trans, root, eb); > + ret = btrfs_qgroup_trace_leaf_items(trans, root, eb); > if (ret) { > btrfs_err_rl(root->fs_info, > "error %d accounting leaf items. > Quota is out of sync, rescan required.", > diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c > index e73eea3..e97f304 100644 > --- a/fs/btrfs/qgroup.c > +++ b/fs/btrfs/qgroup.c > @@ -1510,6 +1510,217 @@ int btrfs_qgroup_trace_extent(struct > btrfs_trans_handle *trans, > return 0; > } > > +int btrfs_qgroup_trace_leaf_items(struct btrfs_trans_handle *trans, > + struct btrfs_root *root, > + struct extent_buffer *eb) > +{ > + int nr = btrfs_header_nritems(eb); > + int i, extent_type, ret; > + struct btrfs_key key; > + struct btrfs_file_extent_item *fi; > + u64 bytenr, num_bytes; > + > + /* We can be called directly from walk_up_proc() */ > + if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags)) > + return 0; > + > + for (i = 0; i < nr; i++) { > + btrfs_item_key_to_cpu(eb, &key, i); > + > + if (key.type != BTRFS_EXTENT_DATA_KEY) > + continue; > + > + fi = btrfs_item_ptr(eb, i, struct btrfs_file_extent_item); > + /* filter out non qgroup-accountable extents */ > + extent_type = btrfs_file_extent_type(eb, fi); > + > + if (extent_type == BTRFS_FILE_EXTENT_INLINE) > + continue; > + > + bytenr = btrfs_file_extent_disk_bytenr(eb, fi); > + if (!bytenr) > + continue; > + > + num_bytes = btrfs_file_extent_disk_num_bytes(eb, fi); > + > + ret = btrfs_qgroup_trace_extent(trans, root->fs_info, > + bytenr, num_bytes, GFP_NOFS); > + if (ret) > + return ret; > + } > + return 0; > +} > + > +/* > + * Walk up the tree from the bottom, freeing leaves and any interior > + * nodes which have had all slots visited. If a node (leaf or > + * interior) is freed, the node above it will have it's slot > + * incremented. The root node will never be freed. > + * > + * At the end of this function, we should have a path which has all > + * slots incremented to the next position for a search. If we need to > + * read a new node it will be NULL and the node above it will have the > + * correct slot selected for a later read. > + * > + * If we increment the root nodes slot counter past the number of > + * elements, 1 is returned to signal completion of the search. > + */ > +static int adjust_slots_upwards(struct btrfs_root *root, > + struct btrfs_path *path, int root_level) > +{ > + int level = 0; > + int nr, slot; > + struct extent_buffer *eb; > + > + if (root_level == 0) > + return 1; > + > + while (level <= root_level) { > + eb = path->nodes[level]; > + nr = btrfs_header_nritems(eb); > + path->slots[level]++; > + slot = path->slots[level]; > + if (slot >= nr || level == 0) { > + /* > + * Don't free the root - we will detect this > + * condition after our loop and return a > + * positive value for caller to stop walking the tree. > + */ > + if (level != root_level) { > + btrfs_tree_unlock_rw(eb, path->locks[level]); > + path->locks[level] = 0; > + > + free_extent_buffer(eb); > + path->nodes[level] = NULL; > + path->slots[level] = 0; > + } > + } else { > + /* > + * We have a valid slot to walk back down > + * from. Stop here so caller can process these > + * new nodes. > + */ > + break; > + } > + > + level++; > + } > + > + eb = path->nodes[root_level]; > + if (path->slots[root_level] >= btrfs_header_nritems(eb)) > + return 1; > + > + return 0; > +} > + > +int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, > + struct btrfs_root *root, > + struct extent_buffer *root_eb, > + u64 root_gen, int root_level) > +{ > + int ret = 0; > + int level; > + struct extent_buffer *eb = root_eb; > + struct btrfs_path *path = NULL; > + > + BUG_ON(root_level < 0 || root_level > BTRFS_MAX_LEVEL); > + BUG_ON(root_eb == NULL); > + > + if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags)) > + return 0; > + > + if (!extent_buffer_uptodate(root_eb)) { > + ret = btrfs_read_buffer(root_eb, root_gen); > + if (ret) > + goto out; > + } > + > + if (root_level == 0) { > + ret = btrfs_qgroup_trace_leaf_items(trans, root, root_eb); > + goto out; > + } > + > + path = btrfs_alloc_path(); > + if (!path) > + return -ENOMEM; > + > + /* > + * Walk down the tree. Missing extent blocks are filled in as > + * we go. Metadata is accounted every time we read a new > + * extent block. > + * > + * When we reach a leaf, we account for file extent items in it, > + * walk back up the tree (adjusting slot pointers as we go) > + * and restart the search process. > + */ > + extent_buffer_get(root_eb); /* For path */ > + path->nodes[root_level] = root_eb; > + path->slots[root_level] = 0; > + path->locks[root_level] = 0; /* so release_path doesn't try to unlock */ > +walk_down: > + level = root_level; > + while (level >= 0) { > + if (path->nodes[level] == NULL) { > + int parent_slot; > + u64 child_gen; > + u64 child_bytenr; > + > + /* We need to get child blockptr/gen from > + * parent before we can read it. */ > + eb = path->nodes[level + 1]; > + parent_slot = path->slots[level + 1]; > + child_bytenr = btrfs_node_blockptr(eb, parent_slot); > + child_gen = btrfs_node_ptr_generation(eb, parent_slot); > + > + eb = read_tree_block(root, child_bytenr, child_gen); > + if (IS_ERR(eb)) { > + ret = PTR_ERR(eb); > + goto out; > + } else if (!extent_buffer_uptodate(eb)) { > + free_extent_buffer(eb); > + ret = -EIO; > + goto out; > + } > + > + path->nodes[level] = eb; > + path->slots[level] = 0; > + > + btrfs_tree_read_lock(eb); > + btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); > + path->locks[level] = BTRFS_READ_LOCK_BLOCKING; > + > + ret = btrfs_qgroup_trace_extent(trans, > + root->fs_info, child_bytenr, > + root->nodesize, GFP_NOFS); > + if (ret) > + goto out; > + } > + > + if (level == 0) { > + ret = btrfs_qgroup_trace_leaf_items(trans, root, > + path->nodes[level]); > + if (ret) > + goto out; > + > + /* Nonzero return here means we completed our search */ > + ret = adjust_slots_upwards(root, path, root_level); > + if (ret) > + break; > + > + /* Restart search with new slots */ > + goto walk_down; > + } > + > + level--; > + } > + > + ret = 0; > +out: > + btrfs_free_path(path); > + > + return ret; > +} > + > #define UPDATE_NEW 0 > #define UPDATE_OLD 1 > /* > diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h > index 9303e09..99c879d 100644 > --- a/fs/btrfs/qgroup.h > +++ b/fs/btrfs/qgroup.h > @@ -122,6 +122,29 @@ int btrfs_qgroup_trace_extent(struct btrfs_trans_handle > *trans, > struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes, > gfp_t gfp_flag); > > +/* > + * Inform qgroup to trace all leaf items of data > + * > + * Return 0 for success > + * Return <0 for error(ENOMEM) > + */ > +int btrfs_qgroup_trace_leaf_items(struct btrfs_trans_handle *trans, > + struct btrfs_root *root, > + struct extent_buffer *eb); > +/* > + * Inform qgroup to trace a whole subtree, including all its child tree > + * blocks and data. > + * The root tree block is specified by @root_eb. > + * > + * Normally used by relocation(tree block swap) and subvolume deletion. > + * > + * Return 0 for success > + * Return <0 for error(ENOMEM or tree search error) > + */ > +int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, > + struct btrfs_root *root, > + struct extent_buffer *root_eb, > + u64 root_gen, int root_level); > int > btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, > struct btrfs_fs_info *fs_info, >
-- Goldwyn -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html