* Re: [PATCH v3] hw/nvme: add namespace hotplug support [not found] <CAPSO8MwceccK3gHgbeZi0A9=p8B9VV85whYmN1D343gV=9PucA@mail.gmail.com> @ 2026-04-13 17:18 ` Stefan Hajnoczi 0 siblings, 0 replies; 5+ messages in thread From: Stefan Hajnoczi @ 2026-04-13 17:18 UTC (permalink / raw) To: Matthieu Rolla; +Cc: qemu-devel [-- Attachment #1: Type: text/plain, Size: 704 bytes --] On Mon, Apr 13, 2026 at 04:13:38PM +0200, Matthieu Rolla wrote: > Hello Stefan, > > Thanks let me know how it goes. [Resending to qemu-devel so others are aware too.] Hi Matthieu, Windows Server 2022 Build 20348 successfully handles NVMe Namespace List changes with your QEMU patch. When adding the disk a new drive appears as expected. When removing the disk the drive disappears and there is a Windows Event Log event about a surprise removal. Windows probably has a procedure for safely removing drives, but this basic test seems like enough confirmation that it is working. Drive letters are preserved across hotplug, so I think everything is working as expected. Stefan [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 0/2] NVMe namespace hotplug and drive reconnection support @ 2026-04-09 6:01 mr-083 2026-04-10 14:30 ` [PATCH v3] hw/nvme: add namespace hotplug support mr-083 0 siblings, 1 reply; 5+ messages in thread From: mr-083 @ 2026-04-09 6:01 UTC (permalink / raw) To: qemu-devel, qemu-block; +Cc: its, kbusch, stefanha, mr-083 This series adds two features that together enable transparent NVMe disk hot-swap simulation in QEMU, matching the behavior of physical NVMe drives being pulled and reinserted in the same PCIe slot. Problem: Currently, hot-swapping an NVMe disk in QEMU requires removing the entire NVMe controller via device_del, which causes the Linux guest to assign a new controller number on re-add (e.g. nvme2 becomes nvme4). This breaks storage software that tracks drives by device name. Solution: Patch 1 adds hotplug support for nvme-ns devices on the NvmeBus, with proper Asynchronous Event Notification (AEN) so the guest kernel detects namespace changes. This allows namespace-level hot-swap without removing the NVMe controller. Patch 2 adds a drive_insert HMP command that reconnects a host block device file to an existing guest device after drive_del. This is the counterpart to drive_del for non-removable devices where blockdev-change-medium cannot be used. The recommended hot-swap sequence is: 1. drive_del <drive-id> # disconnect backing store 2. drive_insert <device> <file> # reconnect backing store 3. pcie_aer_inject_error <port> SDN # trigger controller reset After this sequence, the guest sees the same controller and namespace names (e.g. /dev/nvme2n1 remains /dev/nvme2n1), and the NVMe driver recovers transparently via the standard AER recovery path. Tested with: - Linux 6.1 guest on QEMU aarch64 with HVF (macOS) - NVMe subsystem model with multipath disabled - DirectPV and MinIO AIStor storage stack mr-083 (2): hw/nvme: add namespace hotplug support block/monitor: add drive_insert HMP command block/monitor/block-hmp-cmds.c | 59 +++++++++++++++++++++++ hmp-commands.hx | 18 +++++++ hw/nvme/ctrl.c | 85 ++++++++++++++++++++++++++++++++++ hw/nvme/ns.c | 1 + hw/nvme/subsys.c | 2 + include/block/block-hmp-cmds.h | 1 + 6 files changed, 166 insertions(+) -- 2.50.1 (Apple Git-155) ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v3] hw/nvme: add namespace hotplug support 2026-04-09 6:01 [PATCH 0/2] NVMe namespace hotplug and drive reconnection support mr-083 @ 2026-04-10 14:30 ` mr-083 2026-04-10 14:33 ` Matthieu Rolla 0 siblings, 1 reply; 5+ messages in thread From: mr-083 @ 2026-04-10 14:30 UTC (permalink / raw) To: qemu-devel, qemu-block; +Cc: its, kbusch, stefanha, mr-083 Add hotplug support for nvme-ns devices on the NvmeBus. This enables NVMe namespace-level hot-add and hot-remove via device_add and device_del with proper Asynchronous Event Notification (AEN), so the guest kernel can react to namespace topology changes. Mark nvme-ns devices as hotpluggable and register the NvmeBus as a hotplug handler with proper plug and unplug callbacks: - plug: attach namespace to all started controllers and send an Asynchronous Event Notification (AEN) with NS_ATTR_CHANGED so the guest kernel rescans namespaces and adds the block device - unplug: drain in-flight I/O, detach from all controllers, send AEN, then unrealize the device. The guest kernel rescans and removes the block device. The plug handler skips controllers that haven't started yet (qs_created == false) to avoid interfering with boot-time namespace attachment in nvme_start_ctrl(). The unplug handler drains in-flight I/O via nvme_ns_drain() before detaching the namespace from controllers, so pending requests can complete normally without touching freed state. For symmetry with nvme_ns_realize() which sets subsys->namespaces[nsid], nvme_ns_unrealize() now clears that slot too — making the namespace lifecycle complete. Both the controller bus and subsystem bus are configured as hotplug handlers via qbus_set_bus_hotplug_handler() since nvme-ns devices may reparent to the subsystem bus during realize. Example hot-swap sequence using the NVMe subsystem model: # Boot with: -device nvme-subsys,id=subsys0 # -device nvme,id=ctrl0,subsys=subsys0 # -device nvme-ns,id=ns0,drive=drv0,bus=ctrl0,nsid=1 device_del ns0 # guest receives AEN, removes /dev/nvme0n1 drive_del drv0 drive_add 0 file=disk.qcow2,format=qcow2,id=drv0,if=none device_add nvme-ns,id=ns0,drive=drv0,bus=ctrl0,nsid=1 # guest receives AEN, adds /dev/nvme0n1 Tested with Linux 6.1 guest (NVMe driver processes AEN and rescans namespace list automatically). Signed-off-by: Matthieu <matthieu@min.io> --- hw/nvme/ctrl.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ hw/nvme/ns.c | 8 +++++ hw/nvme/subsys.c | 2 ++ 3 files changed, 98 insertions(+) diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index be6c7028cb..2024b0ff75 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -206,6 +206,7 @@ #include "system/hostmem.h" #include "hw/pci/msix.h" #include "hw/pci/pcie_sriov.h" +#include "hw/core/qdev.h" #include "system/spdm-socket.h" #include "migration/vmstate.h" @@ -9293,6 +9294,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp) } qbus_init(&n->bus, sizeof(NvmeBus), TYPE_NVME_BUS, dev, dev->id); + qbus_set_bus_hotplug_handler(BUS(&n->bus)); if (nvme_init_subsys(n, errp)) { return; @@ -9553,10 +9555,96 @@ static const TypeInfo nvme_info = { }, }; +static void nvme_ns_hot_plug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + NvmeNamespace *ns = NVME_NS(dev); + NvmeSubsystem *subsys = ns->subsys; + uint32_t nsid = ns->params.nsid; + int i; + + /* + * Attach to all started controllers and notify via AEN. + * Skip controllers that haven't started yet (boot-time realize) — + * nvme_start_ctrl() will attach namespaces during controller init. + */ + for (i = 0; i < NVME_MAX_CONTROLLERS; i++) { + NvmeCtrl *ctrl = nvme_subsys_ctrl(subsys, i); + if (!ctrl || !ctrl->qs_created) { + continue; + } + + if (nvme_csi_supported(ctrl, ns->csi) && !ns->params.detached) { + nvme_attach_ns(ctrl, ns); + nvme_update_dsm_limits(ctrl, ns); + + if (!test_and_set_bit(nsid, ctrl->changed_nsids)) { + nvme_enqueue_event(ctrl, NVME_AER_TYPE_NOTICE, + NVME_AER_INFO_NOTICE_NS_ATTR_CHANGED, + NVME_LOG_CHANGED_NSLIST); + } + } + } +} + +static void nvme_ns_hot_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, + Error **errp) +{ + NvmeNamespace *ns = NVME_NS(dev); + NvmeSubsystem *subsys = ns->subsys; + uint32_t nsid = ns->params.nsid; + int i; + + /* + * Drain in-flight I/O before tearing down the namespace. + * This must happen while the namespace is still attached to the + * controllers so any pending requests can complete normally. + */ + nvme_ns_drain(ns); + + /* + * Detach from all controllers and notify the guest via AEN. + * The guest kernel will rescan namespaces and remove the block device. + */ + for (i = 0; i < NVME_MAX_CONTROLLERS; i++) { + NvmeCtrl *ctrl = nvme_subsys_ctrl(subsys, i); + if (!ctrl || !nvme_ns(ctrl, nsid)) { + continue; + } + + nvme_detach_ns(ctrl, ns); + nvme_update_dsm_limits(ctrl, NULL); + + if (!test_and_set_bit(nsid, ctrl->changed_nsids)) { + nvme_enqueue_event(ctrl, NVME_AER_TYPE_NOTICE, + NVME_AER_INFO_NOTICE_NS_ATTR_CHANGED, + NVME_LOG_CHANGED_NSLIST); + } + } + + /* + * Unrealize: removes from subsystem (in nvme_ns_unrealize), flushes, + * cleans up structures, and removes from QOM. + */ + qdev_unrealize(dev); +} + +static void nvme_bus_class_init(ObjectClass *klass, const void *data) +{ + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); + hc->plug = nvme_ns_hot_plug; + hc->unplug = nvme_ns_hot_unplug; +} + static const TypeInfo nvme_bus_info = { .name = TYPE_NVME_BUS, .parent = TYPE_BUS, .instance_size = sizeof(NvmeBus), + .class_init = nvme_bus_class_init, + .interfaces = (const InterfaceInfo[]) { + { TYPE_HOTPLUG_HANDLER }, + { } + }, }; static void nvme_register_types(void) diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c index b0106eaa5c..f4f755c6fc 100644 --- a/hw/nvme/ns.c +++ b/hw/nvme/ns.c @@ -719,10 +719,17 @@ void nvme_ns_cleanup(NvmeNamespace *ns) static void nvme_ns_unrealize(DeviceState *dev) { NvmeNamespace *ns = NVME_NS(dev); + NvmeSubsystem *subsys = ns->subsys; + uint32_t nsid = ns->params.nsid; nvme_ns_drain(ns); nvme_ns_shutdown(ns); nvme_ns_cleanup(ns); + + /* Symmetric with nvme_ns_realize() which sets subsys->namespaces[nsid]. */ + if (subsys && nsid && subsys->namespaces[nsid] == ns) { + subsys->namespaces[nsid] = NULL; + } } void nvme_ns_atomic_configure_boundary(bool dn, uint16_t nabsn, @@ -937,6 +944,7 @@ static void nvme_ns_class_init(ObjectClass *oc, const void *data) dc->bus_type = TYPE_NVME_BUS; dc->realize = nvme_ns_realize; dc->unrealize = nvme_ns_unrealize; + dc->hotpluggable = true; device_class_set_props(dc, nvme_ns_props); dc->desc = "Virtual NVMe namespace"; } diff --git a/hw/nvme/subsys.c b/hw/nvme/subsys.c index 777e1c620f..fa35055d3c 100644 --- a/hw/nvme/subsys.c +++ b/hw/nvme/subsys.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qapi/error.h" +#include "hw/core/qdev.h" #include "nvme.h" @@ -205,6 +206,7 @@ static void nvme_subsys_realize(DeviceState *dev, Error **errp) NvmeSubsystem *subsys = NVME_SUBSYS(dev); qbus_init(&subsys->bus, sizeof(NvmeBus), TYPE_NVME_BUS, dev, dev->id); + qbus_set_bus_hotplug_handler(BUS(&subsys->bus)); nvme_subsys_setup(subsys, errp); } -- 2.53.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v3] hw/nvme: add namespace hotplug support 2026-04-10 14:30 ` [PATCH v3] hw/nvme: add namespace hotplug support mr-083 @ 2026-04-10 14:33 ` Matthieu Rolla 2026-04-10 20:14 ` Stefan Hajnoczi 0 siblings, 1 reply; 5+ messages in thread From: Matthieu Rolla @ 2026-04-10 14:33 UTC (permalink / raw) To: qemu-devel, qemu-block; +Cc: its, kbusch, stefanha, mr-083 [-- Attachment #1: Type: text/plain, Size: 9028 bytes --] Hello @Stefan Hajnoczi <stefanha@redhat.com> , Thanks for the review! v3 sent. Wording: Fixed in v3, no more "physical PCIe slot" claim. Now describes it as NVMe namespace-level hotplug. I/O drain: Moved nvme_ns_drain() to the start of the unplug handler so in-flight I/O completes before detach. Tested under warp load (16 concurrent 1MiB uploads via MinIO/DirectPV) device_del returns in ~400ms with clean removal, no use-after-free. Symmetry: moved subsys->namespaces[nsid] = NULL into nvme_ns_unrealize() so the namespace lifecycle is complete (mirrors what nvme_ns_realize() sets up). I don't have a working Windows test setup, I'd really appreciate if you could test it next week as you offered. Thanks again for your time On Fri, Apr 10, 2026 at 4:29 PM mr-083 <matthieu@minio.io> wrote: > Add hotplug support for nvme-ns devices on the NvmeBus. This enables > NVMe namespace-level hot-add and hot-remove via device_add and > device_del with proper Asynchronous Event Notification (AEN), so the > guest kernel can react to namespace topology changes. > > Mark nvme-ns devices as hotpluggable and register the NvmeBus as a > hotplug handler with proper plug and unplug callbacks: > > - plug: attach namespace to all started controllers and send an > Asynchronous Event Notification (AEN) with NS_ATTR_CHANGED so > the guest kernel rescans namespaces and adds the block device > - unplug: drain in-flight I/O, detach from all controllers, send > AEN, then unrealize the device. The guest kernel rescans and > removes the block device. > > The plug handler skips controllers that haven't started yet > (qs_created == false) to avoid interfering with boot-time namespace > attachment in nvme_start_ctrl(). > > The unplug handler drains in-flight I/O via nvme_ns_drain() before > detaching the namespace from controllers, so pending requests can > complete normally without touching freed state. > > For symmetry with nvme_ns_realize() which sets subsys->namespaces[nsid], > nvme_ns_unrealize() now clears that slot too — making the namespace > lifecycle complete. > > Both the controller bus and subsystem bus are configured as hotplug > handlers via qbus_set_bus_hotplug_handler() since nvme-ns devices > may reparent to the subsystem bus during realize. > > Example hot-swap sequence using the NVMe subsystem model: > > # Boot with: -device nvme-subsys,id=subsys0 > # -device nvme,id=ctrl0,subsys=subsys0 > # -device nvme-ns,id=ns0,drive=drv0,bus=ctrl0,nsid=1 > > device_del ns0 # guest receives AEN, removes /dev/nvme0n1 > drive_del drv0 > drive_add 0 file=disk.qcow2,format=qcow2,id=drv0,if=none > device_add nvme-ns,id=ns0,drive=drv0,bus=ctrl0,nsid=1 > # guest receives AEN, adds /dev/nvme0n1 > > Tested with Linux 6.1 guest (NVMe driver processes AEN and rescans > namespace list automatically). > > Signed-off-by: Matthieu <matthieu@min.io> > --- > hw/nvme/ctrl.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ > hw/nvme/ns.c | 8 +++++ > hw/nvme/subsys.c | 2 ++ > 3 files changed, 98 insertions(+) > > diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c > index be6c7028cb..2024b0ff75 100644 > --- a/hw/nvme/ctrl.c > +++ b/hw/nvme/ctrl.c > @@ -206,6 +206,7 @@ > #include "system/hostmem.h" > #include "hw/pci/msix.h" > #include "hw/pci/pcie_sriov.h" > +#include "hw/core/qdev.h" > #include "system/spdm-socket.h" > #include "migration/vmstate.h" > > @@ -9293,6 +9294,7 @@ static void nvme_realize(PCIDevice *pci_dev, Error > **errp) > } > > qbus_init(&n->bus, sizeof(NvmeBus), TYPE_NVME_BUS, dev, dev->id); > + qbus_set_bus_hotplug_handler(BUS(&n->bus)); > > if (nvme_init_subsys(n, errp)) { > return; > @@ -9553,10 +9555,96 @@ static const TypeInfo nvme_info = { > }, > }; > > +static void nvme_ns_hot_plug(HotplugHandler *hotplug_dev, DeviceState > *dev, > + Error **errp) > +{ > + NvmeNamespace *ns = NVME_NS(dev); > + NvmeSubsystem *subsys = ns->subsys; > + uint32_t nsid = ns->params.nsid; > + int i; > + > + /* > + * Attach to all started controllers and notify via AEN. > + * Skip controllers that haven't started yet (boot-time realize) — > + * nvme_start_ctrl() will attach namespaces during controller init. > + */ > + for (i = 0; i < NVME_MAX_CONTROLLERS; i++) { > + NvmeCtrl *ctrl = nvme_subsys_ctrl(subsys, i); > + if (!ctrl || !ctrl->qs_created) { > + continue; > + } > + > + if (nvme_csi_supported(ctrl, ns->csi) && !ns->params.detached) { > + nvme_attach_ns(ctrl, ns); > + nvme_update_dsm_limits(ctrl, ns); > + > + if (!test_and_set_bit(nsid, ctrl->changed_nsids)) { > + nvme_enqueue_event(ctrl, NVME_AER_TYPE_NOTICE, > + NVME_AER_INFO_NOTICE_NS_ATTR_CHANGED, > + NVME_LOG_CHANGED_NSLIST); > + } > + } > + } > +} > + > +static void nvme_ns_hot_unplug(HotplugHandler *hotplug_dev, DeviceState > *dev, > + Error **errp) > +{ > + NvmeNamespace *ns = NVME_NS(dev); > + NvmeSubsystem *subsys = ns->subsys; > + uint32_t nsid = ns->params.nsid; > + int i; > + > + /* > + * Drain in-flight I/O before tearing down the namespace. > + * This must happen while the namespace is still attached to the > + * controllers so any pending requests can complete normally. > + */ > + nvme_ns_drain(ns); > + > + /* > + * Detach from all controllers and notify the guest via AEN. > + * The guest kernel will rescan namespaces and remove the block > device. > + */ > + for (i = 0; i < NVME_MAX_CONTROLLERS; i++) { > + NvmeCtrl *ctrl = nvme_subsys_ctrl(subsys, i); > + if (!ctrl || !nvme_ns(ctrl, nsid)) { > + continue; > + } > + > + nvme_detach_ns(ctrl, ns); > + nvme_update_dsm_limits(ctrl, NULL); > + > + if (!test_and_set_bit(nsid, ctrl->changed_nsids)) { > + nvme_enqueue_event(ctrl, NVME_AER_TYPE_NOTICE, > + NVME_AER_INFO_NOTICE_NS_ATTR_CHANGED, > + NVME_LOG_CHANGED_NSLIST); > + } > + } > + > + /* > + * Unrealize: removes from subsystem (in nvme_ns_unrealize), flushes, > + * cleans up structures, and removes from QOM. > + */ > + qdev_unrealize(dev); > +} > + > +static void nvme_bus_class_init(ObjectClass *klass, const void *data) > +{ > + HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); > + hc->plug = nvme_ns_hot_plug; > + hc->unplug = nvme_ns_hot_unplug; > +} > + > static const TypeInfo nvme_bus_info = { > .name = TYPE_NVME_BUS, > .parent = TYPE_BUS, > .instance_size = sizeof(NvmeBus), > + .class_init = nvme_bus_class_init, > + .interfaces = (const InterfaceInfo[]) { > + { TYPE_HOTPLUG_HANDLER }, > + { } > + }, > }; > > static void nvme_register_types(void) > diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c > index b0106eaa5c..f4f755c6fc 100644 > --- a/hw/nvme/ns.c > +++ b/hw/nvme/ns.c > @@ -719,10 +719,17 @@ void nvme_ns_cleanup(NvmeNamespace *ns) > static void nvme_ns_unrealize(DeviceState *dev) > { > NvmeNamespace *ns = NVME_NS(dev); > + NvmeSubsystem *subsys = ns->subsys; > + uint32_t nsid = ns->params.nsid; > > nvme_ns_drain(ns); > nvme_ns_shutdown(ns); > nvme_ns_cleanup(ns); > + > + /* Symmetric with nvme_ns_realize() which sets > subsys->namespaces[nsid]. */ > + if (subsys && nsid && subsys->namespaces[nsid] == ns) { > + subsys->namespaces[nsid] = NULL; > + } > } > > void nvme_ns_atomic_configure_boundary(bool dn, uint16_t nabsn, > @@ -937,6 +944,7 @@ static void nvme_ns_class_init(ObjectClass *oc, const > void *data) > dc->bus_type = TYPE_NVME_BUS; > dc->realize = nvme_ns_realize; > dc->unrealize = nvme_ns_unrealize; > + dc->hotpluggable = true; > device_class_set_props(dc, nvme_ns_props); > dc->desc = "Virtual NVMe namespace"; > } > diff --git a/hw/nvme/subsys.c b/hw/nvme/subsys.c > index 777e1c620f..fa35055d3c 100644 > --- a/hw/nvme/subsys.c > +++ b/hw/nvme/subsys.c > @@ -9,6 +9,7 @@ > #include "qemu/osdep.h" > #include "qemu/units.h" > #include "qapi/error.h" > +#include "hw/core/qdev.h" > > #include "nvme.h" > > @@ -205,6 +206,7 @@ static void nvme_subsys_realize(DeviceState *dev, > Error **errp) > NvmeSubsystem *subsys = NVME_SUBSYS(dev); > > qbus_init(&subsys->bus, sizeof(NvmeBus), TYPE_NVME_BUS, dev, dev->id); > + qbus_set_bus_hotplug_handler(BUS(&subsys->bus)); > > nvme_subsys_setup(subsys, errp); > } > -- > 2.53.0 > > [-- Attachment #2: Type: text/html, Size: 13689 bytes --] ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v3] hw/nvme: add namespace hotplug support 2026-04-10 14:33 ` Matthieu Rolla @ 2026-04-10 20:14 ` Stefan Hajnoczi 2026-04-13 15:24 ` Matthieu Rolla 0 siblings, 1 reply; 5+ messages in thread From: Stefan Hajnoczi @ 2026-04-10 20:14 UTC (permalink / raw) To: Matthieu Rolla; +Cc: qemu-devel, qemu-block, its, kbusch, mr-083 [-- Attachment #1: Type: text/plain, Size: 1067 bytes --] On Fri, Apr 10, 2026 at 04:33:47PM +0200, Matthieu Rolla wrote: > Hello @Stefan Hajnoczi <stefanha@redhat.com> , > > > Thanks for the review! v3 sent. > > > Wording: Fixed in v3, no more "physical PCIe slot" claim. Now describes it > as NVMe namespace-level hotplug. > > > I/O drain: Moved nvme_ns_drain() to the start of the unplug handler so > in-flight I/O completes before detach. Tested under warp load (16 > concurrent 1MiB uploads via MinIO/DirectPV) device_del returns in ~400ms > with clean removal, no use-after-free. > > > Symmetry: moved subsys->namespaces[nsid] = NULL into nvme_ns_unrealize() > so the namespace lifecycle is complete (mirrors what nvme_ns_realize() sets > up). > > > I don't have a working Windows test setup, I'd really appreciate if you > could test it next week as you offered. > > Thanks again for your time Awesome, thanks! I will give Windows Server a spin next week. I'm not an expert in hw/nvme/ but the patch looks good to me: Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v3] hw/nvme: add namespace hotplug support 2026-04-10 20:14 ` Stefan Hajnoczi @ 2026-04-13 15:24 ` Matthieu Rolla 0 siblings, 0 replies; 5+ messages in thread From: Matthieu Rolla @ 2026-04-13 15:24 UTC (permalink / raw) To: Stefan Hajnoczi; +Cc: qemu-devel, qemu-block, its, kbusch, mr-083 [-- Attachment #1: Type: text/plain, Size: 2349 bytes --] Hello, I tested further more the device_del + device_add and the AEN works correctly, causing the guest to rescan namespaces. However, when XFS filesystems are mounted on the namespace (via DirectPV/CSI in our case), the kernel doesn't reuse the block device number after re-add. For example, nvme2n1 becomes nvme2n2 because the stale XFS mount holds a reference to the old nvme_ns_head, preventing ida_free() in nvme_free_ns_head() from releasing the instance number before the new namespace is allocated. This causes XFS "duplicate UUID" errors since the same filesystem appears under a different device name while the old stale mount still exists. This is a Linux kernel behavior (ida_alloc in nvme_alloc_ns_head), not a QEMU issue. The namespace hotplug patch itself is correct. But for practical use with mounted filesystems, I found that the drive_del + drive_insert approach (keeping the namespace device alive) avoids the rename entirely since no ida allocation/free cycle occurs. Would it make sense to include drive_insert as a companion patch, or is that better handled separately ? Thanks On Fri, Apr 10, 2026 at 10:14 PM Stefan Hajnoczi <stefanha@redhat.com> wrote: > On Fri, Apr 10, 2026 at 04:33:47PM +0200, Matthieu Rolla wrote: > > Hello @Stefan Hajnoczi <stefanha@redhat.com> , > > > > > > Thanks for the review! v3 sent. > > > > > > Wording: Fixed in v3, no more "physical PCIe slot" claim. Now describes > it > > as NVMe namespace-level hotplug. > > > > > > I/O drain: Moved nvme_ns_drain() to the start of the unplug handler so > > in-flight I/O completes before detach. Tested under warp load (16 > > concurrent 1MiB uploads via MinIO/DirectPV) device_del returns in ~400ms > > with clean removal, no use-after-free. > > > > > > Symmetry: moved subsys->namespaces[nsid] = NULL into nvme_ns_unrealize() > > so the namespace lifecycle is complete (mirrors what nvme_ns_realize() > sets > > up). > > > > > > I don't have a working Windows test setup, I'd really appreciate if you > > could test it next week as you offered. > > > > Thanks again for your time > > Awesome, thanks! > > I will give Windows Server a spin next week. I'm not an expert in > hw/nvme/ but the patch looks good to me: > > Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> > [-- Attachment #2: Type: text/html, Size: 2975 bytes --] ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-04-13 17:19 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <CAPSO8MwceccK3gHgbeZi0A9=p8B9VV85whYmN1D343gV=9PucA@mail.gmail.com>
2026-04-13 17:18 ` [PATCH v3] hw/nvme: add namespace hotplug support Stefan Hajnoczi
2026-04-09 6:01 [PATCH 0/2] NVMe namespace hotplug and drive reconnection support mr-083
2026-04-10 14:30 ` [PATCH v3] hw/nvme: add namespace hotplug support mr-083
2026-04-10 14:33 ` Matthieu Rolla
2026-04-10 20:14 ` Stefan Hajnoczi
2026-04-13 15:24 ` Matthieu Rolla
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.