[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH RFC 1/4] hw/block/nvme: convert dsm to aiocb
From: |
Klaus Jensen |
Subject: |
[PATCH RFC 1/4] hw/block/nvme: convert dsm to aiocb |
Date: |
Tue, 2 Mar 2021 12:10:37 +0100 |
From: Klaus Jensen <k.jensen@samsung.com>
Convert dataset management from ad-hoc multi aio tracking to use
standard QEMU AIOCB processing.
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
---
hw/block/nvme.c | 187 ++++++++++++++++++++++++++++--------------
hw/block/trace-events | 2 +-
2 files changed, 125 insertions(+), 64 deletions(-)
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 54c87c8f5fe3..8830d72b959f 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -1494,23 +1494,16 @@ static void nvme_aio_flush_cb(void *opaque, int ret)
nvme_enqueue_req_completion(nvme_cq(req), req);
}
-static void nvme_aio_discard_cb(void *opaque, int ret)
+static void nvme_misc_cb(void *opaque, int ret)
{
NvmeRequest *req = opaque;
- uintptr_t *discards = (uintptr_t *)&req->opaque;
- trace_pci_nvme_aio_discard_cb(nvme_cid(req));
+ trace_pci_nvme_misc_cb(nvme_cid(req));
if (ret) {
nvme_aio_err(req, ret);
}
- (*discards)--;
-
- if (*discards) {
- return;
- }
-
nvme_enqueue_req_completion(nvme_cq(req), req);
}
@@ -1736,78 +1729,146 @@ out:
nvme_enqueue_req_completion(nvme_cq(req), req);
}
+typedef struct NvmeDSMAIOCB {
+ BlockAIOCB common;
+ BlockAIOCB *aiocb;
+ NvmeRequest *req;
+ QEMUBH *bh;
+ int ret;
+
+ NvmeDsmRange *range;
+ int nr;
+ struct {
+ int64_t offset;
+ size_t len;
+ int idx;
+ } curr;
+} NvmeDSMAIOCB;
+
+static void nvme_dsm_cancel(BlockAIOCB *aiocb)
+{
+ NvmeDSMAIOCB *iocb = container_of(aiocb, NvmeDSMAIOCB, common);
+
+ /* break loop */
+ iocb->curr.len = 0;
+ iocb->curr.idx = iocb->nr;
+
+ iocb->ret = -ECANCELED;
+
+ if (iocb->aiocb) {
+ blk_aio_cancel_async(iocb->aiocb);
+ iocb->aiocb = NULL;
+ }
+}
+
+static const AIOCBInfo nvme_dsm_aiocb_info = {
+ .aiocb_size = sizeof(NvmeDSMAIOCB),
+ .cancel_async = nvme_dsm_cancel,
+};
+
+static void nvme_dsm_bh(void *opaque)
+{
+ NvmeDSMAIOCB *iocb = opaque;
+
+ iocb->common.cb(iocb->common.opaque, iocb->ret);
+
+ qemu_bh_delete(iocb->bh);
+ iocb->bh = NULL;
+ qemu_aio_unref(iocb);
+}
+
+static void nvme_dsm_aio_cb(void *opaque, int ret)
+{
+ NvmeDSMAIOCB *iocb = opaque;
+ NvmeRequest *req = iocb->req;
+ NvmeCtrl *n = nvme_ctrl(req);
+ NvmeNamespace *ns = req->ns;
+ NvmeDsmRange *range;
+ uint64_t slba;
+ uint32_t nlb;
+ size_t bytes;
+
+ if (ret < 0) {
+ iocb->ret = ret;
+ goto done;
+ }
+
+ if (iocb->curr.len == 0) {
+next:
+ if (iocb->curr.idx == iocb->nr) {
+ goto done;
+ }
+
+ range = &iocb->range[iocb->curr.idx++];
+ slba = le64_to_cpu(range->slba);
+ nlb = le32_to_cpu(range->nlb);
+
+ trace_pci_nvme_dsm_deallocate(nvme_cid(req), nvme_nsid(ns), slba,
+ nlb);
+
+ if (nlb > n->dmrsl) {
+ trace_pci_nvme_dsm_single_range_limit_exceeded(nlb, n->dmrsl);
+ }
+
+ if (nvme_check_bounds(ns, slba, nlb)) {
+ trace_pci_nvme_err_invalid_lba_range(slba, nlb,
+ ns->id_ns.nsze);
+ goto next;
+ }
+
+ iocb->curr.offset = nvme_l2b(ns, slba);
+ iocb->curr.len = nvme_l2b(ns, nlb);
+ }
+
+ bytes = MIN(BDRV_REQUEST_MAX_BYTES, iocb->curr.len);
+
+ iocb->aiocb = blk_aio_pdiscard(ns->blkconf.blk, iocb->curr.offset, bytes,
+ nvme_dsm_aio_cb, iocb);
+
+ iocb->curr.offset += bytes;
+ iocb->curr.len -= bytes;
+
+ return;
+
+done:
+ iocb->aiocb = NULL;
+ if (iocb->bh) {
+ qemu_bh_schedule(iocb->bh);
+ }
+}
+
static uint16_t nvme_dsm(NvmeCtrl *n, NvmeRequest *req)
{
NvmeNamespace *ns = req->ns;
NvmeDsmCmd *dsm = (NvmeDsmCmd *) &req->cmd;
-
uint32_t attr = le32_to_cpu(dsm->attributes);
uint32_t nr = (le32_to_cpu(dsm->nr) & 0xff) + 1;
-
uint16_t status = NVME_SUCCESS;
trace_pci_nvme_dsm(nvme_cid(req), nvme_nsid(ns), nr, attr);
if (attr & NVME_DSMGMT_AD) {
- int64_t offset;
- size_t len;
- NvmeDsmRange range[nr];
- uintptr_t *discards = (uintptr_t *)&req->opaque;
+ NvmeDSMAIOCB *iocb = blk_aio_get(&nvme_dsm_aiocb_info, ns->blkconf.blk,
+ nvme_misc_cb, req);
- status = nvme_dma(n, (uint8_t *)range, sizeof(range),
+ iocb->req = req;
+ iocb->bh = qemu_bh_new(nvme_dsm_bh, iocb);
+ iocb->ret = 0;
+ iocb->range = g_new(NvmeDsmRange, nr);
+ iocb->nr = nr;
+ iocb->curr.len = 0;
+ iocb->curr.idx = 0;
+
+ status = nvme_dma(n, (uint8_t *)iocb->range, sizeof(NvmeDsmRange) * nr,
DMA_DIRECTION_TO_DEVICE, req);
if (status) {
return status;
}
- /*
- * AIO callbacks may be called immediately, so initialize discards to 1
- * to make sure the the callback does not complete the request before
- * all discards have been issued.
- */
- *discards = 1;
+ nvme_dsm_aio_cb(iocb, 0);
+ req->aiocb = &iocb->common;
- for (int i = 0; i < nr; i++) {
- uint64_t slba = le64_to_cpu(range[i].slba);
- uint32_t nlb = le32_to_cpu(range[i].nlb);
-
- if (nvme_check_bounds(ns, slba, nlb)) {
- trace_pci_nvme_err_invalid_lba_range(slba, nlb,
- ns->id_ns.nsze);
- continue;
- }
-
- trace_pci_nvme_dsm_deallocate(nvme_cid(req), nvme_nsid(ns), slba,
- nlb);
-
- if (nlb > n->dmrsl) {
- trace_pci_nvme_dsm_single_range_limit_exceeded(nlb, n->dmrsl);
- }
-
- offset = nvme_l2b(ns, slba);
- len = nvme_l2b(ns, nlb);
-
- while (len) {
- size_t bytes = MIN(BDRV_REQUEST_MAX_BYTES, len);
-
- (*discards)++;
-
- blk_aio_pdiscard(ns->blkconf.blk, offset, bytes,
- nvme_aio_discard_cb, req);
-
- offset += bytes;
- len -= bytes;
- }
- }
-
- /* account for the 1-initialization */
- (*discards)--;
-
- if (*discards) {
- status = NVME_NO_COMPLETE;
- } else {
- status = req->status;
- }
+ return NVME_NO_COMPLETE;
}
return status;
diff --git a/hw/block/trace-events b/hw/block/trace-events
index 8deeacc8c35c..0e5bddbdd48b 100644
--- a/hw/block/trace-events
+++ b/hw/block/trace-events
@@ -54,7 +54,7 @@ pci_nvme_dsm_deallocate(uint16_t cid, uint32_t nsid, uint64_t
slba, uint32_t nlb
pci_nvme_dsm_single_range_limit_exceeded(uint32_t nlb, uint32_t dmrsl) "nlb
%"PRIu32" dmrsl %"PRIu32""
pci_nvme_compare(uint16_t cid, uint32_t nsid, uint64_t slba, uint32_t nlb)
"cid %"PRIu16" nsid %"PRIu32" slba 0x%"PRIx64" nlb %"PRIu32""
pci_nvme_compare_cb(uint16_t cid) "cid %"PRIu16""
-pci_nvme_aio_discard_cb(uint16_t cid) "cid %"PRIu16""
+pci_nvme_misc_cb(uint16_t cid) "cid %"PRIu16""
pci_nvme_aio_copy_in_cb(uint16_t cid) "cid %"PRIu16""
pci_nvme_aio_zone_reset_cb(uint16_t cid, uint64_t zslba) "cid %"PRIu16" zslba
0x%"PRIx64""
pci_nvme_aio_flush_cb(uint16_t cid, const char *blkname) "cid %"PRIu16" blk
'%s'"
--
2.30.1
[PATCH RFC 4/4] hw/block/nvme: convert zone reset to aiocb, Klaus Jensen, 2021/03/02
Re: [PATCH RFC 0/4] hw/block/nvme: convert ad-hoc aio tracking to aiocbs, Stefan Hajnoczi, 2021/03/08