btrfs-progs: Make csum tree rebuild works with extent tree rebuild.

Before this patch, csum tree rebuild will not work with extent tree
rebuild, since extent tree rebuild will only build up basic block
groups, but csum tree rebuild needs data extents to rebuild.
So if one use btrfsck with --init-csum-tree and --init-extent-tree, csum
tree will be empty and tons of "missing csum" error will be outputted.

This patch allows csum tree rebuild get its data from fs/subvol trees
using regular file extents (which is also the only one using csum tree
currently).

Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
[renamed to fill_csum_tree_from_one_fs_root]
Signed-off-by: David Sterba <dsterba@suse.cz>
master
Qu Wenruo 2015-01-26 13:53:02 +08:00 committed by David Sterba
parent 7a7d5f019f
commit 25db1dd11d
1 changed files with 155 additions and 3 deletions

View File

@ -8622,8 +8622,142 @@ static int populate_csum(struct btrfs_trans_handle *trans,
return ret;
}
static int fill_csum_tree(struct btrfs_trans_handle *trans,
struct btrfs_root *csum_root)
static int fill_csum_tree_from_one_fs_root(struct btrfs_trans_handle *trans,
struct btrfs_root *csum_root,
struct btrfs_root *cur_root)
{
struct btrfs_path *path;
struct btrfs_key key;
struct extent_buffer *node;
struct btrfs_file_extent_item *fi;
char *buf = NULL;
u64 start = 0;
u64 len = 0;
int slot = 0;
int ret = 0;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
buf = malloc(cur_root->fs_info->csum_root->sectorsize);
if (!buf) {
ret = -ENOMEM;
goto out;
}
key.objectid = 0;
key.offset = 0;
key.type = 0;
ret = btrfs_search_slot(NULL, cur_root, &key, path, 0, 0);
if (ret < 0)
goto out;
/* Iterate all regular file extents and fill its csum */
while (1) {
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
if (key.type != BTRFS_EXTENT_DATA_KEY)
goto next;
node = path->nodes[0];
slot = path->slots[0];
fi = btrfs_item_ptr(node, slot, struct btrfs_file_extent_item);
if (btrfs_file_extent_type(node, fi) != BTRFS_FILE_EXTENT_REG)
goto next;
start = btrfs_file_extent_disk_bytenr(node, fi);
len = btrfs_file_extent_disk_num_bytes(node, fi);
ret = populate_csum(trans, csum_root, buf, start, len);
if (ret == -EEXIST)
ret = 0;
if (ret < 0)
goto out;
next:
/*
* TODO: if next leaf is corrupted, jump to nearest next valid
* leaf.
*/
ret = btrfs_next_item(cur_root, path);
if (ret < 0)
goto out;
if (ret > 0) {
ret = 0;
goto out;
}
}
out:
btrfs_free_path(path);
free(buf);
return ret;
}
static int fill_csum_tree_from_fs(struct btrfs_trans_handle *trans,
struct btrfs_root *csum_root)
{
struct btrfs_fs_info *fs_info = csum_root->fs_info;
struct btrfs_path *path;
struct btrfs_root *tree_root = fs_info->tree_root;
struct btrfs_root *cur_root;
struct extent_buffer *node;
struct btrfs_key key;
int slot = 0;
int ret = 0;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
key.objectid = BTRFS_FS_TREE_OBJECTID;
key.offset = 0;
key.type = BTRFS_ROOT_ITEM_KEY;
ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
if (ret < 0)
goto out;
if (ret > 0) {
ret = -ENOENT;
goto out;
}
while (1) {
node = path->nodes[0];
slot = path->slots[0];
btrfs_item_key_to_cpu(node, &key, slot);
if (key.objectid > BTRFS_LAST_FREE_OBJECTID)
goto out;
if (key.type != BTRFS_ROOT_ITEM_KEY)
goto next;
if (!is_fstree(key.objectid))
goto next;
key.offset = (u64)-1;
cur_root = btrfs_read_fs_root(fs_info, &key);
if (IS_ERR(cur_root) || !cur_root) {
fprintf(stderr, "Fail to read fs/subvol tree: %lld\n",
key.objectid);
goto out;
}
ret = fill_csum_tree_from_one_fs_root(trans, csum_root,
cur_root);
if (ret < 0)
goto out;
next:
ret = btrfs_next_item(tree_root, path);
if (ret > 0) {
ret = 0;
goto out;
}
if (ret < 0)
goto out;
}
out:
btrfs_free_path(path);
return ret;
}
static int fill_csum_tree_from_extent(struct btrfs_trans_handle *trans,
struct btrfs_root *csum_root)
{
struct btrfs_root *extent_root = csum_root->fs_info->extent_root;
struct btrfs_path *path;
@ -8691,6 +8825,23 @@ static int fill_csum_tree(struct btrfs_trans_handle *trans,
return ret;
}
/*
* Recalculate the csum and put it into the csum tree.
*
* Extent tree init will wipe out all the extent info, so in that case, we
* can't depend on extent tree, but use fs tree. If search_fs_tree is set, we
* will use fs/subvol trees to init the csum tree.
*/
static int fill_csum_tree(struct btrfs_trans_handle *trans,
struct btrfs_root *csum_root,
int search_fs_tree)
{
if (search_fs_tree)
return fill_csum_tree_from_fs(trans, csum_root);
else
return fill_csum_tree_from_extent(trans, csum_root);
}
struct root_item_info {
/* level of the root */
u8 level;
@ -9250,7 +9401,8 @@ int cmd_check(int argc, char **argv)
goto close_out;
}
ret = fill_csum_tree(trans, info->csum_root);
ret = fill_csum_tree(trans, info->csum_root,
init_extent_tree);
if (ret) {
fprintf(stderr, "crc refilling failed\n");
return -EIO;