aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnand Jain <anand.jain@oracle.com>2018-10-14 22:45:17 -0400
committerDavid Sterba <dsterba@suse.com>2018-12-17 08:51:34 -0500
commita9261d4125c97ce8624e9941b75dee1b43ad5df9 (patch)
tree623742668ed75e56e5aafa15e89e16d54f76c033
parentb50836edf9fe531c66310071df59eac2d8dfc708 (diff)
btrfs: harden agaist duplicate fsid on scanned devices
It's not that impossible to imagine that a device OR a btrfs image is copied just by using the dd or the cp command. Which in case both the copies of the btrfs will have the same fsid. If on the system with automount enabled, the copied FS gets scanned. We have a known bug in btrfs, that we let the device path be changed after the device has been mounted. So using this loop hole the new copied device would appears as if its mounted immediately after it's been copied. For example: Initially.. /dev/mmcblk0p4 is mounted as / $ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT mmcblk0 179:0 0 29.2G 0 disk |-mmcblk0p4 179:4 0 4G 0 part / |-mmcblk0p2 179:2 0 500M 0 part /boot |-mmcblk0p3 179:3 0 256M 0 part [SWAP] `-mmcblk0p1 179:1 0 256M 0 part /boot/efi $ btrfs fi show Label: none uuid: 07892354-ddaa-4443-90ea-f76a06accaba Total devices 1 FS bytes used 1.40GiB devid 1 size 4.00GiB used 3.00GiB path /dev/mmcblk0p4 Copy mmcblk0 to sda $ dd if=/dev/mmcblk0 of=/dev/sda And immediately after the copy completes the change in the device superblock is notified which the automount scans using btrfs device scan and the new device sda becomes the mounted root device. $ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 1 14.9G 0 disk |-sda4 8:4 1 4G 0 part / |-sda2 8:2 1 500M 0 part |-sda3 8:3 1 256M 0 part `-sda1 8:1 1 256M 0 part mmcblk0 179:0 0 29.2G 0 disk |-mmcblk0p4 179:4 0 4G 0 part |-mmcblk0p2 179:2 0 500M 0 part /boot |-mmcblk0p3 179:3 0 256M 0 part [SWAP] `-mmcblk0p1 179:1 0 256M 0 part /boot/efi $ btrfs fi show / Label: none uuid: 07892354-ddaa-4443-90ea-f76a06accaba Total devices 1 FS bytes used 1.40GiB devid 1 size 4.00GiB used 3.00GiB path /dev/sda4 The bug is quite nasty that you can't either unmount /dev/sda4 or /dev/mmcblk0p4. And the problem does not get solved until you take sda out of the system on to another system to change its fsid using the 'btrfstune -u' command. Signed-off-by: Anand Jain <anand.jain@oracle.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/volumes.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 29fc8a09dd2e..fc9a3d8f6238 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -857,6 +857,35 @@ static noinline struct btrfs_device *device_list_add(const char *path,
857 return ERR_PTR(-EEXIST); 857 return ERR_PTR(-EEXIST);
858 } 858 }
859 859
860 /*
861 * We are going to replace the device path for a given devid,
862 * make sure it's the same device if the device is mounted
863 */
864 if (device->bdev) {
865 struct block_device *path_bdev;
866
867 path_bdev = lookup_bdev(path);
868 if (IS_ERR(path_bdev)) {
869 mutex_unlock(&fs_devices->device_list_mutex);
870 return ERR_CAST(path_bdev);
871 }
872
873 if (device->bdev != path_bdev) {
874 bdput(path_bdev);
875 mutex_unlock(&fs_devices->device_list_mutex);
876 btrfs_warn_in_rcu(device->fs_info,
877 "duplicate device fsid:devid for %pU:%llu old:%s new:%s",
878 disk_super->fsid, devid,
879 rcu_str_deref(device->name), path);
880 return ERR_PTR(-EEXIST);
881 }
882 bdput(path_bdev);
883 btrfs_info_in_rcu(device->fs_info,
884 "device fsid %pU devid %llu moved old:%s new:%s",
885 disk_super->fsid, devid,
886 rcu_str_deref(device->name), path);
887 }
888
860 name = rcu_string_strdup(path, GFP_NOFS); 889 name = rcu_string_strdup(path, GFP_NOFS);
861 if (!name) { 890 if (!name) {
862 mutex_unlock(&fs_devices->device_list_mutex); 891 mutex_unlock(&fs_devices->device_list_mutex);