Comment 16 for bug 1735839

Dmitrii Shcherbakov (dmitriis) wrote :

Another thing I noticed is that the udev rule for NVMe namespaces is not based on a wwid of a namespace - it is tied to a serial of a controller. For NVMe devices with a single namespace this is ok but NVMe controllers can create multiple namespaces each with its own unique identifier (e.g. in the NVMeOF use-case).

https://paste.ubuntu.com/p/WJYpnWmnxp/
for i in `ls -1 /dev/vd* /dev/sd* /dev/nvme*n*` ; do echo "Info for device $i" ; cat /etc/udev/rules.d/`basename $i`.rules ; echo "Unique attribute: " ; udevadm info -a --path $(udevadm info -q path -n $i) | grep -P 'serial|wwid' ; done

Info for device /dev/nvme0n1
# Written by curtin
SUBSYSTEM=="block", ACTION=="add|change", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="QEMU NVMe Ctrl_nvmec0", SYMLINK+="disk/by-dname/nvme0n1"

SUBSYSTEM=="block", ACTION=="add|change", ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}=="QEMU NVMe Ctrl_nvmec0", SYMLINK+="disk/by-dname/nvme0n1-part%n"
Unique attribute:
    ATTR{wwid}=="nvme.8086-6e766d656330-51454d55204e564d65204374726c-00000001"
    ATTRS{serial}=="nvmec0 "

nvme.8086-6e766d656330-51454d55204e564d65204374726c-00000001 is a wwid of a namespace.

So, I think we should prefer ID_WWN over ID_SERIAL in general and use ID_SERIAL as a fallback:

udevadm info --query=property --name /dev/nvme0n1
DEVLINKS=/dev/disk/by-id/nvme-QEMU_NVMe_Ctrl_nvmec0 /dev/disk/by-path/pci-0000:00:03.0-nvme-1 /dev/disk/by-id/nvme-nvme.8086-6e766d656330-51454d55204e564d65204374726c-00000001 /dev/disk/by-dname/nvme0n1
DEVNAME=/dev/nvme0n1
DEVPATH=/devices/pci0000:00/0000:00:03.0/nvme/nvme0/nvme0n1
DEVTYPE=disk
ID_MODEL=QEMU NVMe Ctrl
ID_PATH=pci-0000:00:03.0-nvme-1
ID_PATH_TAG=pci-0000_00_03_0-nvme-1
ID_SERIAL=QEMU NVMe Ctrl_nvmec0
ID_SERIAL_SHORT=nvmec0
ID_WWN=nvme.8086-6e766d656330-51454d55204e564d65204374726c-00000001
MAJOR=259
MINOR=0
SUBSYSTEM=block
TAGS=:systemd:
USEC_INITIALIZED=1792441

NVMe spec references:

[1] "5.15.2 Identify Namespace data structure
Namespace Globally Unique Identifier (NGUID): This field contains a 128-bit value that is globally unique and assigned to the namespace when the namespace is created. This field remains fixed throughout the life of the namespace and is preserved across namespace and controller operations (e.g., controller reset, namespace format, etc.)."

A namespace ID is extracted from a controller and exported via sysfs via a wwid node:
https://github.com/torvalds/linux/blob/v4.14/drivers/nvme/host/core.c#L802-L818
https://github.com/torvalds/linux/blob/v4.14/drivers/nvme/host/core.c#L2054-L2081

[2] Namespaces also have non-unique (across controllers or NVMe subsystems) numeric namespace identifiers (NSID) that are similar to SCSI LUNs (nvme<controller-num>n<namespace-identifier>), see “Section 6.1.2 Valid and Invalid NSIDs” in the NVMe specification:

“Associated with each controller namespace is a namespace ID, labeled as NSID 1 and NSID 2, that is used by the controller to reference a specific namespace.