Skip to contentSkip to conversation

ublk: persistent device links

PATCH Superseded Hannes Reinecke 3 participants 4 messages Feb 16 – Feb 20

Subsystems (2)

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 ublk: persistent device links

Implement a 'uuid' parameter to export a device UUID in a sysfs attribute 'uuid'. This allows udev to create persistent device links for ublk devices:

KERNEL=="ublkb*", ATTRS{uuid}=="?*", SYMLINK+="disk/by-id/ublk-$attr{uuid}"

---
 drivers/block/ublk_drv.c      | 57 +++++++++++++++++++++++++++++++++--
 include/uapi/linux/ublk_cmd.h |  6 ++++
 2 files changed, 61 insertions(+), 2 deletions(-)
drivers/block/ublk_drv.c +55 -2
index aaf94d2fb789..859414065be0 100644
@@ -89,7 +89,7 @@
 	(UBLK_PARAM_TYPE_BASIC | UBLK_PARAM_TYPE_DISCARD | \
 	 UBLK_PARAM_TYPE_DEVT | UBLK_PARAM_TYPE_ZONED |    \
 	 UBLK_PARAM_TYPE_DMA_ALIGN | UBLK_PARAM_TYPE_SEGMENT | \
-	 UBLK_PARAM_TYPE_INTEGRITY)
+	 UBLK_PARAM_TYPE_INTEGRITY | UBLK_PARAM_TYPE_UUID)
 
 struct ublk_uring_cmd_pdu {
 	/*
@@ -761,6 +761,16 @@ static int ublk_validate_params(const struct ublk_device *ub)
 			return -EINVAL;
 	}
 
+	if (ub->params.types & UBLK_PARAM_TYPE_UUID) {
+		const struct ublk_param_uuid *p = &ub->params.uuid;
+		uuid_t uuid;
+
+		import_uuid(&uuid, p->uuid);
+		if (uuid_is_null(&uuid)) {
+			printk("uuid is NULL\n");
+			return -EINVAL;
+		}
+	}
 	return 0;
 }
 
@@ -2971,6 +2981,49 @@ static int ublk_add_chdev(struct ublk_device *ub)
 	return ret;
 }
 
+static ssize_t uuid_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct gendisk *disk = dev_to_disk(dev);
+	struct ublk_device *ub = disk->private_data;
+	const struct ublk_param_uuid *p = &ub->params.uuid;
+	uuid_t uuid;
+
+	import_uuid(&uuid, p->uuid);
+	return sprintf(buf, "%pU\n", &uuid);
+}
+
+static DEVICE_ATTR_RO(uuid);
+
+static struct attribute *ublk_attrs[] = {
+	&dev_attr_uuid.attr,
+	NULL,
+};
+
+static umode_t ublk_attrs_are_visible(struct kobject *kobj,
+		struct attribute *a, int n)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct gendisk *disk = dev_to_disk(dev);
+	struct ublk_device *ub = disk->private_data;
+
+	if (a == &dev_attr_uuid.attr &&
+	    (ub->params.types & UBLK_PARAM_TYPE_UUID))
+		return S_IRUGO;
+
+	return a->mode;
+}
+
+static const struct attribute_group ublk_attr_group = {
+	.attrs = ublk_attrs,
+	.is_visible = ublk_attrs_are_visible,
+};
+
+static const struct attribute_group *ublk_attr_groups[] = {
+	&ublk_attr_group,
+	NULL,
+};
+
 /* align max io buffer size with PAGE_SIZE */
 static void ublk_align_max_io_size(struct ublk_device *ub)
 {
@@ -3149,7 +3202,7 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub,
 			goto out_put_cdev;
 	}
 
-	ret = add_disk(disk);
+	ret = device_add_disk(NULL, disk, ublk_attr_groups);
 	if (ret)
 		goto out_put_cdev;
 
include/uapi/linux/ublk_cmd.h +6 -0
index 90f47da4f435..b30a0de44b85 100644
@@ -630,6 +630,10 @@ struct ublk_param_integrity {
 	__u8	pad[5];
 };
 
+struct ublk_param_uuid {
+	__u8	uuid[16];
+};
+
 struct ublk_params {
 	/*
 	 * Total length of parameters, userspace has to set 'len' for both
@@ -645,6 +649,7 @@ struct ublk_params {
 #define UBLK_PARAM_TYPE_DMA_ALIGN       (1 << 4)
 #define UBLK_PARAM_TYPE_SEGMENT         (1 << 5)
 #define UBLK_PARAM_TYPE_INTEGRITY       (1 << 6) /* requires UBLK_F_INTEGRITY */
+#define UBLK_PARAM_TYPE_UUID            (1 << 7)
 	__u32	types;			/* types of parameter included */
 
 	struct ublk_param_basic		basic;
@@ -654,6 +659,7 @@ struct ublk_params {
 	struct ublk_param_dma_align	dma;
 	struct ublk_param_segment	seg;
 	struct ublk_param_integrity	integrity;
+	struct ublk_param_uuid		uuid;
 };
 
 #endif
Signature · 1 line
2.43.0
#1 lore raw
Quoted 5 lines · Hannes Reinecke

Implement a 'uuid' parameter to export a device UUID in a sysfs attribute 'uuid'. This allows udev to create persistent device links for ublk devices:

KERNEL=="ublkb*", ATTRS{uuid}=="?*", SYMLINK+="disk/by-id/ublk-$attr{uuid}"

uuid is passed from ublk server, so the uniqueness has to be provided by ublk server.

So far, the ublk device ID is guaranteed to be unique, can we export ublk device id instead?

Or can you explain a bit if uuid is a must here for some special purpose?

Thanks,
Ming

#2 lore raw
Quoted 10 lines · Ming Lei
Quoted 5 lines · Hannes Reinecke

Implement a 'uuid' parameter to export a device UUID in a sysfs attribute 'uuid'. This allows udev to create persistent device links for ublk devices:

KERNEL=="ublkb*", ATTRS{uuid}=="?*", SYMLINK+="disk/by-id/ublk-$attr{uuid}"

uuid is passed from ublk server, so the uniqueness has to be provided by ublk server.

Correct.

Quoted 3 lines

So far, the ublk device ID is guaranteed to be unique, can we export ublk device id instead?

The device id is unique, but not persistent across reboots. (Note the subject: _persistent_ device links ...)

If you have to reference the ublk device from some configuration tool or automation framework (eg the nvmet json configuration) you have to have a persistent ID to reference the device.
The UUID serves that purpose.
With the additional benefit that you can update the ublk target driver to pick up an UUID defined on the target side, allowing for better identification.
I was actually thinking of adding a 'serial' field with 256 bytes in addtion to the UUID; then we could expose target identifications (like the IQN for the iscsi target, or the NQN for nvme) directly. But that seemed excessive.

Cheers,

Hannes

Signature · 4 lines
Dr. Hannes Reinecke                  Kernel Storage Architect
[email protected]                                +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich
#3 lore raw
In reply to Hannes Reinecke
Quoted 26 lines · Hannes Reinecke

Implement a 'uuid' parameter to export a device UUID in a sysfs attribute 'uuid'. This allows udev to create persistent device links for ublk devices:

KERNEL=="ublkb*", ATTRS{uuid}=="?*", SYMLINK+="disk/by-id/ublk-$attr{uuid}"

---
 drivers/block/ublk_drv.c      | 57 +++++++++++++++++++++++++++++++++--
 include/uapi/linux/ublk_cmd.h |  6 ++++
 2 files changed, 61 insertions(+), 2 deletions(-)
drivers/block/ublk_drv.c +1 -1
index aaf94d2fb789..859414065be0 100644
@@ -89,7 +89,7 @@
 	(UBLK_PARAM_TYPE_BASIC | UBLK_PARAM_TYPE_DISCARD | \
 	 UBLK_PARAM_TYPE_DEVT | UBLK_PARAM_TYPE_ZONED |    \
 	 UBLK_PARAM_TYPE_DMA_ALIGN | UBLK_PARAM_TYPE_SEGMENT | \
-	 UBLK_PARAM_TYPE_INTEGRITY)
+	 UBLK_PARAM_TYPE_INTEGRITY | UBLK_PARAM_TYPE_UUID)
 
 struct ublk_uring_cmd_pdu {
 	/*

drivers/block/ublk_drv.c static int ublk_validate_params(const struct ublk_device *ub) · line 770

Quoted 10 lines
drivers/block/ublk_drv.c +7 -0
@@ -761,6 +761,16 @@ static int ublk_validate_params(const struct ublk_device *ub)
 			return -EINVAL;
 	}
 
+	if (ub->params.types & UBLK_PARAM_TYPE_UUID) {
+		const struct ublk_param_uuid *p = &ub->params.uuid;
+		uuid_t uuid;
+
+		import_uuid(&uuid, p->uuid);
+		if (uuid_is_null(&uuid)) {
+			printk("uuid is NULL\n");

pr_warn() could be better.

Quoted 89 lines
drivers/block/ublk_drv.c +47 -1
+			return -EINVAL;
+		}
+	}
 	return 0;
 }
 
@@ -2971,6 +2981,49 @@ static int ublk_add_chdev(struct ublk_device *ub)
 	return ret;
 }
 
+static ssize_t uuid_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct gendisk *disk = dev_to_disk(dev);
+	struct ublk_device *ub = disk->private_data;
+	const struct ublk_param_uuid *p = &ub->params.uuid;
+	uuid_t uuid;
+
+	import_uuid(&uuid, p->uuid);
+	return sprintf(buf, "%pU\n", &uuid);
+}
+
+static DEVICE_ATTR_RO(uuid);
+
+static struct attribute *ublk_attrs[] = {
+	&dev_attr_uuid.attr,
+	NULL,
+};
+
+static umode_t ublk_attrs_are_visible(struct kobject *kobj,
+		struct attribute *a, int n)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct gendisk *disk = dev_to_disk(dev);
+	struct ublk_device *ub = disk->private_data;
+
+	if (a == &dev_attr_uuid.attr &&
+	    (ub->params.types & UBLK_PARAM_TYPE_UUID))
+		return S_IRUGO;
+
+	return a->mode;
+}
+
+static const struct attribute_group ublk_attr_group = {
+	.attrs = ublk_attrs,
+	.is_visible = ublk_attrs_are_visible,
+};
+
+static const struct attribute_group *ublk_attr_groups[] = {
+	&ublk_attr_group,
+	NULL,
+};
+
 /* align max io buffer size with PAGE_SIZE */
 static void ublk_align_max_io_size(struct ublk_device *ub)
 {
@@ -3149,7 +3202,7 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub,
 			goto out_put_cdev;
 	}
 
-	ret = add_disk(disk);
+	ret = device_add_disk(NULL, disk, ublk_attr_groups);
 	if (ret)
 		goto out_put_cdev;
 
include/uapi/linux/ublk_cmd.h +5 -0
index 90f47da4f435..b30a0de44b85 100644
@@ -630,6 +630,10 @@ struct ublk_param_integrity {
 	__u8	pad[5];
 };
 
+struct ublk_param_uuid {
+	__u8	uuid[16];
+};
+
 struct ublk_params {
 	/*
 	 * Total length of parameters, userspace has to set 'len' for both
@@ -645,6 +649,7 @@ struct ublk_params {
 #define UBLK_PARAM_TYPE_DMA_ALIGN       (1 << 4)
 #define UBLK_PARAM_TYPE_SEGMENT         (1 << 5)
 #define UBLK_PARAM_TYPE_INTEGRITY       (1 << 6) /* requires UBLK_F_INTEGRITY */
+#define UBLK_PARAM_TYPE_UUID            (1 << 7)
 	__u32	types;			/* types of parameter included */
 
 	struct ublk_param_basic		basic;

include/uapi/linux/ublk_cmd.h struct ublk_params { · line 662

Quoted 4 lines
include/uapi/linux/ublk_cmd.h +1 -0
@@ -654,6 +659,7 @@ struct ublk_params {
 	struct ublk_param_dma_align	dma;
 	struct ublk_param_segment	seg;
 	struct ublk_param_integrity	integrity;
+	struct ublk_param_uuid		uuid;

Please document ublk server should provide persistent uuid for persistent id or link.

Otherwise, this patch looks fine.

Thanks,
Ming