[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Stable-8.2.8 48/49] hw/nvme: fix handling of over-committed queues
From: |
Michael Tokarev |
Subject: |
[Stable-8.2.8 48/49] hw/nvme: fix handling of over-committed queues |
Date: |
Sat, 9 Nov 2024 13:14:39 +0300 |
From: Klaus Jensen <k.jensen@samsung.com>
If a host chooses to use the SQHD "hint" in the CQE to know if there is
room in the submission queue for additional commands, it may result in a
situation where there are not enough internal resources (struct
NvmeRequest) available to process the command. For a lack of a better
term, the host may "over-commit" the device (i.e., it may have more
inflight commands than the queue size).
For example, assume a queue with N entries. The host submits N commands
and all are picked up for processing, advancing the head and emptying
the queue. Regardless of which of these N commands complete first, the
SQHD field of that CQE will indicate to the host that the queue is
empty, which allows the host to issue N commands again. However, if the
device has not posted CQEs for all the previous commands yet, the device
will have less than N resources available to process the commands, so
queue processing is suspended.
And here lies an 11 year latent bug. In the absense of any additional
tail updates on the submission queue, we never schedule the processing
bottom-half again unless we observe a head update on an associated full
completion queue. This has been sufficient to handle N-to-1 SQ/CQ setups
(in the absense of over-commit of course). Incidentially, that "kick all
associated SQs" mechanism can now be killed since we now just schedule
queue processing when we return a processing resource to a non-empty
submission queue, which happens to cover both edge cases. However, we
must retain kicking the CQ if it was previously full.
So, apparently, no previous driver tested with hw/nvme has ever used
SQHD (e.g., neither the Linux NVMe driver or SPDK uses it). But then OSv
shows up with the driver that actually does. I salute you.
Fixes: f3c507adcd7b ("NVMe: Initial commit for new storage interface")
Cc: qemu-stable@nongnu.org
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2388
Reported-by: Waldemar Kozaczuk <jwkozaczuk@gmail.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
(cherry picked from commit 9529aa6bb4d18763f5b4704cb4198bd25cbbee31)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c
index ca54c250b2..359313dbcb 100644
--- a/hw/nvme/ctrl.c
+++ b/hw/nvme/ctrl.c
@@ -1516,9 +1516,16 @@ static void nvme_post_cqes(void *opaque)
stl_le_p(&n->bar.csts, NVME_CSTS_FAILED);
break;
}
+
QTAILQ_REMOVE(&cq->req_list, req, entry);
+
nvme_inc_cq_tail(cq);
nvme_sg_unmap(&req->sg);
+
+ if (QTAILQ_EMPTY(&sq->req_list) && !nvme_sq_empty(sq)) {
+ qemu_bh_schedule(sq->bh);
+ }
+
QTAILQ_INSERT_TAIL(&sq->req_list, req, entry);
}
if (cq->tail != cq->head) {
@@ -7575,7 +7582,6 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr, int
val)
/* Completion queue doorbell write */
uint16_t new_head = val & 0xffff;
- int start_sqs;
NvmeCQueue *cq;
qid = (addr - (0x1000 + (1 << 2))) >> 3;
@@ -7626,18 +7632,15 @@ static void nvme_process_db(NvmeCtrl *n, hwaddr addr,
int val)
trace_pci_nvme_mmio_doorbell_cq(cq->cqid, new_head);
- start_sqs = nvme_cq_full(cq) ? 1 : 0;
+ /* scheduled deferred cqe posting if queue was previously full */
+ if (nvme_cq_full(cq)) {
+ qemu_bh_schedule(cq->bh);
+ }
+
cq->head = new_head;
if (!qid && n->dbbuf_enabled) {
stl_le_pci_dma(pci, cq->db_addr, cq->head, MEMTXATTRS_UNSPECIFIED);
}
- if (start_sqs) {
- NvmeSQueue *sq;
- QTAILQ_FOREACH(sq, &cq->sq_list, entry) {
- qemu_bh_schedule(sq->bh);
- }
- qemu_bh_schedule(cq->bh);
- }
if (cq->tail == cq->head) {
if (cq->irq_enabled) {
--
2.39.5
- [Stable-8.2.8 34/49] target/arm: Fix arithmetic underflow in SETM instruction, (continued)
- [Stable-8.2.8 34/49] target/arm: Fix arithmetic underflow in SETM instruction, Michael Tokarev, 2024/11/09
- [Stable-8.2.8 31/49] net: fix build when libbpf is disabled, but libxdp is enabled, Michael Tokarev, 2024/11/09
- [Stable-8.2.8 36/49] target/riscv: Correct SXL return value for RV32 in RV64 QEMU, Michael Tokarev, 2024/11/09
- [Stable-8.2.8 40/49] hw/intc/riscv_aplic: Check and update pending when write sourcecfg, Michael Tokarev, 2024/11/09
- [Stable-8.2.8 39/49] hw/intc/riscv_aplic: Fix in_clrip[x] read emulation, Michael Tokarev, 2024/11/09
- [Stable-8.2.8 37/49] hw/intc: Don't clear pending bits on IRQ lowering, Michael Tokarev, 2024/11/09
- [Stable-8.2.8 47/49] migration: Ensure vmstate_save() sets errp, Michael Tokarev, 2024/11/09
- [Stable-8.2.8 29/49] dockerfiles: fix default targets for debian-loongarch-cross, Michael Tokarev, 2024/11/09
- [Stable-8.2.8 42/49] target/riscv/kvm: clarify how 'riscv-aia' default works, Michael Tokarev, 2024/11/09
- [Stable-8.2.8 46/49] target/arm: Fix SVE SDOT/UDOT/USDOT (4-way, indexed), Michael Tokarev, 2024/11/09
- [Stable-8.2.8 48/49] hw/nvme: fix handling of over-committed queues,
Michael Tokarev <=
- [Stable-8.2.8 49/49] 9pfs: fix crash on 'Treaddir' request, Michael Tokarev, 2024/11/09
- [Stable-8.2.8 41/49] target/riscv/kvm: set 'aia_mode' to default in error path, Michael Tokarev, 2024/11/09
- [Stable-8.2.8 44/49] target/ppc: Set ctx->opcode for decode_insn32(), Michael Tokarev, 2024/11/09
- [Stable-8.2.8 43/49] target/riscv: Fix vcompress with rvv_ta_all_1s, Michael Tokarev, 2024/11/09
- [Stable-8.2.8 45/49] target/ppc: Fix mtDPDES targeting SMT siblings, Michael Tokarev, 2024/11/09