* [PATCH 2/5] btrfs-progs: check: move csum tree population into mode-common.[ch]
2021-12-24 5:50 [PATCH 0/5] btrfs-progs: check: properly skip preallocated/nodatasum extents when re-calculating csum tree Qu Wenruo
2021-12-24 5:50 ` [PATCH 1/5] btrfs-progs: backref: properly queue indirect refs Qu Wenruo
@ 2021-12-24 5:50 ` Qu Wenruo
2021-12-24 5:50 ` [PATCH 3/5] btrfs-progs: check: don't calculate csum for preallocated file extents Qu Wenruo
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Qu Wenruo @ 2021-12-24 5:50 UTC (permalink / raw)
To: linux-btrfs
This part has no mode specific operations, just move them into
mode-common.[ch].
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
check/main.c | 244 --------------------------------------------
check/mode-common.c | 244 ++++++++++++++++++++++++++++++++++++++++++++
check/mode-common.h | 1 +
3 files changed, 245 insertions(+), 244 deletions(-)
diff --git a/check/main.c b/check/main.c
index 540130b8e223..ea2f2d7b16b8 100644
--- a/check/main.c
+++ b/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)
diff --git a/check/mode-common.c b/check/mode-common.c
index 62a9837bde5e..299d66d644e7 100644
--- a/check/mode-common.c
+++ b/check/mode-common.c
@@ -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;
+}
diff --git a/check/mode-common.h b/check/mode-common.h
index 8cd135b9bfc2..b894c2be4f97 100644
--- a/check/mode-common.h
+++ b/check/mode-common.h
@@ -199,4 +199,5 @@ 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
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/5] btrfs-progs: check: don't calculate csum for preallocated file extents
2021-12-24 5:50 [PATCH 0/5] btrfs-progs: check: properly skip preallocated/nodatasum extents when re-calculating csum tree Qu Wenruo
2021-12-24 5:50 ` [PATCH 1/5] btrfs-progs: backref: properly queue indirect refs Qu Wenruo
2021-12-24 5:50 ` [PATCH 2/5] btrfs-progs: check: move csum tree population into mode-common.[ch] Qu Wenruo
@ 2021-12-24 5:50 ` Qu Wenruo
2021-12-24 5:50 ` [PATCH 4/5] btrfs-progs: check: skip NODATASUM inodes for `--init-csum-tree --init-extent-tree` Qu Wenruo
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Qu Wenruo @ 2021-12-24 5:50 UTC (permalink / raw)
To: linux-btrfs
[BUG]
If a btrfs filesystem has preallocated file extents, `btrfs check
--init-csum-tree` will create csum item for preallocated extents, and
cause error:
# mkfs.btrfs -f test.img
# mount test.img /mnt/btrfs
# fallocate -l 32K /mnt/btrfs/file
# umount /mnt/btrfs
# btrfs check --init-csum-tree --force test.img
...
[4/7] checking fs roots
root 5 inode 257 errors 800, odd csum item
ERROR: errors found in fs roots
found 376832 bytes used, error(s) found
And the csum tree is not empty, containing csum for the preallocated
extent:
$ btrfs ins dump-tree -t csum test.img
btrfs-progs v5.15.1
checksum tree key (CSUM_TREE ROOT_ITEM 0)
leaf 30408704 items 1 free space 16226 generation 9 owner CSUM_TREE
leaf 30408704 flags 0x1(WRITTEN) backref revision 1
fs uuid ecc79835-5611-4609-b985-e4ccd6f15b54
chunk uuid b1c75553-5b82-4aa6-bbbe-e7f50643b1a8
item 0 key (EXTENT_CSUM EXTENT_CSUM 13631488) itemoff 16251 itemsize 32
range start 13631488 end 13664256 length 32768
[CAUSE]
For `--init-csum-tree` alone, we will use extent tree to iterate each
data extent, and calcluate csum for them.
But extent items alone can not tell us if the file extent belongs to a
NODATASUM inode, nor if it's preallocated.
Thus we create csums for those data extents, and cause the problem.
[FIX]
Fix it by iterate all inode items and file extent items to skip the
following cases:
- Inodes with NODATASUM flags
- Preallocated/hole file extents
Issue: #430
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
check/mode-common.c | 103 ++++++++++++++++++++++++++++++++++++++------
1 file changed, 90 insertions(+), 13 deletions(-)
diff --git a/check/mode-common.c b/check/mode-common.c
index 299d66d644e7..dd0b1d695bfa 100644
--- a/check/mode-common.c
+++ b/check/mode-common.c
@@ -22,6 +22,7 @@
#include "common/utils.h"
#include "kernel-shared/disk-io.h"
#include "kernel-shared/volumes.h"
+#include "kernel-shared/backref.h"
#include "common/repair.h"
#include "check/mode-common.h"
@@ -1338,14 +1339,99 @@ out:
return ret;
}
+static int fill_csum_for_file_extent(u64 ino, u64 offset, u64 rootid, void *ctx)
+{
+ struct btrfs_trans_handle *trans = (struct btrfs_trans_handle *)ctx;
+ struct btrfs_fs_info *fs_info = trans->fs_info;
+ struct btrfs_file_extent_item *fi;
+ struct btrfs_inode_item *ii;
+ struct btrfs_path path = {};
+ struct btrfs_key key;
+ struct btrfs_root *root;
+ struct btrfs_root *csum_root;
+ char *buf;
+ u64 disk_bytenr;
+ u64 disk_len;
+ int ret = 0;
+
+ key.objectid = rootid;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = (u64)-1;
+ root = btrfs_read_fs_root(fs_info, &key);
+ if (IS_ERR(root)) {
+ ret = PTR_ERR(root);
+ goto out;
+ }
+
+ /* Check if the inode has NODATASUM flag */
+ key.objectid = ino;
+ key.type = BTRFS_INODE_ITEM_KEY;
+ key.offset = 0;
+ ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
+ if (ret > 0)
+ ret = -ENOENT;
+ if (ret < 0)
+ goto out;
+
+ ii = btrfs_item_ptr(path.nodes[0], path.slots[0],
+ struct btrfs_inode_item);
+ if (btrfs_inode_flags(path.nodes[0], ii) & BTRFS_INODE_NODATASUM) {
+ /* The inode has NODATASUM flag, not need to calculate csum */
+ ret = 0;
+ goto out;
+ }
+
+ btrfs_release_path(&path);
+
+ /* Check the file extent item to make sure it's not preallocated */
+ key.objectid = ino;
+ key.type = BTRFS_EXTENT_DATA_KEY;
+ key.offset = offset;
+ ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
+ if (ret > 0)
+ ret = -ENOENT;
+ if (ret < 0)
+ goto out;
+ fi = btrfs_item_ptr(path.nodes[0], path.slots[0],
+ struct btrfs_file_extent_item);
+ if (btrfs_file_extent_type(path.nodes[0], fi) != BTRFS_FILE_EXTENT_REG)
+ goto out;
+ disk_bytenr = btrfs_file_extent_disk_bytenr(path.nodes[0], fi);
+ disk_len = btrfs_file_extent_disk_num_bytes(path.nodes[0], fi);
+ if (!disk_bytenr)
+ goto out;
+
+ /*
+ * Now it's non-hole regular file extents, get its real on-disk bytenr
+ * for csum population.
+ */
+ if (btrfs_file_extent_compression(path.nodes[0], fi) ==
+ BTRFS_COMPRESS_NONE) {
+ disk_bytenr += btrfs_file_extent_offset(path.nodes[0], fi);
+ disk_len = btrfs_file_extent_num_bytes(path.nodes[0], fi);
+ }
+ btrfs_release_path(&path);
+
+ csum_root = btrfs_csum_root(fs_info, disk_bytenr);
+ buf = malloc(fs_info->sectorsize);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ /* Insert the csum */
+ ret = populate_csum(trans, csum_root, buf, disk_bytenr, disk_len);
+ free(buf);
+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;
@@ -1359,12 +1445,6 @@ static int fill_csum_tree_from_extent(struct btrfs_trans_handle *trans,
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);
@@ -1390,17 +1470,14 @@ static int fill_csum_tree_from_extent(struct btrfs_trans_handle *trans,
path.slots[0]++;
continue;
}
-
- csum_root = btrfs_csum_root(gfs_info, key.objectid);
- ret = populate_csum(trans, csum_root, buf, key.objectid,
- key.offset);
+ ret = iterate_extent_inodes(trans->fs_info, key.objectid, 0, 0,
+ fill_csum_for_file_extent, trans);
if (ret)
break;
path.slots[0]++;
}
btrfs_release_path(&path);
- free(buf);
return ret;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 4/5] btrfs-progs: check: skip NODATASUM inodes for `--init-csum-tree --init-extent-tree`
2021-12-24 5:50 [PATCH 0/5] btrfs-progs: check: properly skip preallocated/nodatasum extents when re-calculating csum tree Qu Wenruo
` (2 preceding siblings ...)
2021-12-24 5:50 ` [PATCH 3/5] btrfs-progs: check: don't calculate csum for preallocated file extents Qu Wenruo
@ 2021-12-24 5:50 ` Qu Wenruo
2021-12-24 5:50 ` [PATCH 5/5] btrfs-progs: fsck-tests: add test case for init-csum-tree Qu Wenruo
2022-01-03 16:22 ` [PATCH 0/5] btrfs-progs: check: properly skip preallocated/nodatasum extents when re-calculating csum tree Josef Bacik
5 siblings, 0 replies; 7+ messages in thread
From: Qu Wenruo @ 2021-12-24 5:50 UTC (permalink / raw)
To: linux-btrfs
When using `--init-csum-tree` with `--init-extent-tree`, csum tree
population will be done by iterating all file extent items.
This allow us to skip preallocated extents, but it still has the
folllwing problems:
- Inodes with NODATASUM
- Hole file extents
- Written preallocated extents
We will generate csum for the whole extent, while other part may still
be unwritten.
Make it to follow the same behavior of recently introduced
fill_csum_for_file_extent(), so we can generate correct csum.
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
check/mode-common.c | 43 ++++++++++++++++++++++++++++++++++++++++---
1 file changed, 40 insertions(+), 3 deletions(-)
diff --git a/check/mode-common.c b/check/mode-common.c
index dd0b1d695bfa..1c1374bae70b 100644
--- a/check/mode-common.c
+++ b/check/mode-common.c
@@ -1225,6 +1225,7 @@ static int fill_csum_tree_from_one_fs_root(struct btrfs_trans_handle *trans,
struct extent_buffer *node;
struct btrfs_file_extent_item *fi;
char *buf = NULL;
+ u64 skip_ino = 0;
u64 start = 0;
u64 len = 0;
int slot = 0;
@@ -1245,15 +1246,51 @@ static int fill_csum_tree_from_one_fs_root(struct btrfs_trans_handle *trans,
while (1) {
btrfs_item_key_to_cpu(path.nodes[0], &key, path.slots[0]);
- if (key.type != BTRFS_EXTENT_DATA_KEY)
+ if (key.type != BTRFS_EXTENT_DATA_KEY &&
+ key.type != BTRFS_INODE_ITEM_KEY)
+ goto next;
+
+ /* This item belongs to an inode with NODATASUM, skip it */
+ if (key.objectid == skip_ino)
+ goto next;
+
+ if (key.type == BTRFS_INODE_ITEM_KEY) {
+ struct btrfs_inode_item *ii;
+
+ ii = btrfs_item_ptr(path.nodes[0], path.slots[0],
+ struct btrfs_inode_item);
+ /* Check if the inode has NODATASUM flag */
+ if (btrfs_inode_flags(path.nodes[0], ii) &
+ BTRFS_INODE_NODATASUM)
+ skip_ino = key.objectid;
goto next;
+ }
node = path.nodes[0];
slot = path.slots[0];
fi = btrfs_item_ptr(node, slot, struct btrfs_file_extent_item);
+
+ /* Skip preallocated/inline extents */
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);
+
+ /* Skip hole extents */
+ if (btrfs_file_extent_disk_bytenr(node, fi) == 0)
+ goto next;
+
+ if (btrfs_file_extent_compression(node, fi) ==
+ BTRFS_COMPRESS_NONE) {
+ /*
+ * Non-compressed extent, only calculate csum for the
+ * referred part, as the original larger extent can
+ * be preallocated.
+ */
+ start = btrfs_file_extent_disk_bytenr(node, fi) +
+ btrfs_file_extent_offset(node, fi);
+ len = btrfs_file_extent_num_bytes(node, fi);
+ } else {
+ 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);
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread