* [PULL 1/5] hw/nvme: initialize ns->subsys for n->namespace
2026-10-05 11:58 [PULL 0/5] hw/nvme queue Klaus Jensen
@ 2026-10-05 11:58 ` Klaus Jensen
2026-10-05 11:58 ` [PULL 2/5] hw/nvme: support online resize Klaus Jensen
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Klaus Jensen @ 2026-10-05 11:58 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Alexander Mikhalitsyn, Klaus Jensen, Keith Busch,
Klaus Jensen, Jesper Devantier, qemu-block
From: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
We must properly initialize n->namespace.subsys too.
Will be important in the following patches.
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
---
hw/nvme/ctrl.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index c641226e27ad..597aeedd6a11 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -9694,6 +9694,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
ns = &n->namespace;
ns->params.nsid = 1;
ns->ctrl = n;
+ ns->subsys = n->subsys;
if (nvme_ns_setup(ns, errp)) {
return;
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PULL 2/5] hw/nvme: support online resize
2026-10-05 11:58 [PULL 0/5] hw/nvme queue Klaus Jensen
2026-10-05 11:58 ` [PULL 1/5] hw/nvme: initialize ns->subsys for n->namespace Klaus Jensen
@ 2026-10-05 11:58 ` Klaus Jensen
2026-10-05 11:58 ` [PULL 3/5] hw/nvme: fix assertion failure on sr-iov capable nvme controller removal Klaus Jensen
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Klaus Jensen @ 2026-10-05 11:58 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Alexander Mikhalitsyn, Klaus Jensen, Keith Busch,
Klaus Jensen, Jesper Devantier, qemu-block
From: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
Implement (BlockDevOps *)->resize_cb() for NVMe namespace to enable
online resize support.
We must handle cases when multiple namespaces are attached to
a single controller, or namespace is shared across a few
different controllers by iterating over controllers attached to
a NvmeSubsystem and properly notify every controller about a size change.
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io>
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
---
hw/nvme/ctrl.c | 9 +++++++
hw/nvme/ns.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++-
hw/nvme/nvme.h | 2 ++
3 files changed, 77 insertions(+), 1 deletion(-)
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index 597aeedd6a11..3e8a1c8b77b1 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -7043,6 +7043,15 @@ static uint16_t nvme_ns_attachment(NvmeCtrl *n, NvmeRequest *req)
return NVME_SUCCESS;
}
+void nvme_ctrl_notify_ns_resize(NvmeCtrl *ctrl, NvmeNamespace *ns)
+{
+ if (!test_and_set_bit(ns->params.nsid, ctrl->changed_nsids)) {
+ nvme_enqueue_event(ctrl, NVME_AER_TYPE_NOTICE,
+ NVME_AER_INFO_NOTICE_NS_ATTR_CHANGED,
+ NVME_LOG_CHANGED_NSLIST);
+ }
+}
+
typedef struct NvmeFormatAIOCB {
BlockAIOCB common;
BlockAIOCB *aiocb;
diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c
index 7f0f9ac7662c..de15921b613b 100644
--- a/hw/nvme/ns.c
+++ b/hw/nvme/ns.c
@@ -163,6 +163,69 @@ lbaf_found:
return 0;
}
+static void nvme_ns_resize_cb(void *opaque)
+{
+ NvmeNamespace *ns = opaque;
+ int64_t size;
+ int cntlid, notified_ctrls;
+
+ size = blk_getlength(ns->blkconf.blk);
+ if (size < 0) {
+ error_report("can't get size of block device %s: %s",
+ blk_name(ns->blkconf.blk), strerror(-size));
+ return;
+ }
+
+ ns->size = size;
+ nvme_ns_init_format(ns);
+
+ if (!ns->attached) {
+ return;
+ }
+
+ /*
+ * Okay, the namespace is attached so we need to notify all controllers
+ * about size change.
+ *
+ * Let's just take ns->subsys, iterate over all controllers and find
+ * to which of them our namespace is attached.
+ */
+
+ assert(ns->subsys);
+
+ notified_ctrls = 0;
+ for (cntlid = 0; cntlid < ARRAY_SIZE(ns->subsys->ctrls); cntlid++) {
+ NvmeCtrl *ctrl;
+
+ /* notified everyone? */
+ if (notified_ctrls == ns->attached) {
+ break;
+ }
+
+ ctrl = nvme_subsys_ctrl(ns->subsys, cntlid);
+ if (!ctrl) {
+ continue;
+ }
+
+ for (uint32_t nsid = 1; nsid <= NVME_MAX_NAMESPACES; nsid++) {
+ NvmeNamespace *ns_iter = ctrl->namespaces[nsid];
+
+ if (!ns_iter || ns_iter != ns) {
+ continue;
+ }
+
+ nvme_ctrl_notify_ns_resize(ctrl, ns);
+
+ notified_ctrls++;
+ break;
+ }
+ }
+}
+
+static const BlockDevOps nvme_ns_block_ops = {
+ .resize_cb = nvme_ns_resize_cb,
+};
+
static int nvme_ns_init_blk(NvmeNamespace *ns, Error **errp)
{
bool read_only;
@@ -172,10 +235,12 @@ static int nvme_ns_init_blk(NvmeNamespace *ns, Error **errp)
}
read_only = !blk_supports_write_perm(ns->blkconf.blk);
- if (!blkconf_apply_backend_options(&ns->blkconf, read_only, false, errp)) {
+ if (!blkconf_apply_backend_options(&ns->blkconf, read_only, true, errp)) {
return -1;
}
+ blk_set_dev_ops(ns->blkconf.blk, &nvme_ns_block_ops, ns);
+
if (ns->blkconf.discard_granularity == -1) {
ns->blkconf.discard_granularity =
MAX(ns->blkconf.logical_block_size, MIN_DISCARD_GRANULARITY);
diff --git a/hw/nvme/nvme.h b/hw/nvme/nvme.h
index 43e3c916f73f..a4b2c01a2cc4 100644
--- a/hw/nvme/nvme.h
+++ b/hw/nvme/nvme.h
@@ -764,6 +764,8 @@ void nvme_atomic_configure_max_write_size(bool dn, uint16_t awun,
void nvme_ns_atomic_configure_boundary(bool dn, uint16_t nabsn,
uint16_t nabspf, NvmeAtomic *atomic);
+void nvme_ctrl_notify_ns_resize(NvmeCtrl *ctrl, NvmeNamespace *ns);
+
extern const VMStateDescription nvme_vmstate_atomic;
extern const VMStateDescription nvme_vmstate_ns;
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PULL 3/5] hw/nvme: fix assertion failure on sr-iov capable nvme controller removal
2026-10-05 11:58 [PULL 0/5] hw/nvme queue Klaus Jensen
2026-10-05 11:58 ` [PULL 1/5] hw/nvme: initialize ns->subsys for n->namespace Klaus Jensen
2026-10-05 11:58 ` [PULL 2/5] hw/nvme: support online resize Klaus Jensen
@ 2026-10-05 11:58 ` Klaus Jensen
2026-10-05 11:58 ` [PULL 4/5] hw/nvme: fix memory leak " Klaus Jensen
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Klaus Jensen @ 2026-10-05 11:58 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Daniel Paziyski, qemu-stable, Klaus Jensen,
Keith Busch, Klaus Jensen, Jesper Devantier, qemu-block
From: Daniel Paziyski <danielpaziyski@gmail.com>
In a nvme subsystem, the ctrls array maps controller IDs to nvme controllers.
The value of the array elements can either be NULL (no controller present for
this ID), SUBSYS_SLOT_RSVD, or any other value, representing a pointer to the
nvme controller structure.
The SUBSYS_SLOT_RSVD value is special: when a nvme controller physical function
is being created and is reserving the controller IDs for its virtual functions,
it indicates that the slot is soon going to be filled by its corresponding
virtual function when it is realized, and on virtual function removal, it means
that its controller has been removed.
When the physical function is being removed, it goes through its list of
secondary controllers (virtual functions), ensures that their slots have the
SUBSYS_SLOT_RSVD values, and then frees up the controller IDs by setting the
NULL value. This traversal occurs before the virtual functions are destroyed,
causing an assertion failure because the slots contain as values the pointers to
the secondary controllers.
Destroy the virtual functions (and therefore, the secondary controllers) after
they are offlined in the nvme_ctrl_reset call of the physical function, but
before releasing the controller IDs of the secondary controllers in
nvme_subsys_unregister_ctrl.
QEMU command line (boot with a hotunplug-aware OS, such as Linux):
qemu-system-x86_64 -M q35 -device pcie-root-port,id=rp -monitor stdio \
-device nvme-subsys,id=subsys0 \
-device nvme,subsys=subsys0,serial=ctrl0,sriov_max_vfs=1,\
sriov_vq_flexible=2,sriov_vi_flexible=1,max_ioqpairs=4,msix_qsize=2,bus=rp,id=ctrl0
In the QEMU monitor:
device_del ctrl0
Message in stderr:
qemu-system-x86_64: ../hw/nvme/subsys.c:49: nvme_subsys_unreserve_cntlids: Assertion `subsys->ctrls[cntlid] == SUBSYS_SLOT_RSVD' failed.
Cc: qemu-stable@nongnu.org
Fixes: 44c2c09488db ("hw/nvme: Add support for SR-IOV")
Signed-off-by: Daniel Paziyski <danielpaziyski@gmail.com>
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
---
hw/nvme/ctrl.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index 3e8a1c8b77b1..1047961b03c5 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -9732,6 +9732,10 @@ static void nvme_exit(PCIDevice *pci_dev)
}
}
+ if (!pci_is_vf(pci_dev) && n->params.sriov_max_vfs) {
+ pcie_sriov_pf_exit(pci_dev);
+ }
+
nvme_subsys_unregister_ctrl(n->subsys, n);
g_free(n->cq);
@@ -9756,10 +9760,6 @@ static void nvme_exit(PCIDevice *pci_dev)
host_memory_backend_set_mapped(n->pmr.dev, false);
}
- if (!pci_is_vf(pci_dev) && n->params.sriov_max_vfs) {
- pcie_sriov_pf_exit(pci_dev);
- }
-
if (n->params.msix_exclusive_bar && !pci_is_vf(pci_dev)) {
msix_uninit_exclusive_bar(pci_dev);
} else {
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PULL 4/5] hw/nvme: fix memory leak on sr-iov capable nvme controller removal
2026-10-05 11:58 [PULL 0/5] hw/nvme queue Klaus Jensen
` (2 preceding siblings ...)
2026-10-05 11:58 ` [PULL 3/5] hw/nvme: fix assertion failure on sr-iov capable nvme controller removal Klaus Jensen
@ 2026-10-05 11:58 ` Klaus Jensen
2026-10-05 11:58 ` [PULL 5/5] hw/nvme: fix firmware boot path when nvme-ns has a bootindex Klaus Jensen
2026-10-07 7:58 ` [PULL 0/5] hw/nvme queue Richard Henderson
5 siblings, 0 replies; 7+ messages in thread
From: Klaus Jensen @ 2026-10-05 11:58 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Daniel Paziyski, qemu-stable, Klaus Jensen,
Keith Busch, Klaus Jensen, Jesper Devantier, qemu-block
From: Daniel Paziyski <danielpaziyski@gmail.com>
If a nvme controller is SR-IOV capable, its list of secondary controllers
(virtual functions) is stored in the sec_ctrl_list dynamically allocated
array, located in the NvmeCtrl struct.
Free the secondary controller list after destroying the virtual functions and
freeing their controller IDs.
QEMU command line (boot with a hotunplug-aware OS, such as Linux):
qemu-system-x86_64 -M q35 -device pcie-root-port,id=rp -monitor stdio \
-device nvme-subsys,id=subsys0 \
-device nvme,subsys=subsys0,serial=ctrl0,sriov_max_vfs=1,\
sriov_vq_flexible=2,sriov_vi_flexible=1,max_ioqpairs=4,msix_qsize=2,bus=rp,id=ctrl0
In the QEMU monitor:
device_del ctrl0
quit
ASAN splat:
==78982==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 32 byte(s) in 1 object(s) allocated from:
#0 0x7fcbab32bea9 in calloc (/usr/lib/libasan.so.8+0x12bea9) (BuildId: 7f2845989b820f536270e19ec47df085ae89a675)
#1 0x7fcbaa2a34b2 in g_malloc0 (/usr/lib/libglib-2.0.so.0+0x694b2) (BuildId: cb17d184459352a7985a010f1cd3acef4a4f90d8)
#2 0x559c531fff4b in nvme_subsys_register_ctrl ../hw/nvme/subsys.c:65
#3 0x559c531d715e in nvme_init_subsys ../hw/nvme/ctrl.c:9582
#4 0x559c531d7a7d in nvme_realize ../hw/nvme/ctrl.c:9637
#5 0x559c5323c0da in pci_qdev_realize ../hw/pci/pci.c:2316
#6 0x559c54001e88 in device_set_realized ../hw/core/qdev.c:514
#7 0x559c5402462e in property_set_bool ../qom/object.c:2484
#8 0x559c5401dbd2 in object_property_set ../qom/object.c:1548
#9 0x559c5402b76c in object_property_set_qobject ../qom/qom-qobject.c:28
#10 0x559c5401e24c in object_property_set_bool ../qom/object.c:1618
#11 0x559c53fffd77 in qdev_realize ../hw/core/qdev.c:277
#12 0x559c53934166 in qdev_device_add_from_qdict ../system/qdev-monitor.c:740
#13 0x559c53934272 in qdev_device_add ../system/qdev-monitor.c:758
#14 0x559c538867c8 in device_init_func ../system/vl.c:1217
#15 0x559c5487236a in qemu_opts_foreach ../util/qemu-option.c:1148
#16 0x559c53891205 in qemu_create_cli_devices ../system/vl.c:2762
#17 0x559c53891968 in qmp_x_exit_preconfig ../system/vl.c:2822
#18 0x559c53898108 in qemu_init ../system/vl.c:3862
#19 0x559c545efabf in main ../system/main.c:71
#20 0x7fcba7627780 (/usr/lib/libc.so.6+0x27780) (BuildId: 1fa174a830cef40a5b2388add4318ee2795f573e)
#21 0x7fcba76278b8 in __libc_start_main (/usr/lib/libc.so.6+0x278b8) (BuildId: 1fa174a830cef40a5b2388add4318ee2795f573e)
#22 0x559c524df1f4 in _start (BuildId: 35402cb4fc46114b7a4102258726bbdec82cd9bc)
Cc: qemu-stable@nongnu.org
Fixes: c6159d0e384f ("hw/nvme: Allocate sec-ctrl-list as a dynamic array")
Signed-off-by: Daniel Paziyski <danielpaziyski@gmail.com>
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
---
hw/nvme/ctrl.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index 1047961b03c5..578421c21761 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -9738,6 +9738,10 @@ static void nvme_exit(PCIDevice *pci_dev)
nvme_subsys_unregister_ctrl(n->subsys, n);
+ if (!pci_is_vf(pci_dev) && n->params.sriov_max_vfs) {
+ g_free(n->sec_ctrl_list);
+ }
+
g_free(n->cq);
g_free(n->sq);
g_free(n->aer_reqs);
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PULL 5/5] hw/nvme: fix firmware boot path when nvme-ns has a bootindex
2026-10-05 11:58 [PULL 0/5] hw/nvme queue Klaus Jensen
` (3 preceding siblings ...)
2026-10-05 11:58 ` [PULL 4/5] hw/nvme: fix memory leak " Klaus Jensen
@ 2026-10-05 11:58 ` Klaus Jensen
2026-10-07 7:58 ` [PULL 0/5] hw/nvme queue Richard Henderson
5 siblings, 0 replies; 7+ messages in thread
From: Klaus Jensen @ 2026-10-05 11:58 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Luigi Leonardi, Gerd Hoffmann, Klaus Jensen,
Keith Busch, Klaus Jensen, Jesper Devantier, qemu-block
From: Luigi Leonardi <leonardi@redhat.com>
The correct way to register an NVMe namespace in fw_boot_order is to use
the NVMe controller as the device pointer with the namespace ID appended
as a suffix, producing:
/pci@i0cf8/pci1b36,0010@4/namespace@1,0
This is how the controller-level bootindex works.
Explicit nvme-ns devices instead register the nvme-ns device itself,
which is wrong: realize() reparents the namespace onto the NVMe subsystem
bus, disconnecting it from the controller in the bus hierarchy.
qdev_get_fw_dev_path() therefore produces a path without the controller's
address:
/nvme-ns/namespace@1,0
Fix by re-registering in realize(), once the controller and final nsid
are known, using the controller as the device pointer with the namespace
suffix. The old entry (registered against the nvme-ns device) must be
removed first since add_boot_device_path() only removes entries matching
the same device pointer, and leaving both would cause a
duplicate-bootindex error.
device_add_bootindex_property() cannot be called in realize() because
QEMU parses command-line properties before realize() runs, so the
bootindex property must exist by instance_init() time. The final nsid is
not yet known then either as it's assigned in realize().
The fix is restricted to non-shared namespaces: for shared namespaces
there is no single controller to register the boot path against.
Also add the symmetric unrealize() cleanup so that hot-unplugging a
non-shared nvme-ns with a bootindex removes the fw_boot_order entry that
was registered against the controller in realize().
Reported-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Luigi Leonardi <leonardi@redhat.com>
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
---
hw/nvme/ns.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c
index de15921b613b..2ae26a9acbd0 100644
--- a/hw/nvme/ns.c
+++ b/hw/nvme/ns.c
@@ -792,6 +792,10 @@ static void nvme_ns_unrealize(DeviceState *dev)
nvme_ns_shutdown(ns);
nvme_ns_cleanup(ns);
+ if (!ns->params.shared && ns->bootindex >= 0) {
+ del_boot_device_path(DEVICE(ns->ctrl), ns->bootindex_suffix);
+ }
+
/* Symmetric with nvme_ns_realize() which sets subsys->namespaces[nsid]. */
if (subsys && nsid && subsys->namespaces[nsid] == ns) {
subsys->namespaces[nsid] = NULL;
@@ -956,6 +960,19 @@ static void nvme_ns_realize(DeviceState *dev, Error **errp)
if (!ns->params.shared) {
ns->ctrl = n;
+
+ /*
+ * Register the boot device path using the NVMe controller
+ * so the OFW path includes the controller's PCI address:
+ * /pci@i0cf8/pci1b36,0010@<slot>,0/namespace@<nsid>,0
+ */
+ if (ns->bootindex >= 0) {
+ del_boot_device_path(dev, NULL);
+ snprintf(ns->bootindex_suffix, sizeof(ns->bootindex_suffix),
+ "/namespace@%" PRIu32 ",0", nsid);
+ add_boot_device_path(ns->bootindex, DEVICE(n),
+ ns->bootindex_suffix);
+ }
}
}
@@ -1182,10 +1199,8 @@ static void nvme_ns_instance_init(Object *obj)
{
NvmeNamespace *ns = NVME_NS(obj);
- sprintf(ns->bootindex_suffix, "/namespace@%" PRIu32 ",0", ns->params.nsid);
-
device_add_bootindex_property(obj, &ns->bootindex, "bootindex",
- ns->bootindex_suffix, DEVICE(obj));
+ NULL, DEVICE(obj));
}
static const TypeInfo nvme_ns_info = {
--
2.53.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PULL 0/5] hw/nvme queue
2026-10-05 11:58 [PULL 0/5] hw/nvme queue Klaus Jensen
` (4 preceding siblings ...)
2026-10-05 11:58 ` [PULL 5/5] hw/nvme: fix firmware boot path when nvme-ns has a bootindex Klaus Jensen
@ 2026-10-07 7:58 ` Richard Henderson
5 siblings, 0 replies; 7+ messages in thread
From: Richard Henderson @ 2026-10-07 7:58 UTC (permalink / raw)
To: Klaus Jensen, qemu-devel; +Cc: Peter Maydell, Klaus Jensen
On 10/5/26 13:58, Klaus Jensen wrote:
> From: Klaus Jensen<k.jensen@samsung.com>
>
> Hi,
>
> The following changes since commit d7a65d1793d691d356a56833620f7d1e6f5d653b:
>
> Merge tag 'hppa-a400-updates-pull-request' ofhttps://github.com/hdeller/qemu-hppa into staging (2026-10-03 14:17:49 +0200)
>
> are available in the Git repository at:
>
> https://gitlab.com/birkelund/qemu.git tags/pull-nvme-20261005
>
> for you to fetch changes up to f6c0588fd7c22caefc5b31f485c8bb3ee994a58b:
>
> hw/nvme: fix firmware boot path when nvme-ns has a bootindex (2026-10-05 11:00:47 +0200)
>
> ----------------------------------------------------------------
> nvme queue
Applied, thanks.
r~
^ permalink raw reply [flat|nested] 7+ messages in thread