From a997aee58f8f594c34fa1c666c967aece30c9824 Mon Sep 17 00:00:00 2001 From: Roman Bogorodskiy Date: Sat, 25 Oct 2025 10:15:57 +0200 Subject: [PATCH] bhyve: do not allow more than one NVMe device per controller As bhyve does not have explicit notion of controllers, and for NVMe devices it allows to specify one a single source for for a given PCI address, it effectively means that there could be only one device per controller. Update validation code to check this case. Signed-off-by: Roman Bogorodskiy Reviewed-by: Michal Privoznik --- src/bhyve/bhyve_domain.c | 27 +++++++++++++++++++ .../bhyvexml2argv-2-nvme-same-controller.args | 10 +++++++ ...hyvexml2argv-2-nvme-same-controller.ldargs | 4 +++ .../bhyvexml2argv-2-nvme-same-controller.xml | 21 +++++++++++++++ tests/bhyvexml2argvtest.c | 1 + 5 files changed, 63 insertions(+) create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-2-nvme-same-controller.args create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-2-nvme-same-controller.ldargs create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-2-nvme-same-controller.xml diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c index 79ac336430..6b47890c93 100644 --- a/src/bhyve/bhyve_domain.c +++ b/src/bhyve/bhyve_domain.c @@ -310,7 +310,34 @@ bhyveDomainDefValidate(const virDomainDef *def, void *opaque G_GNUC_UNUSED, void *parseOpaque G_GNUC_UNUSED) { + size_t i; virStorageSource *src = NULL; + g_autoptr(GHashTable) nvme_controllers = g_hash_table_new(g_direct_hash, + g_direct_equal); + + for (i = 0; i < def->ndisks; i++) { + virDomainDiskDef *disk = def->disks[i]; + int nvme_ctrl = 0; + int idx = -1; + + if (disk->bus == VIR_DOMAIN_DISK_BUS_NVME) { + if (virDiskNameParse(disk->dst, &nvme_ctrl, &idx, NULL) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Unknown disk name '%1$s' and no address specified"), + disk->dst); + return -1; + } + + if (g_hash_table_contains(nvme_controllers, GINT_TO_POINTER(nvme_ctrl))) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", + _("Cannot have more than one disk per NVMe controller")); + return -1; + } + + g_hash_table_add(nvme_controllers, GINT_TO_POINTER(nvme_ctrl)); + } + } if (!def->os.loader) return 0; diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-2-nvme-same-controller.args b/tests/bhyvexml2argvdata/bhyvexml2argv-2-nvme-same-controller.args new file mode 100644 index 0000000000..664eec99bc --- /dev/null +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-2-nvme-same-controller.args @@ -0,0 +1,10 @@ +bhyve \ +-c 1 \ +-m 214 \ +-u \ +-H \ +-P \ +-s 0:0,hostbridge \ +-s 2:0,nvme,/tmp/freebsd.img \ +-s 3:0,nvme,/tmp/data.img \ +bhyve diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-2-nvme-same-controller.ldargs b/tests/bhyvexml2argvdata/bhyvexml2argv-2-nvme-same-controller.ldargs new file mode 100644 index 0000000000..5905f4b3e6 --- /dev/null +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-2-nvme-same-controller.ldargs @@ -0,0 +1,4 @@ +bhyveload \ +-m 214 \ +-d /tmp/freebsd.img \ +bhyve diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-2-nvme-same-controller.xml b/tests/bhyvexml2argvdata/bhyvexml2argv-2-nvme-same-controller.xml new file mode 100644 index 0000000000..dc4e3c621b --- /dev/null +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-2-nvme-same-controller.xml @@ -0,0 +1,21 @@ + + bhyve + df3be7e7-a104-11e3-aeb0-50e5492bd3dc + 219136 + 1 + + hvm + + + + + + + + + + + + + + diff --git a/tests/bhyvexml2argvtest.c b/tests/bhyvexml2argvtest.c index 9d20e5669e..3c6d530f66 100644 --- a/tests/bhyvexml2argvtest.c +++ b/tests/bhyvexml2argvtest.c @@ -262,6 +262,7 @@ mymain(void) DO_TEST_FAILURE("serial-invalid-port"); DO_TEST("nvme"); DO_TEST("2-nvme-2-controllers"); + DO_TEST_FAILURE("2-nvme-same-controller"); /* Address allocation tests */ DO_TEST("addr-single-sata-disk"); -- 2.47.3