btrfs-progs: tune: delete the csum change item after converting the fs

[BUG]
Doing the following csum change in a row, it would fail:

 # mkfs.btrfs -f --csum crc32c $dev
 # btrfstune --csum sha256 $dev
 # btrfstune --csum crc32c $dev
 # btrfstune --csum sha256 $dev
 WARNING: Experimental build with unstable or unfinished features
 WARNING: Switching checksums is experimental, do not use for valuable data!

 Proceed to switch checksums
 ERROR: failed to insert csum change item: File exists
 ERROR: failed to generate new data csums: File exists
 WARNING: reserved space leaked, flag=0x4 bytes_reserved=16384
 extent buffer leak: start 30572544 len 16384
 extent buffer leak: start 30441472 len 16384
 WARNING: dirty eb leak (aborted trans): start 30441472 len 16384

[CAUSE]
During every csum change operation, btrfstune would insert an temporaray
csum change item into root tree.

But unfortunately after the conversion btrfstune doesn't properly delete
the csum change item, result the following items in the root tree:

	item 10 key (CSUM_CHANGE TEMPORARY_ITEM 0) itemoff 13423 itemsize 0
		temporary item objectid CSUM_CHANGE offset 0
		target csum type crc32c (0)
	item 11 key (CSUM_CHANGE TEMPORARY_ITEM 2) itemoff 13423 itemsize 0
		temporary item objectid CSUM_CHANGE offset 2
		target csum type sha256 (2)

Thus at the last conversion try to go back to SHA256, we failed to
insert the same item, and caused the above error.

[FIX]
After finishing the metadata csum conversion, do a proper removal of the
csum item.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2023-05-23 08:37:12 +08:00 committed by David Sterba
parent 5d2aa5fa1e
commit cd877c2d23

View File

@ -583,10 +583,13 @@ out:
btrfs_release_path(&path);
/*
* Finish the change by clearing the csum change flag and update the superblock
* csum type.
* Finish the change by clearing the csum change flag, update the superblock
* csum type, and delete the csum change item in the fs with new csum type.
*/
if (ret == 0) {
struct btrfs_root *tree_root = fs_info->tree_root;
struct btrfs_trans_handle *trans;
u64 super_flags = btrfs_super_flags(fs_info->super_copy);
btrfs_set_super_csum_type(fs_info->super_copy, new_csum_type);
@ -596,11 +599,42 @@ out:
fs_info->csum_type = new_csum_type;
fs_info->csum_size = btrfs_csum_type_size(new_csum_type);
fs_info->skip_csum_check = 0;
ret = write_all_supers(fs_info);
trans = btrfs_start_transaction(tree_root, 1);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
errno = -ret;
error("failed to start new transaction with new csum type: %m");
return ret;
}
key.objectid = BTRFS_CSUM_CHANGE_OBJECTID;
key.type = BTRFS_TEMPORARY_ITEM_KEY;
key.offset = new_csum_type;
ret = btrfs_search_slot(trans, tree_root, &key, &path, -1, 1);
if (ret > 0)
ret = -ENOENT;
if (ret < 0) {
errno = -ret;
error("failed to write super blocks: %m");
error("failed to locate the csum change item: %m");
btrfs_release_path(&path);
btrfs_abort_transaction(trans, ret);
return ret;
}
ret = btrfs_del_item(trans, tree_root, &path);
if (ret < 0) {
errno = -ret;
error("failed to delete the csum change item: %m");
btrfs_release_path(&path);
btrfs_abort_transaction(trans, ret);
return ret;
}
btrfs_release_path(&path);
ret = btrfs_commit_transaction(trans, tree_root);
if (ret < 0) {
errno = -ret;
error("failed to finalize the csum change: %m");
}
}
return ret;