From 6a3e64613962a04cdc54dd2b6546c5d51d5a49c9 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Sun, 2 Jun 2024 13:15:33 +0930 Subject: [PATCH] btrfs-progs: change-csum: handle finished dev-replace correctly [BUG] If a btrfs filesystem had dev-replace ran in the past, even it's already finished, btrfstune would refuse to change its csum: WARNING: Experimental build with unstable or unfinished features WARNING: Switching checksums is experimental, do not use for valuable data! Proceed to switch checksums ERROR: running dev-replace detected, please finish or cancel it. ERROR: btrfstune failed [CAUSE] The current dev-replace detection is only checking if we have DEV_REPLACE item in device tree. However DEV_REPLACE item will also exist even if a dev-replace finished, so the existing check can not handle such case at all. [FIX] If an dev-replace item is found, further check the state of the item to prevent false alerts. Issue: #798 Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- tune/change-csum.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tune/change-csum.c b/tune/change-csum.c index 7802509f..f5fc3c7f 100644 --- a/tune/change-csum.c +++ b/tune/change-csum.c @@ -73,16 +73,27 @@ static int check_csum_change_requreiment(struct btrfs_fs_info *fs_info, u16 new_ key.type = BTRFS_DEV_REPLACE_KEY; key.offset = 0; ret = btrfs_search_slot(NULL, dev_root, &key, &path, 0, 0); - btrfs_release_path(&path); if (ret < 0) { + btrfs_release_path(&path); errno = -ret; error("failed to check the dev-replace status: %m"); return ret; } if (ret == 0) { - error("running dev-replace detected, please finish or cancel it."); - return -EINVAL; + struct btrfs_dev_replace_item *ptr; + u64 state; + + ptr = btrfs_item_ptr(path.nodes[0], path.slots[0], struct btrfs_dev_replace_item); + state = btrfs_dev_replace_replace_state(path.nodes[0], ptr); + if (state == BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED || + state == BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED) { + btrfs_release_path(&path); + error( + "running/suspended dev-replace detected, please finish or cancel it"); + return -EINVAL; + } } + btrfs_release_path(&path); if (fs_info->csum_type == new_csum_type) { error("the fs is already using csum type %s (%u)",