Commit 90fcba23c5 for qemu.org

commit 90fcba23c526f3417953429832d0a97be4389fdb
Author: Daniel Paziyski <danielpaziyski@gmail.com>
Date:   Sat Sep 5 14:18:11 2026 +0200

    hw/nvme: fix assertion failure on sr-iov capable nvme controller removal

    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>

diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index 3e8a1c8b77..1047961b03 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 {