From d4f19ad08475204baf3fd15b91bca25da7bef388 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Mon, 18 Jun 2018 14:10:58 +0300 Subject: btrfs-progs: check: factor out root parsing from check_chunks_and_extents check_chunks_and_extents does quite a number of distinct things. The first of those is going through all root items in the root tree and classify every root depending on whether they have a dropping operation in progress or not. Lets factor out this code and move the variables specific to this in a separate function so clean up check_chunks_and_extents a bit. Accidentally, this patch fixes some reference leaks since in error conditions in the loop the code does "goto out" but at that label we don't really release the path. Having this code extracted in a separate function which always releases the path avoids this problem entirely. Signed-off-by: Nikolay Borisov Reviewed-by: Su Yue Signed-off-by: David Sterba --- check/main.c | 141 +++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 85 insertions(+), 56 deletions(-) (limited to 'check') diff --git a/check/main.c b/check/main.c index 2a74e7d2..c25c50ef 100644 --- a/check/main.c +++ b/check/main.c @@ -8075,6 +8075,89 @@ static int deal_root_from_list(struct list_head *list, return ret; } +/** + * parse_tree_roots - Go over all roots in the tree root and add each one to + * a list. + * + * @fs_info - pointer to fs_info struct of the file system. + * + * @normal_trees - list to contains all roots which don't have a drop + * operation in progress + * + * @dropping_trees - list containing all roots which have a drop operation + * pending + * + * Returns 0 on success or a negative value indicating an error. + */ +static int parse_tree_roots(struct btrfs_fs_info *fs_info, + struct list_head *normal_trees, + struct list_head *dropping_trees) +{ + struct btrfs_path path; + struct btrfs_key key; + struct btrfs_key found_key; + struct btrfs_root_item ri; + struct extent_buffer *leaf; + int slot; + int ret = 0; + + btrfs_init_path(&path); + key.offset = 0; + key.objectid = 0; + key.type = BTRFS_ROOT_ITEM_KEY; + ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, &path, 0, 0); + if (ret < 0) + goto out; + while (1) { + leaf = path.nodes[0]; + slot = path.slots[0]; + if (slot >= btrfs_header_nritems(path.nodes[0])) { + ret = btrfs_next_leaf(fs_info->tree_root, &path); + if (ret != 0) + break; + leaf = path.nodes[0]; + slot = path.slots[0]; + } + btrfs_item_key_to_cpu(leaf, &found_key, path.slots[0]); + if (found_key.type == BTRFS_ROOT_ITEM_KEY) { + unsigned long offset; + u64 last_snapshot; + u8 level; + + offset = btrfs_item_ptr_offset(leaf, path.slots[0]); + read_extent_buffer(leaf, &ri, offset, sizeof(ri)); + last_snapshot = btrfs_root_last_snapshot(&ri); + level = btrfs_root_level(&ri); + if (btrfs_disk_key_objectid(&ri.drop_progress) == 0) { + ret = add_root_item_to_list(normal_trees, + found_key.objectid, + btrfs_root_bytenr(&ri), + last_snapshot, level, + 0, NULL); + if (ret < 0) + break; + } else { + u64 objectid = found_key.objectid; + + btrfs_disk_key_to_cpu(&found_key, + &ri.drop_progress); + ret = add_root_item_to_list(dropping_trees, + objectid, + btrfs_root_bytenr(&ri), + last_snapshot, level, + ri.drop_level, &found_key); + if (ret < 0) + break; + } + } + path.slots[0]++; + } + +out: + btrfs_release_path(&path); + return ret; +} + static int check_chunks_and_extents(struct btrfs_fs_info *fs_info) { struct rb_root dev_cache; @@ -8088,20 +8171,13 @@ static int check_chunks_and_extents(struct btrfs_fs_info *fs_info) struct cache_tree nodes; struct extent_io_tree excluded_extents; struct cache_tree corrupt_blocks; - struct btrfs_path path; - struct btrfs_key key; - struct btrfs_key found_key; int ret, err = 0; struct block_info *bits; int bits_nr; - struct extent_buffer *leaf; - int slot; - struct btrfs_root_item ri; struct list_head dropping_trees; struct list_head normal_trees; struct btrfs_root *root1; struct btrfs_root *root; - u64 objectid; u8 level; root = fs_info->fs_root; @@ -8152,57 +8228,10 @@ again: root1->node->start, 0, level, 0, NULL); if (ret < 0) goto out; - btrfs_init_path(&path); - key.offset = 0; - key.objectid = 0; - key.type = BTRFS_ROOT_ITEM_KEY; - ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, &path, 0, 0); + + ret = parse_tree_roots(fs_info, &normal_trees, &dropping_trees); if (ret < 0) goto out; - while (1) { - leaf = path.nodes[0]; - slot = path.slots[0]; - if (slot >= btrfs_header_nritems(path.nodes[0])) { - ret = btrfs_next_leaf(fs_info->tree_root, &path); - if (ret != 0) - break; - leaf = path.nodes[0]; - slot = path.slots[0]; - } - btrfs_item_key_to_cpu(leaf, &found_key, path.slots[0]); - if (found_key.type == BTRFS_ROOT_ITEM_KEY) { - unsigned long offset; - u64 last_snapshot; - - offset = btrfs_item_ptr_offset(leaf, path.slots[0]); - read_extent_buffer(leaf, &ri, offset, sizeof(ri)); - last_snapshot = btrfs_root_last_snapshot(&ri); - if (btrfs_disk_key_objectid(&ri.drop_progress) == 0) { - level = btrfs_root_level(&ri); - ret = add_root_item_to_list(&normal_trees, - found_key.objectid, - btrfs_root_bytenr(&ri), - last_snapshot, level, - 0, NULL); - if (ret < 0) - goto out; - } else { - level = btrfs_root_level(&ri); - objectid = found_key.objectid; - btrfs_disk_key_to_cpu(&found_key, - &ri.drop_progress); - ret = add_root_item_to_list(&dropping_trees, - objectid, - btrfs_root_bytenr(&ri), - last_snapshot, level, - ri.drop_level, &found_key); - if (ret < 0) - goto out; - } - } - path.slots[0]++; - } - btrfs_release_path(&path); /* * check_block can return -EAGAIN if it fixes something, please keep -- cgit v1.2.3