From 42a1aaeec47bc34ae4a923e3e8b2e55b59c01711 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Jul 26 2019 15:46:42 +0000 Subject: btrfs-progs: deal with drop_progress properly in fsck While testing snapshot deletion with dm-log-writes I saw that I was failing the fsck sometimes when the fs was actually in the correct state. This is because we only skip blocks on the same level of root_item->drop_level. If the drop_level < the root level then we could very well walk into nodes that we wouldn't actually walk into on fs mount, because the drop_progress is further ahead in the slot of the root. Instead only process the slots of the nodes that are above the drop_progress key. With this patch in place we no longer improperly fail to check fs'es that have a drop_progress set with a drop_level < root level. Signed-off-by: Josef Bacik Signed-off-by: David Sterba --- diff --git a/check/main.c b/check/main.c index bb57933..8b340e5 100644 --- a/check/main.c +++ b/check/main.c @@ -6319,15 +6319,28 @@ static int run_next_block(struct btrfs_root *root, int level; level = btrfs_header_level(buf); - for (i = 0; i < nritems; i++) { + i = 0; + + /* + * If we have a drop key we need to not walk down any slots we + * would have ignored when mounting the fs. These blocks are + * technically unreferenced and don't need to be worried about. + */ + if (ri != NULL && ri->drop_level && level > ri->drop_level) { + ret = btrfs_bin_search(buf, &ri->drop_key, level, &i); + if (ret && i > 0) + i--; + } + + for (; i < nritems; i++) { struct extent_record tmpl; ptr = btrfs_node_blockptr(buf, i); size = root->fs_info->nodesize; btrfs_node_key_to_cpu(buf, &key, i); if (ri != NULL) { - if ((level == ri->drop_level) - && is_dropped_key(&key, &ri->drop_key)) { + if ((level == ri->drop_level) && + is_dropped_key(&key, &ri->drop_key)) { continue; } } diff --git a/ctree.c b/ctree.c index 76bc9c5..c97fbb4 100644 --- a/ctree.c +++ b/ctree.c @@ -633,8 +633,8 @@ static int generic_bin_search(struct extent_buffer *eb, unsigned long p, * simple bin_search frontend that does the right thing for * leaves vs nodes */ -static int bin_search(struct extent_buffer *eb, const struct btrfs_key *key, - int level, int *slot) +int btrfs_bin_search(struct extent_buffer *eb, const struct btrfs_key *key, + int level, int *slot) { if (level == 0) return generic_bin_search(eb, @@ -1167,7 +1167,7 @@ again: ret = check_block(fs_info, p, level); if (ret) return -1; - ret = bin_search(b, key, level, &slot); + ret = btrfs_bin_search(b, key, level, &slot); if (level != 0) { if (ret && slot > 0) slot -= 1; diff --git a/ctree.h b/ctree.h index c63fad8..b73abe1 100644 --- a/ctree.h +++ b/ctree.h @@ -2628,6 +2628,8 @@ int btrfs_search_slot_for_read(struct btrfs_root *root, const struct btrfs_key *key, struct btrfs_path *p, int find_higher, int return_any); +int btrfs_bin_search(struct extent_buffer *eb, const struct btrfs_key *key, + int level, int *slot); int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path, u64 iobjectid, u64 ioff, u8 key_type, struct btrfs_key *found_key);