summaryrefslogtreecommitdiff
path: root/cmds-check.c
diff options
context:
space:
mode:
authorQu Wenruo <quwenruo@cn.fujitsu.com>2014-10-30 10:54:03 +0800
committerDavid Sterba <dsterba@suse.cz>2014-12-04 16:48:13 +0100
commit0ffacad2906cdb8f62fb56565632160a1a82ad14 (patch)
tree7534854b9e8a2b820b1591c26e41410cb8b1e28e /cmds-check.c
parente7c4e700ffa656af4b221a2068b02b391b0ed817 (diff)
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 <quwenruo@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.cz>
Diffstat (limited to 'cmds-check.c')
-rw-r--r--cmds-check.c29
1 files changed, 18 insertions, 11 deletions
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;