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 <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2024-06-02 13:15:33 +09:30 committed by David Sterba
parent 6ad89f67a9
commit 6a3e646139

View file

@ -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)",