From 0ffacad2906cdb8f62fb56565632160a1a82ad14 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 30 Oct 2014 10:54:03 +0800 Subject: btrfs-progs: rebuild missing block group during chunk recovery if possible Before the patch, chunk will be considered bad if the corresponding block group is missing, even the only uncertain data is the 'used' member of the block group. This patch will try to recalculate the 'used' value of the block group and rebuild it. So even only chunk item and dev extent item is found, the chunk can be recovered. Although if extent tree is damanged and needed extent item can't be read, the block group's 'used' value will be the block group length, to prevent any later write/block reserve damaging the block group. In that case, we will prompt user and recommend them to use '--init-extent-tree' to rebuild extent tree if possible. Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- cmds-check.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'cmds-check.c') diff --git a/cmds-check.c b/cmds-check.c index 9fc14101..d4274058 100644 --- a/cmds-check.c +++ b/cmds-check.c @@ -6257,6 +6257,13 @@ u64 calc_stripe_length(u64 type, u64 length, int num_stripes) return stripe_size; } +/* + * Check the chunk with its block group/dev list ref: + * Return 0 if all refs seems valid. + * Return 1 if part of refs seems valid, need later check for rebuild ref + * like missing block group and needs to search extent tree to rebuild them. + * Return -1 if essential refs are missing and unable to rebuild. + */ static int check_chunk_refs(struct chunk_record *chunk_rec, struct block_group_tree *block_group_cache, struct device_extent_tree *dev_extent_cache, @@ -6312,7 +6319,7 @@ static int check_chunk_refs(struct chunk_record *chunk_rec, chunk_rec->length, chunk_rec->offset, chunk_rec->type_flags); - ret = -1; + ret = 1; } length = calc_stripe_length(chunk_rec->type_flags, chunk_rec->length, @@ -6365,7 +6372,8 @@ static int check_chunk_refs(struct chunk_record *chunk_rec, int check_chunks(struct cache_tree *chunk_cache, struct block_group_tree *block_group_cache, struct device_extent_tree *dev_extent_cache, - struct list_head *good, struct list_head *bad, int silent) + struct list_head *good, struct list_head *bad, + struct list_head *rebuild, int silent) { struct cache_extent *chunk_item; struct chunk_record *chunk_rec; @@ -6380,15 +6388,14 @@ int check_chunks(struct cache_tree *chunk_cache, cache); err = check_chunk_refs(chunk_rec, block_group_cache, dev_extent_cache, silent); - if (err) { + if (err) ret = err; - if (bad) - list_add_tail(&chunk_rec->list, bad); - } else { - if (good) - list_add_tail(&chunk_rec->list, good); - } - + if (err == 0 && good) + list_add_tail(&chunk_rec->list, good); + if (err > 0 && rebuild) + list_add_tail(&chunk_rec->list, rebuild); + if (err < 0 && bad) + list_add_tail(&chunk_rec->list, bad); chunk_item = next_cache_extent(chunk_item); } @@ -6672,7 +6679,7 @@ again: } err = check_chunks(&chunk_cache, &block_group_cache, - &dev_extent_cache, NULL, NULL, 0); + &dev_extent_cache, NULL, NULL, NULL, 0); if (err && !ret) ret = err; -- cgit v1.2.3