summaryrefslogtreecommitdiff
path: root/check
diff options
context:
space:
mode:
authorNikolay Borisov <nborisov@suse.com>2018-06-18 14:10:58 +0300
committerDavid Sterba <dsterba@suse.com>2018-08-06 15:00:08 +0200
commitd4f19ad08475204baf3fd15b91bca25da7bef388 (patch)
treea9b0f53197e421554b3ba9e9db2f4d5052febba1 /check
parenta7773d7f0671aa28a20aa3a736f930e8d1cdbba9 (diff)
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 <nborisov@suse.com> Reviewed-by: Su Yue <suy.fnst@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'check')
-rw-r--r--check/main.c141
1 files changed, 85 insertions, 56 deletions
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