summaryrefslogtreecommitdiff
path: root/check
diff options
context:
space:
mode:
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