From b76e1732f7c4781db4eb1611f7fdbbd7d8f830ad Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 24 Mar 2026 14:44:34 +0100 Subject: [PATCH] vmspawn: add nvme disk type support Extend --image-disk-type= and the --extra-drive= disk type prefix to support nvme in addition to virtio-blk and virtio-scsi: systemd-vmspawn --image-disk-type=nvme --image=image.raw systemd-vmspawn --image=image.raw --extra-drive=nvme:data.raw The NVMe serial number is limited to 20 characters by the NVMe spec. If the image filename exceeds this, it is hashed with SHA-256 and truncated to 20 hex characters via the disk_serial() helper introduced in the previous commit. Signed-off-by: Christian Brauner --- man/systemd-vmspawn.xml | 5 +++-- shell-completion/bash/systemd-vmspawn | 2 +- src/vmspawn/vmspawn-settings.c | 1 + src/vmspawn/vmspawn-settings.h | 1 + src/vmspawn/vmspawn.c | 26 ++++++++++++++++++++++---- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/man/systemd-vmspawn.xml b/man/systemd-vmspawn.xml index 80798f7354c..eec52f13742 100644 --- a/man/systemd-vmspawn.xml +++ b/man/systemd-vmspawn.xml @@ -130,8 +130,9 @@ Specifies the disk type to use for the root disk passed to . Extra drives added via inherit this disk type unless overridden - with an explicit disk type prefix. Takes one of virtio-blk or - virtio-scsi. Defaults to virtio-blk. + with an explicit disk type prefix. Takes one of virtio-blk, + virtio-scsi, or nvme. Defaults to + virtio-blk. diff --git a/shell-completion/bash/systemd-vmspawn b/shell-completion/bash/systemd-vmspawn index 955c59bef5b..718cb300ce4 100644 --- a/shell-completion/bash/systemd-vmspawn +++ b/shell-completion/bash/systemd-vmspawn @@ -61,7 +61,7 @@ _systemd_vmspawn() { elif __contains_word "$prev" ${OPTS[IMAGE_FORMAT]}; then comps='raw qcow2' elif __contains_word "$prev" ${OPTS[IMAGE_DISK_TYPE]}; then - comps='virtio-blk virtio-scsi' + comps='virtio-blk virtio-scsi nvme' elif __contains_word "$prev" ${OPTS[ARG]}; then comps='' else diff --git a/src/vmspawn/vmspawn-settings.c b/src/vmspawn/vmspawn-settings.c index 2e594e59b25..7c30ed753f5 100644 --- a/src/vmspawn/vmspawn-settings.c +++ b/src/vmspawn/vmspawn-settings.c @@ -13,6 +13,7 @@ DEFINE_STRING_TABLE_LOOKUP(image_format, ImageFormat); static const char *const disk_type_table[_DISK_TYPE_MAX] = { [DISK_TYPE_VIRTIO_BLK] = "virtio-blk", [DISK_TYPE_VIRTIO_SCSI] = "virtio-scsi", + [DISK_TYPE_NVME] = "nvme", }; DEFINE_STRING_TABLE_LOOKUP(disk_type, DiskType); diff --git a/src/vmspawn/vmspawn-settings.h b/src/vmspawn/vmspawn-settings.h index 2fe3b84297d..252ceecceb9 100644 --- a/src/vmspawn/vmspawn-settings.h +++ b/src/vmspawn/vmspawn-settings.h @@ -13,6 +13,7 @@ typedef enum ImageFormat { typedef enum DiskType { DISK_TYPE_VIRTIO_BLK, DISK_TYPE_VIRTIO_SCSI, + DISK_TYPE_NVME, _DISK_TYPE_MAX, _DISK_TYPE_INVALID = -EINVAL, } DiskType; diff --git a/src/vmspawn/vmspawn.c b/src/vmspawn/vmspawn.c index 4abc54675b8..72aa39e18a4 100644 --- a/src/vmspawn/vmspawn.c +++ b/src/vmspawn/vmspawn.c @@ -209,7 +209,7 @@ static int help(void) { " -i --image=FILE|DEVICE Root file system disk image or device for the VM\n" " --image-format=FORMAT Specify disk image format (raw, qcow2; default: raw)\n" " --image-disk-type=TYPE\n" - " Specify disk type (virtio-blk, virtio-scsi)\n" + " Specify disk type (virtio-blk, virtio-scsi, nvme; default: virtio-blk)\n" "\n%3$sHost Configuration:%4$s\n" " --cpus=CPUS Configure number of CPUs in guest\n" " --ram=BYTES Configure guest's RAM size\n" @@ -251,8 +251,9 @@ static int help(void) { " --bind-ro=SOURCE[:TARGET]\n" " Mount a file or directory, but read-only\n" " --extra-drive=[FORMAT:][DISKTYPE:]PATH\n" - " Adds an additional disk to the virtual machine\n" - " (FORMAT: raw, qcow2; DISKTYPE: virtio-blk, virtio-scsi)\n" + " Adds an additional disk to the VM\n" + " FORMAT: raw, qcow2\n" + " DISKTYPE: virtio-blk, virtio-scsi, nvme\n" " --bind-user=NAME Bind user from host to virtual machine\n" " --bind-user-shell=BOOL|PATH\n" " Configure the shell to use for --bind-user= users\n" @@ -1994,7 +1995,7 @@ static int make_sidecar_path(const char *suffix, char **ret) { return 0; } -/* Device serial numbers have length limits (e.g. 30 for SCSI). +/* Device serial numbers have length limits (e.g. 20 for NVMe, 30 for SCSI). * If the filename fits, use it directly; otherwise hash it with SHA-256 and * take the first max_len hex characters. max_len must be even and <= 64. * The filename should already be QEMU-escaped (commas doubled) so that the @@ -2593,6 +2594,14 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) { return log_oom(); break; } + case DISK_TYPE_NVME: { + _cleanup_free_ char *serial = NULL; + if (disk_serial(escaped_image_fn, 20, &serial) < 0) + return log_oom(); + if (strv_extend_joined(&cmdline, "nvme,drive=vmspawn,bootindex=1,serial=", serial) < 0) + return log_oom(); + break; + } default: assert_not_reached(); } @@ -2737,6 +2746,15 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) { return log_oom(); break; } + case DISK_TYPE_NVME: { + _cleanup_free_ char *serial = NULL; + r = disk_serial(escaped_drive_fn, 20, &serial); + if (r < 0) + return log_oom(); + if (strv_extendf(&cmdline, "nvme,drive=vmspawn_extra_%zu,serial=%s", i++, serial) < 0) + return log_oom(); + break; + } default: assert_not_reached(); } -- 2.47.3