From: Anand Jain <anand.j...@oracle.com>

[ Upstream commit c6a5d954950c5031444173ad2195efc163afcac9 ]

If you replace a seed device in a sprouted fs, it appears to have
successfully replaced the seed device, but if you look closely, it
didn't.  Here is an example.

  $ mkfs.btrfs /dev/sda
  $ btrfstune -S1 /dev/sda
  $ mount /dev/sda /btrfs
  $ btrfs device add /dev/sdb /btrfs
  $ umount /btrfs
  $ btrfs device scan --forget
  $ mount -o device=/dev/sda /dev/sdb /btrfs
  $ btrfs replace start -f /dev/sda /dev/sdc /btrfs
  $ echo $?
  0

  BTRFS info (device sdb): dev_replace from /dev/sda (devid 1) to /dev/sdc 
started
  BTRFS info (device sdb): dev_replace from /dev/sda (devid 1) to /dev/sdc 
finished

  $ btrfs fi show
  Label: none  uuid: ab2c88b7-be81-4a7e-9849-c3666e7f9f4f
          Total devices 2 FS bytes used 256.00KiB
          devid    1 size 3.00GiB used 520.00MiB path /dev/sdc
          devid    2 size 3.00GiB used 896.00MiB path /dev/sdb

  Label: none  uuid: 10bd3202-0415-43af-96a8-d5409f310a7e
          Total devices 1 FS bytes used 128.00KiB
          devid    1 size 3.00GiB used 536.00MiB path /dev/sda

So as per the replace start command and kernel log replace was successful.
Now let's try to clean mount.

  $ umount /btrfs
  $ btrfs device scan --forget

  $ mount -o device=/dev/sdc /dev/sdb /btrfs
  mount: /btrfs: wrong fs type, bad option, bad superblock on /dev/sdb, missing 
codepage or helper program, or other error.

  [  636.157517] BTRFS error (device sdc): failed to read chunk tree: -2
  [  636.180177] BTRFS error (device sdc): open_ctree failed

That's because per dev items it is still looking for the original seed
device.

 $ btrfs inspect-internal dump-tree -d /dev/sdb

        item 0 key (DEV_ITEMS DEV_ITEM 1) itemoff 16185 itemsize 98
                devid 1 total_bytes 3221225472 bytes_used 545259520
                io_align 4096 io_width 4096 sector_size 4096 type 0
                generation 6 start_offset 0 dev_group 0
                seek_speed 0 bandwidth 0
                uuid 59368f50-9af2-4b17-91da-8a783cc418d4  <--- seed uuid
                fsid 10bd3202-0415-43af-96a8-d5409f310a7e  <--- seed fsid
        item 1 key (DEV_ITEMS DEV_ITEM 2) itemoff 16087 itemsize 98
                devid 2 total_bytes 3221225472 bytes_used 939524096
                io_align 4096 io_width 4096 sector_size 4096 type 0
                generation 0 start_offset 0 dev_group 0
                seek_speed 0 bandwidth 0
                uuid 56a0a6bc-4630-4998-8daf-3c3030c4256a  <- sprout uuid
                fsid ab2c88b7-be81-4a7e-9849-c3666e7f9f4f <- sprout fsid

But the replaced target has the following uuid+fsid in its superblock
which doesn't match with the expected uuid+fsid in its devitem.

  $ btrfs in dump-super /dev/sdc | egrep 
'^generation|dev_item.uuid|dev_item.fsid|devid'
  generation    20
  dev_item.uuid 59368f50-9af2-4b17-91da-8a783cc418d4
  dev_item.fsid ab2c88b7-be81-4a7e-9849-c3666e7f9f4f [match]
  dev_item.devid        1

So if you provide the original seed device the mount shall be
successful.  Which so long happening in the test case btrfs/163.

  $ btrfs device scan --forget
  $ mount -o device=/dev/sda /dev/sdb /btrfs

Fix in this patch:
If a seed is not sprouted then there is no replacement of it, because of
its read-only filesystem with a read-only device. Similarly, in the case
of a sprouted filesystem, the seed device is still read only. So, mark
it as you can't replace a seed device, you can only add a new device and
then delete the seed device. If replace is attempted then returns
-EINVAL.

Signed-off-by: Anand Jain <anand.j...@oracle.com>
Signed-off-by: David Sterba <dste...@suse.com>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 fs/btrfs/dev-replace.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index e4a1c6afe35dc..0cb36746060da 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -230,7 +230,7 @@ static int btrfs_init_dev_replace_tgtdev(struct 
btrfs_fs_info *fs_info,
        int ret = 0;
 
        *device_out = NULL;
-       if (fs_info->fs_devices->seeding) {
+       if (srcdev->fs_devices->seeding) {
                btrfs_err(fs_info, "the filesystem is a seed filesystem!");
                return -EINVAL;
        }
-- 
2.27.0



Reply via email to