diff mbox series

[2/2] btrfs: support cloned-device mount capability

Message ID e85f357bfbcef98bba37e2f39e884a371fc25b56.1695826320.git.anand.jain@oracle.com (mailing list archive)
State New, archived
Headers show
Series btrfs: support cloned-device mount capability | expand

Commit Message

Anand Jain Sept. 28, 2023, 1:09 a.m. UTC
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 :0
  $ mkfs.btrfs -f ./disk1.img :0
  $ cp ./disk1.img ./disk2.img :0
  $ cp ./disk1.img ./disk3.img :0
  $ mount -o loop ./disk1.img /btrfs :0
  $ mount -o ./disk2.img /btrfs1 :0
  $ mount -o ./disk3.img /btrfs2 :0

  $ btrfs fi show -m :0
  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>
---

 fs/btrfs/disk-io.c |  3 ++-
 fs/btrfs/volumes.c | 62 +++++++++++++++++++++++++++++++++++++++++++---
 fs/btrfs/volumes.h |  2 ++
 3 files changed, 63 insertions(+), 4 deletions(-)

Comments

David Sterba Oct. 2, 2023, 12:57 p.m. UTC | #1
On Thu, Sep 28, 2023 at 09:09:47AM +0800, Anand Jain wrote:
> 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 :0
>   $ mkfs.btrfs -f ./disk1.img :0
>   $ cp ./disk1.img ./disk2.img :0
>   $ cp ./disk1.img ./disk3.img :0
>   $ mount -o loop ./disk1.img /btrfs :0
>   $ mount -o ./disk2.img /btrfs1 :0
>   $ mount -o ./disk3.img /btrfs2 :0

I'm confused what the ":0" are supposed to mean, is it some artifact of
your editor?

> 
>   $ btrfs fi show -m :0
>   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>
Anand Jain Oct. 2, 2023, 10:41 p.m. UTC | #2
On 02/10/2023 20:57, David Sterba wrote:
> On Thu, Sep 28, 2023 at 09:09:47AM +0800, Anand Jain wrote:
>> 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/

The link should go at SOB with prefix Link:.

>>
>> 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 :0
>>    $ mkfs.btrfs -f ./disk1.img :0
>>    $ cp ./disk1.img ./disk2.img :0
>>    $ cp ./disk1.img ./disk3.img :0
>>    $ mount -o loop ./disk1.img /btrfs :0
>>    $ mount -o ./disk2.img /btrfs1 :0
>>    $ mount -o ./disk3.img /btrfs2 :0
> 
> I'm confused what the ":0" are supposed to mean, is it some artifact of
> your editor?

Oh, sorry for the confusion. It is the return status of the command.
I have some local scripts to collect the output. Could you pls remove 
":0", or I'll if there is a reroll.

Thanks, Anand

> 
>>
>>    $ btrfs fi show -m :0
>>    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>
diff mbox series

Patch

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index a970da7263b3..04f57d8368c8 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2399,7 +2399,8 @@  int btrfs_validate_super(struct btrfs_fs_info *fs_info,
 		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,
 		"superblock fsid doesn't match fsid of fs_devices: %pU != %pU",
 			  sb->fsid, fs_info->fs_devices->fsid);
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 39b5bc2521fb..ea4a110d7753 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -554,17 +554,64 @@  static int btrfs_free_stale_devices(dev_t devt, struct btrfs_device *skip_device
 }
 
 static struct btrfs_fs_devices *find_fsid_by_disk(
-					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 *devt_fs_devices;
 	bool has_metadata_uuid = (btrfs_super_incompat_flags(disk_super) &
 					BTRFS_FEATURE_INCOMPAT_METADATA_UUID);
+	bool found_by_devt = false;
 
 	/* Find the fs_device by the usual method if found use it */
 	fsid_fs_devices = find_fsid(disk_super->fsid, has_metadata_uuid ?
 					disk_super->metadata_uuid : NULL);
 
-	return fsid_fs_devices;
+	/* The temp_fsid feature is supported only with single device btrfs */
+	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 +717,7 @@  static noinline struct btrfs_device *device_list_add(const char *path,
 	u64 devid = btrfs_stack_device_id(&disk_super->dev_item);
 	dev_t path_devt;
 	int error;
+	bool same_fsid_diff_dev = false;
 	bool has_metadata_uuid = (btrfs_super_incompat_flags(disk_super) &
 		BTRFS_FEATURE_INCOMPAT_METADATA_UUID);
 
@@ -687,7 +735,8 @@  static noinline struct btrfs_device *device_list_add(const char *path,
 		return ERR_PTR(error);
 	}
 
-	fs_devices = find_fsid_by_disk(disk_super);
+	fs_devices = find_fsid_by_disk(disk_super, path_devt,
+				       &same_fsid_diff_dev);
 
 	if (!fs_devices) {
 		fs_devices = alloc_fs_devices(disk_super->fsid);
@@ -698,6 +747,13 @@  static noinline struct btrfs_device *device_list_add(const char *path,
 		if (IS_ERR(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);
 		list_add(&fs_devices->fs_list, &fs_uuids);
 
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index e485e6a3e52c..5921fdd3dd90 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -364,6 +364,8 @@  struct btrfs_fs_devices {
 	bool discardable;
 	/* The filesystem is a seed filesystem. */
 	bool seeding;
+	/* The mount need to use a randomly generated fsid. */
+	bool temp_fsid;
 
 	struct btrfs_fs_info *fs_info;
 	/* sysfs kobjects */