btrfs: support cloned-device mount capability
Guilherme's previous work [1] aimed at the mounting of cloned devices using a superblock flag SINGLE_DEV during mkfs. [1] https://lore.kernel.org/linux-btrfs/20230831001544.3379273-1-gpiccoli@igalia.com/ Building upon this work, here is in memory only approach. As it mounts we determine if the same fsid is already mounted if then we generate a random temp fsid which shall be used the mount, in memory only not written to the disk. We distinguish devices by devt. Example: $ fallocate -l 300m ./disk1.img $ mkfs.btrfs -f ./disk1.img $ cp ./disk1.img ./disk2.img $ cp ./disk1.img ./disk3.img $ mount -o loop ./disk1.img /btrfs $ mount -o ./disk2.img /btrfs1 $ mount -o ./disk3.img /btrfs2 $ btrfs fi show -m Label: none uuid: 4a212b48-1bec-46a5-938a-783c8c1f0b02 Total devices 1 FS bytes used 144.00KiB devid 1 size 300.00MiB used 88.00MiB path /dev/loop0 Label: none uuid: adabf2fe-5515-4ad0-95b4-7b1609218c16 Total devices 1 FS bytes used 144.00KiB devid 1 size 300.00MiB used 88.00MiB path /dev/loop1 Label: none uuid: 1d77d0df-7d92-439e-adbd-20b9b86fdedb Total devices 1 FS bytes used 144.00KiB devid 1 size 300.00MiB used 88.00MiB path /dev/loop2 Co-developed-by: Guilherme G. Piccoli <gpiccoli@igalia.com> Signed-off-by: Anand Jain <anand.jain@oracle.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
69d427f34c
commit
a5b8a5f9f8
3 changed files with 61 additions and 4 deletions
|
@ -2399,7 +2399,8 @@ int btrfs_validate_super(struct btrfs_fs_info *fs_info,
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(fs_info->fs_devices->fsid, sb->fsid, BTRFS_FSID_SIZE) != 0) {
|
if (!fs_info->fs_devices->temp_fsid &&
|
||||||
|
memcmp(fs_info->fs_devices->fsid, sb->fsid, BTRFS_FSID_SIZE) != 0) {
|
||||||
btrfs_err(fs_info,
|
btrfs_err(fs_info,
|
||||||
"superblock fsid doesn't match fsid of fs_devices: %pU != %pU",
|
"superblock fsid doesn't match fsid of fs_devices: %pU != %pU",
|
||||||
sb->fsid, fs_info->fs_devices->fsid);
|
sb->fsid, fs_info->fs_devices->fsid);
|
||||||
|
|
|
@ -554,17 +554,63 @@ static int btrfs_free_stale_devices(dev_t devt, struct btrfs_device *skip_device
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct btrfs_fs_devices *find_fsid_by_device(
|
static struct btrfs_fs_devices *find_fsid_by_device(
|
||||||
struct btrfs_super_block *disk_super)
|
struct btrfs_super_block *disk_super,
|
||||||
|
dev_t devt, bool *same_fsid_diff_dev)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_devices *fsid_fs_devices;
|
struct btrfs_fs_devices *fsid_fs_devices;
|
||||||
|
struct btrfs_fs_devices *devt_fs_devices;
|
||||||
const bool has_metadata_uuid = (btrfs_super_incompat_flags(disk_super) &
|
const bool has_metadata_uuid = (btrfs_super_incompat_flags(disk_super) &
|
||||||
BTRFS_FEATURE_INCOMPAT_METADATA_UUID);
|
BTRFS_FEATURE_INCOMPAT_METADATA_UUID);
|
||||||
|
bool found_by_devt = false;
|
||||||
|
|
||||||
/* Find the fs_device by the usual method, if found use it. */
|
/* Find the fs_device by the usual method, if found use it. */
|
||||||
fsid_fs_devices = find_fsid(disk_super->fsid,
|
fsid_fs_devices = find_fsid(disk_super->fsid,
|
||||||
has_metadata_uuid ? disk_super->metadata_uuid : NULL);
|
has_metadata_uuid ? disk_super->metadata_uuid : NULL);
|
||||||
|
|
||||||
return fsid_fs_devices;
|
/* The temp_fsid feature is supported only with single device filesystem. */
|
||||||
|
if (btrfs_super_num_devices(disk_super) != 1)
|
||||||
|
return fsid_fs_devices;
|
||||||
|
|
||||||
|
/* Try to find a fs_devices by matching devt. */
|
||||||
|
list_for_each_entry(devt_fs_devices, &fs_uuids, fs_list) {
|
||||||
|
struct btrfs_device *device;
|
||||||
|
|
||||||
|
list_for_each_entry(device, &devt_fs_devices->devices, dev_list) {
|
||||||
|
if (device->devt == devt) {
|
||||||
|
found_by_devt = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found_by_devt)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found_by_devt) {
|
||||||
|
/* Existing device. */
|
||||||
|
if (fsid_fs_devices == NULL) {
|
||||||
|
if (devt_fs_devices->opened == 0) {
|
||||||
|
/* Stale device. */
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
/* temp_fsid is mounting a subvol. */
|
||||||
|
return devt_fs_devices;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Regular or temp_fsid device mounting a subvol. */
|
||||||
|
return devt_fs_devices;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* New device. */
|
||||||
|
if (fsid_fs_devices == NULL) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
/* sb::fsid is already used create a new temp_fsid. */
|
||||||
|
*same_fsid_diff_dev = true;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not reached. */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -670,6 +716,7 @@ static noinline struct btrfs_device *device_list_add(const char *path,
|
||||||
u64 devid = btrfs_stack_device_id(&disk_super->dev_item);
|
u64 devid = btrfs_stack_device_id(&disk_super->dev_item);
|
||||||
dev_t path_devt;
|
dev_t path_devt;
|
||||||
int error;
|
int error;
|
||||||
|
bool same_fsid_diff_dev = false;
|
||||||
bool has_metadata_uuid = (btrfs_super_incompat_flags(disk_super) &
|
bool has_metadata_uuid = (btrfs_super_incompat_flags(disk_super) &
|
||||||
BTRFS_FEATURE_INCOMPAT_METADATA_UUID);
|
BTRFS_FEATURE_INCOMPAT_METADATA_UUID);
|
||||||
|
|
||||||
|
@ -687,7 +734,7 @@ static noinline struct btrfs_device *device_list_add(const char *path,
|
||||||
return ERR_PTR(error);
|
return ERR_PTR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
fs_devices = find_fsid_by_device(disk_super);
|
fs_devices = find_fsid_by_device(disk_super, path_devt, &same_fsid_diff_dev);
|
||||||
|
|
||||||
if (!fs_devices) {
|
if (!fs_devices) {
|
||||||
fs_devices = alloc_fs_devices(disk_super->fsid);
|
fs_devices = alloc_fs_devices(disk_super->fsid);
|
||||||
|
@ -698,6 +745,13 @@ static noinline struct btrfs_device *device_list_add(const char *path,
|
||||||
if (IS_ERR(fs_devices))
|
if (IS_ERR(fs_devices))
|
||||||
return ERR_CAST(fs_devices);
|
return ERR_CAST(fs_devices);
|
||||||
|
|
||||||
|
if (same_fsid_diff_dev) {
|
||||||
|
generate_random_uuid(fs_devices->fsid);
|
||||||
|
fs_devices->temp_fsid = true;
|
||||||
|
pr_info("BTRFS: device %s using temp-fsid %pU\n",
|
||||||
|
path, fs_devices->fsid);
|
||||||
|
}
|
||||||
|
|
||||||
mutex_lock(&fs_devices->device_list_mutex);
|
mutex_lock(&fs_devices->device_list_mutex);
|
||||||
list_add(&fs_devices->fs_list, &fs_uuids);
|
list_add(&fs_devices->fs_list, &fs_uuids);
|
||||||
|
|
||||||
|
|
|
@ -364,6 +364,8 @@ struct btrfs_fs_devices {
|
||||||
bool discardable;
|
bool discardable;
|
||||||
/* The filesystem is a seed filesystem. */
|
/* The filesystem is a seed filesystem. */
|
||||||
bool seeding;
|
bool seeding;
|
||||||
|
/* The mount needs to use a randomly generated fsid. */
|
||||||
|
bool temp_fsid;
|
||||||
|
|
||||||
struct btrfs_fs_info *fs_info;
|
struct btrfs_fs_info *fs_info;
|
||||||
/* sysfs kobjects */
|
/* sysfs kobjects */
|
||||||
|
|
Loading…
Add table
Reference in a new issue