@@ -9182,6 +9182,11 @@ again:
if (init_csum_tree) {
fprintf(stderr, "Reinit crc root\n");
+ ret = remove_csum_extents(trans, info->extent_root);
+ if (ret < 0) {
+ fprintf(stderr, "crc extents removing failed\n");
+ goto close_out;
+ }
ret = btrfs_fsck_reinit_root(trans, info->csum_root, 0);
if (ret) {
fprintf(stderr, "crc root initialization failed\n");
@@ -2249,6 +2249,8 @@ int btrfs_record_file_extent(struct btrfs_trans_handle *trans,
struct btrfs_inode_item *inode,
u64 file_pos, u64 disk_bytenr,
u64 num_bytes);
+int remove_csum_extents(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root);
/* ctree.c */
int btrfs_comp_cpu_keys(struct btrfs_key *k1, struct btrfs_key *k2);
int btrfs_del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
@@ -3555,3 +3555,111 @@ fail:
btrfs_release_path(&path);
return ret;
}
+
+/*
+ * Remove all the extents belong to csum tree and update blockgroup info
+ *
+ * Only used in csum tree rebuilding. Since the whole csum tree root
+ * will be a new one, no backref needs to be updated
+ */
+int remove_csum_extents(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root)
+{
+ struct btrfs_key key;
+ struct btrfs_path *path;
+ struct btrfs_extent_item *ei;
+ int skinny_metadata = btrfs_fs_incompat(root->fs_info,
+ BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA);
+ int ret = 0;
+
+ /* Extent tree root not exists, no need to remove csum extents */
+ if (!root)
+ return 0;
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+
+ key.objectid = 0;
+ key.type = 0;
+ key.offset = 0;
+
+ ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
+ if (ret < 0)
+ goto out;
+ while (1) {
+ struct extent_buffer *node;
+ int slot;
+
+ slot = path->slots[0];
+ node = path->nodes[0];
+
+ btrfs_item_key_to_cpu(node, &key, slot);
+ if (key.type != BTRFS_METADATA_ITEM_KEY &&
+ key.type != BTRFS_EXTENT_ITEM_KEY)
+ goto next;
+ ei = btrfs_item_ptr(node, slot,
+ struct btrfs_extent_item);
+ /*
+ * refs to csum tree extent must be 1
+ * if not 1, it must be a fs tree extent.
+ */
+ if (btrfs_extent_refs(node, ei) != 1)
+ goto next;
+
+ if (skinny_metadata) {
+ struct btrfs_extent_inline_ref *iref;
+
+ if (key.type != BTRFS_METADATA_ITEM_KEY)
+ goto next;
+
+ iref = (struct btrfs_extent_inline_ref *)(ei + 1);
+
+ if (btrfs_extent_inline_ref_offset(node, iref) !=
+ BTRFS_CSUM_TREE_OBJECTID)
+ goto next;
+ } else {
+ struct btrfs_tree_block_info *tref;
+ struct btrfs_disk_key disk_key;
+ struct btrfs_key tree_key;
+
+ if (!(btrfs_extent_flags(node, ei) &
+ BTRFS_EXTENT_FLAG_TREE_BLOCK))
+ goto next;
+ tref = (struct btrfs_tree_block_info *)(ei + 1);
+ btrfs_tree_block_key(node, tref, &disk_key);
+ btrfs_disk_key_to_cpu(&tree_key, &disk_key);
+ if (tree_key.type != BTRFS_EXTENT_CSUM_KEY)
+ goto next;
+ }
+ /* Now we are sure it's a extent of csum tree */
+ ret = btrfs_del_item(trans, root, path);
+ if (ret < 0)
+ goto out;
+
+ ret = update_block_group(trans, root, key.objectid,
+ root->leafsize, 0, 1);
+ if (ret < 0)
+ goto out;
+
+ /* We are at the next block, check slot and continue */
+ if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
+ ret = btrfs_next_leaf(root, path);
+ if (ret > 0) {
+ ret = 0;
+ goto out;
+ }
+ }
+ continue;
+next:
+ ret = btrfs_next_item(root, path);
+ if (ret < 0)
+ goto out;
+ if (ret > 0) {
+ ret = 0;
+ goto out;
+ }
+ }
+out:
+ btrfs_free_path(path);
+ return ret;
+}
The original csum tree init codes will only rebuild the csum tree, but don't remove the tree block extents in extent tree, and let extent tree repair to repair all the mismatch extents. This is OK if calling --init-csum manually, but it's confusing if csum tree build it executed automatically, and csum tree corruption will be reported twice. This patch removes the csum extents in csum tree rebuild routine, which will make the check result clean after automatically csum tree rebuild. Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> --- cmds-check.c | 5 +++ ctree.h | 2 ++ extent-tree.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+)