mirror of
https://github.com/kdave/btrfs-progs
synced 2025-04-11 03:31:17 +00:00
btrfs-progs: check: move csum tree population into mode-common.[ch]
This part has no mode specific operations, just move them into mode-common.[ch]. Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
08823f7512
commit
f8bc08cb75
244
check/main.c
244
check/main.c
@ -9557,250 +9557,6 @@ static int zero_log_tree(struct btrfs_root *root)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int populate_csum(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *csum_root, char *buf, u64 start,
|
||||
u64 len)
|
||||
{
|
||||
u64 offset = 0;
|
||||
u64 sectorsize;
|
||||
int ret = 0;
|
||||
|
||||
while (offset < len) {
|
||||
sectorsize = gfs_info->sectorsize;
|
||||
ret = read_extent_data(gfs_info, buf, start + offset,
|
||||
§orsize, 0);
|
||||
if (ret)
|
||||
break;
|
||||
ret = btrfs_csum_file_block(trans, start + len, start + offset,
|
||||
buf, sectorsize);
|
||||
if (ret)
|
||||
break;
|
||||
offset += sectorsize;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fill_csum_tree_from_one_fs_root(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *cur_root)
|
||||
{
|
||||
struct btrfs_root *csum_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;
|
||||
|
||||
buf = malloc(gfs_info->sectorsize);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
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);
|
||||
|
||||
csum_root = btrfs_csum_root(gfs_info, start);
|
||||
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_release_path(&path);
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fill_csum_tree_from_fs(struct btrfs_trans_handle *trans)
|
||||
{
|
||||
struct btrfs_path path;
|
||||
struct btrfs_root *tree_root = gfs_info->tree_root;
|
||||
struct btrfs_root *cur_root;
|
||||
struct extent_buffer *node;
|
||||
struct btrfs_key key;
|
||||
int slot = 0;
|
||||
int ret = 0;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
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(gfs_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, 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_release_path(&path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fill_csum_tree_from_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *extent_root)
|
||||
{
|
||||
struct btrfs_root *csum_root;
|
||||
struct btrfs_path path;
|
||||
struct btrfs_extent_item *ei;
|
||||
struct extent_buffer *leaf;
|
||||
char *buf;
|
||||
struct btrfs_key key;
|
||||
int ret;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
key.objectid = 0;
|
||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
key.offset = 0;
|
||||
ret = btrfs_search_slot(NULL, extent_root, &key, &path, 0, 0);
|
||||
if (ret < 0) {
|
||||
btrfs_release_path(&path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
buf = malloc(gfs_info->sectorsize);
|
||||
if (!buf) {
|
||||
btrfs_release_path(&path);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (path.slots[0] >= btrfs_header_nritems(path.nodes[0])) {
|
||||
ret = btrfs_next_leaf(extent_root, &path);
|
||||
if (ret < 0)
|
||||
break;
|
||||
if (ret) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
leaf = path.nodes[0];
|
||||
|
||||
btrfs_item_key_to_cpu(leaf, &key, path.slots[0]);
|
||||
if (key.type != BTRFS_EXTENT_ITEM_KEY) {
|
||||
path.slots[0]++;
|
||||
continue;
|
||||
}
|
||||
|
||||
ei = btrfs_item_ptr(leaf, path.slots[0],
|
||||
struct btrfs_extent_item);
|
||||
if (!(btrfs_extent_flags(leaf, ei) &
|
||||
BTRFS_EXTENT_FLAG_DATA)) {
|
||||
path.slots[0]++;
|
||||
continue;
|
||||
}
|
||||
|
||||
csum_root = btrfs_csum_root(gfs_info, key.objectid);
|
||||
ret = populate_csum(trans, csum_root, buf, key.objectid,
|
||||
key.offset);
|
||||
if (ret)
|
||||
break;
|
||||
path.slots[0]++;
|
||||
}
|
||||
|
||||
btrfs_release_path(&path);
|
||||
free(buf);
|
||||
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,
|
||||
int search_fs_tree)
|
||||
{
|
||||
struct btrfs_root *root;
|
||||
struct rb_node *n;
|
||||
int ret;
|
||||
|
||||
if (search_fs_tree)
|
||||
return fill_csum_tree_from_fs(trans);
|
||||
|
||||
root = btrfs_extent_root(gfs_info, 0);
|
||||
while (1) {
|
||||
ret = fill_csum_tree_from_extent(trans, root);
|
||||
if (ret)
|
||||
break;
|
||||
n = rb_next(&root->rb_node);
|
||||
if (!n)
|
||||
break;
|
||||
root = rb_entry(n, struct btrfs_root, rb_node);
|
||||
if (root->root_key.objectid != BTRFS_EXTENT_TREE_OBJECTID)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void free_roots_info_cache(void)
|
||||
{
|
||||
if (!roots_info_cache)
|
||||
|
@ -1191,3 +1191,247 @@ error:
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int populate_csum(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *csum_root, char *buf, u64 start,
|
||||
u64 len)
|
||||
{
|
||||
u64 offset = 0;
|
||||
u64 sectorsize;
|
||||
int ret = 0;
|
||||
|
||||
while (offset < len) {
|
||||
sectorsize = gfs_info->sectorsize;
|
||||
ret = read_extent_data(gfs_info, buf, start + offset,
|
||||
§orsize, 0);
|
||||
if (ret)
|
||||
break;
|
||||
ret = btrfs_csum_file_block(trans, start + len, start + offset,
|
||||
buf, sectorsize);
|
||||
if (ret)
|
||||
break;
|
||||
offset += sectorsize;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fill_csum_tree_from_one_fs_root(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *cur_root)
|
||||
{
|
||||
struct btrfs_root *csum_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;
|
||||
|
||||
buf = malloc(gfs_info->sectorsize);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
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);
|
||||
|
||||
csum_root = btrfs_csum_root(gfs_info, start);
|
||||
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_release_path(&path);
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fill_csum_tree_from_fs(struct btrfs_trans_handle *trans)
|
||||
{
|
||||
struct btrfs_path path;
|
||||
struct btrfs_root *tree_root = gfs_info->tree_root;
|
||||
struct btrfs_root *cur_root;
|
||||
struct extent_buffer *node;
|
||||
struct btrfs_key key;
|
||||
int slot = 0;
|
||||
int ret = 0;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
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(gfs_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, 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_release_path(&path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fill_csum_tree_from_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *extent_root)
|
||||
{
|
||||
struct btrfs_root *csum_root;
|
||||
struct btrfs_path path;
|
||||
struct btrfs_extent_item *ei;
|
||||
struct extent_buffer *leaf;
|
||||
char *buf;
|
||||
struct btrfs_key key;
|
||||
int ret;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
key.objectid = 0;
|
||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
key.offset = 0;
|
||||
ret = btrfs_search_slot(NULL, extent_root, &key, &path, 0, 0);
|
||||
if (ret < 0) {
|
||||
btrfs_release_path(&path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
buf = malloc(gfs_info->sectorsize);
|
||||
if (!buf) {
|
||||
btrfs_release_path(&path);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (path.slots[0] >= btrfs_header_nritems(path.nodes[0])) {
|
||||
ret = btrfs_next_leaf(extent_root, &path);
|
||||
if (ret < 0)
|
||||
break;
|
||||
if (ret) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
leaf = path.nodes[0];
|
||||
|
||||
btrfs_item_key_to_cpu(leaf, &key, path.slots[0]);
|
||||
if (key.type != BTRFS_EXTENT_ITEM_KEY) {
|
||||
path.slots[0]++;
|
||||
continue;
|
||||
}
|
||||
|
||||
ei = btrfs_item_ptr(leaf, path.slots[0],
|
||||
struct btrfs_extent_item);
|
||||
if (!(btrfs_extent_flags(leaf, ei) &
|
||||
BTRFS_EXTENT_FLAG_DATA)) {
|
||||
path.slots[0]++;
|
||||
continue;
|
||||
}
|
||||
|
||||
csum_root = btrfs_csum_root(gfs_info, key.objectid);
|
||||
ret = populate_csum(trans, csum_root, buf, key.objectid,
|
||||
key.offset);
|
||||
if (ret)
|
||||
break;
|
||||
path.slots[0]++;
|
||||
}
|
||||
|
||||
btrfs_release_path(&path);
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Recalculate the csum and put it into the csum tree.
|
||||
*
|
||||
* @search_fs_tree: How to get the data extent item.
|
||||
* If true, iterate all fs roots to get all
|
||||
* extent data (which can be slow).
|
||||
* Otherwise, search extent tree for extent data.
|
||||
*/
|
||||
int fill_csum_tree(struct btrfs_trans_handle *trans, bool search_fs_tree)
|
||||
{
|
||||
struct btrfs_root *root;
|
||||
struct rb_node *n;
|
||||
int ret;
|
||||
|
||||
if (search_fs_tree)
|
||||
return fill_csum_tree_from_fs(trans);
|
||||
|
||||
root = btrfs_extent_root(gfs_info, 0);
|
||||
while (1) {
|
||||
ret = fill_csum_tree_from_extent(trans, root);
|
||||
if (ret)
|
||||
break;
|
||||
n = rb_next(&root->rb_node);
|
||||
if (!n)
|
||||
break;
|
||||
root = rb_entry(n, struct btrfs_root, rb_node);
|
||||
if (root->root_key.objectid != BTRFS_EXTENT_TREE_OBJECTID)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -199,4 +199,6 @@ static inline void btrfs_check_subpage_eb_alignment(struct btrfs_fs_info *info,
|
||||
int repair_dev_item_bytes_used(struct btrfs_fs_info *fs_info,
|
||||
u64 devid, u64 bytes_used_expected);
|
||||
|
||||
int fill_csum_tree(struct btrfs_trans_handle *trans, bool search_fs_tree);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user