aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/block/nvme.c19
-rw-r--r--hw/block/nvme.h1
2 files changed, 17 insertions, 3 deletions
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index c6a6a0e49a..dc9caf07fe 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -207,11 +207,23 @@ static void nvme_rw_cb(void *opaque, int ret)
} else {
req->status = NVME_INTERNAL_DEV_ERROR;
}
-
- qemu_sglist_destroy(&req->qsg);
+ if (req->has_sg) {
+ qemu_sglist_destroy(&req->qsg);
+ }
nvme_enqueue_req_completion(cq, req);
}
+static uint16_t nvme_flush(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
+ NvmeRequest *req)
+{
+ req->has_sg = false;
+ block_acct_start(blk_get_stats(n->conf.blk), &req->acct, 0,
+ BLOCK_ACCT_FLUSH);
+ req->aiocb = blk_aio_flush(n->conf.blk, nvme_rw_cb, req);
+
+ return NVME_NO_COMPLETE;
+}
+
static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
NvmeRequest *req)
{
@@ -235,6 +247,7 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
}
assert((nlb << data_shift) == req->qsg.size);
+ req->has_sg = true;
dma_acct_start(n->conf.blk, &req->acct, &req->qsg,
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
req->aiocb = is_write ?
@@ -256,7 +269,7 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd *cmd, NvmeRequest *req)
ns = &n->namespaces[nsid - 1];
switch (cmd->opcode) {
case NVME_CMD_FLUSH:
- return NVME_SUCCESS;
+ return nvme_flush(n, ns, cmd, req);
case NVME_CMD_WRITE:
case NVME_CMD_READ:
return nvme_rw(n, ns, cmd, req);
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
index b6ccb655a6..bf3a3ccac8 100644
--- a/hw/block/nvme.h
+++ b/hw/block/nvme.h
@@ -638,6 +638,7 @@ typedef struct NvmeRequest {
struct NvmeSQueue *sq;
BlockAIOCB *aiocb;
uint16_t status;
+ bool has_sg;
NvmeCqe cqe;
BlockAcctCookie acct;
QEMUSGList qsg;