mirror of
https://github.com/kdave/btrfs-progs
synced 2025-04-18 21:15:33 +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;
|
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)
|
static void free_roots_info_cache(void)
|
||||||
{
|
{
|
||||||
if (!roots_info_cache)
|
if (!roots_info_cache)
|
||||||
|
@ -1191,3 +1191,247 @@ error:
|
|||||||
btrfs_abort_transaction(trans, ret);
|
btrfs_abort_transaction(trans, ret);
|
||||||
return 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,
|
int repair_dev_item_bytes_used(struct btrfs_fs_info *fs_info,
|
||||||
u64 devid, u64 bytes_used_expected);
|
u64 devid, u64 bytes_used_expected);
|
||||||
|
|
||||||
|
int fill_csum_tree(struct btrfs_trans_handle *trans, bool search_fs_tree);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user