On May 17 17:52, Changqi Lu wrote: > Add reservation acquire, reservation register, > reservation release and reservation report commands > in the nvme device layer. > > By introducing these commands, this enables the nvme > device to perform reservation-related tasks, including > querying keys, querying reservation status, registering > reservation keys, initiating and releasing reservations, > as well as clearing and preempting reservations held by > other keys. > > These commands are crucial for management and control of > shared storage resources in a persistent manner. > > Signed-off-by: Changqi Lu <luchangqi....@bytedance.com> > Signed-off-by: zhenwei pi <pizhen...@bytedance.com> > --- > hw/nvme/ctrl.c | 321 ++++++++++++++++++++++++++++++++++++++++++- > hw/nvme/nvme.h | 4 + > include/block/nvme.h | 38 +++++ > 3 files changed, 362 insertions(+), 1 deletion(-) > > diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c > index 182307a48b..ac2fbd22ec 100644 > --- a/hw/nvme/ctrl.c > +++ b/hw/nvme/ctrl.c > @@ -294,6 +294,10 @@ static const uint32_t nvme_cse_iocs_nvm[256] = { > [NVME_CMD_COMPARE] = NVME_CMD_EFF_CSUPP, > [NVME_CMD_IO_MGMT_RECV] = NVME_CMD_EFF_CSUPP, > [NVME_CMD_IO_MGMT_SEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, > + [NVME_CMD_RESV_REGISTER] = NVME_CMD_EFF_CSUPP, > + [NVME_CMD_RESV_REPORT] = NVME_CMD_EFF_CSUPP, > + [NVME_CMD_RESV_ACQUIRE] = NVME_CMD_EFF_CSUPP, > + [NVME_CMD_RESV_RELEASE] = NVME_CMD_EFF_CSUPP, > }; > > static const uint32_t nvme_cse_iocs_zoned[256] = { > @@ -308,6 +312,10 @@ static const uint32_t nvme_cse_iocs_zoned[256] = { > [NVME_CMD_ZONE_APPEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, > [NVME_CMD_ZONE_MGMT_SEND] = NVME_CMD_EFF_CSUPP | NVME_CMD_EFF_LBCC, > [NVME_CMD_ZONE_MGMT_RECV] = NVME_CMD_EFF_CSUPP, > + [NVME_CMD_RESV_REGISTER] = NVME_CMD_EFF_CSUPP, > + [NVME_CMD_RESV_REPORT] = NVME_CMD_EFF_CSUPP, > + [NVME_CMD_RESV_ACQUIRE] = NVME_CMD_EFF_CSUPP, > + [NVME_CMD_RESV_RELEASE] = NVME_CMD_EFF_CSUPP, > }; > > static void nvme_process_sq(void *opaque); > @@ -1745,6 +1753,7 @@ static void nvme_aio_err(NvmeRequest *req, int ret) > > switch (req->cmd.opcode) { > case NVME_CMD_READ: > + case NVME_CMD_RESV_REPORT: > status = NVME_UNRECOVERED_READ; > break; > case NVME_CMD_FLUSH: > @@ -1752,6 +1761,9 @@ static void nvme_aio_err(NvmeRequest *req, int ret) > case NVME_CMD_WRITE_ZEROES: > case NVME_CMD_ZONE_APPEND: > case NVME_CMD_COPY: > + case NVME_CMD_RESV_REGISTER: > + case NVME_CMD_RESV_ACQUIRE: > + case NVME_CMD_RESV_RELEASE: > status = NVME_WRITE_FAULT; > break; > default: > @@ -2127,7 +2139,10 @@ static inline bool nvme_is_write(NvmeRequest *req) > > return rw->opcode == NVME_CMD_WRITE || > rw->opcode == NVME_CMD_ZONE_APPEND || > - rw->opcode == NVME_CMD_WRITE_ZEROES; > + rw->opcode == NVME_CMD_WRITE_ZEROES || > + rw->opcode == NVME_CMD_RESV_REGISTER || > + rw->opcode == NVME_CMD_RESV_ACQUIRE || > + rw->opcode == NVME_CMD_RESV_RELEASE; > } > > static void nvme_misc_cb(void *opaque, int ret) > @@ -2692,6 +2707,302 @@ static uint16_t nvme_verify(NvmeCtrl *n, NvmeRequest > *req) > return NVME_NO_COMPLETE; > } > > +typedef struct NvmeKeyInfo { > + uint64_t cr_key; > + uint64_t nr_key; > +} NvmeKeyInfo; > + > +static uint16_t nvme_resv_register(NvmeCtrl *n, NvmeRequest *req) > +{ > + int ret; > + NvmeKeyInfo key_info; > + NvmeNamespace *ns = req->ns; > + uint32_t cdw10 = le32_to_cpu(req->cmd.cdw10); > + bool ignore_key = cdw10 >> 3 & 0x1; > + uint8_t action = cdw10 & 0x7; > + uint8_t ptpl = cdw10 >> 30 & 0x3; > + bool aptpl; > + > + switch (ptpl) { > + case NVME_RESV_PTPL_NO_CHANGE: > + aptpl = (ns->id_ns.rescap & NVME_PR_CAP_PTPL) ? true : false; > + break; > + case NVME_RESV_PTPL_DISABLE: > + aptpl = false; > + break; > + case NVME_RESV_PTPL_ENABLE: > + aptpl = true; > + break; > + default: > + return NVME_INVALID_FIELD; > + } > + > + ret = nvme_h2c(n, (uint8_t *)&key_info, sizeof(NvmeKeyInfo), req); > + if (ret) { > + return ret; > + } > + > + switch (action) { > + case NVME_RESV_REGISTER_ACTION_REGISTER: > + req->aiocb = blk_aio_pr_register(ns->blkconf.blk, 0, > + key_info.nr_key, 0, aptpl, > + ignore_key, nvme_misc_cb, > + req); > + break; > + case NVME_RESV_REGISTER_ACTION_UNREGISTER: > + req->aiocb = blk_aio_pr_register(ns->blkconf.blk, key_info.cr_key, 0, > + 0, aptpl, ignore_key, > + nvme_misc_cb, req); > + break; > + case NVME_RESV_REGISTER_ACTION_REPLACE: > + req->aiocb = blk_aio_pr_register(ns->blkconf.blk, key_info.cr_key, > + key_info.nr_key, 0, aptpl, > ignore_key, > + nvme_misc_cb, req); > + break; > + default: > + return NVME_INVALID_FIELD; > + } > + > + return NVME_NO_COMPLETE; > +} > + > +static uint16_t nvme_resv_release(NvmeCtrl *n, NvmeRequest *req) > +{ > + int ret; > + uint64_t cr_key; > + NvmeNamespace *ns = req->ns; > + uint32_t cdw10 = le32_to_cpu(req->cmd.cdw10); > + uint8_t action = cdw10 & 0x7; > + NVMEResvType type = cdw10 >> 8 & 0xff; > + > + ret = nvme_h2c(n, (uint8_t *)&cr_key, sizeof(cr_key), req); > + if (ret) { > + return ret; > + } > + > + switch (action) { > + case NVME_RESV_RELEASE_ACTION_RELEASE: > + req->aiocb = blk_aio_pr_release(ns->blkconf.blk, cr_key, > + nvme_pr_type_to_block(type), > + nvme_misc_cb, req); > + break; > + case NVME_RESV_RELEASE_ACTION_CLEAR: > + req->aiocb = blk_aio_pr_clear(ns->blkconf.blk, cr_key, > + nvme_misc_cb, req); > + break; > + default: > + return NVME_INVALID_FIELD; > + } > + > + return NVME_NO_COMPLETE; > +} > + > +static uint16_t nvme_resv_acquire(NvmeCtrl *n, NvmeRequest *req) > +{ > + int ret; > + NvmeKeyInfo key_info; > + NvmeNamespace *ns = req->ns; > + uint32_t cdw10 = le32_to_cpu(req->cmd.cdw10); > + uint8_t action = cdw10 & 0x7; > + NVMEResvType type = cdw10 >> 8 & 0xff; > + > + ret = nvme_h2c(n, (uint8_t *)&key_info, sizeof(NvmeKeyInfo), req); > + if (ret) { > + return ret; > + } > + > + switch (action) { > + case NVME_RESV_ACQUIRE_ACTION_ACQUIRE: > + req->aiocb = blk_aio_pr_reserve(ns->blkconf.blk, key_info.cr_key, > + nvme_pr_type_to_block(type), > + nvme_misc_cb, req); > + break; > + case NVME_RESV_ACQUIRE_ACTION_PREEMPT: > + req->aiocb = blk_aio_pr_preempt(ns->blkconf.blk, > + key_info.cr_key, key_info.nr_key, > + nvme_pr_type_to_block(type), > + false, nvme_misc_cb, req); > + break; > + case NVME_RESV_ACQUIRE_ACTION_PREEMPT_AND_ABORT: > + req->aiocb = blk_aio_pr_preempt(ns->blkconf.blk, key_info.cr_key, > + key_info.nr_key, type, true, > + nvme_misc_cb, req); > + break; > + default: > + return NVME_INVALID_FIELD; > + } > + > + return NVME_NO_COMPLETE; > +} > + > +typedef struct NvmeResvKeys { > + uint32_t generation; > + uint32_t num_keys; > + uint64_t *keys; > + NvmeRequest *req; > +} NvmeResvKeys; > + > +typedef struct NvmeReadReservation { > + uint32_t generation; > + uint64_t key; > + BlockPrType type; > + NvmeRequest *req; > + NvmeResvKeys *keys_info; > +} NvmeReadReservation; > + > +static int _nvme_resv_read_reservation_cb(NvmeReadReservation *reservation)
Nit: you can drop the leading underscore. But I have no problems introducing this to hw/nvme, so Acked-by: Klaus Jensen <k.jen...@samsung.com> I will give this a proper review once reviews trickle in on the core block layer changes (since this obviously depends on that).
signature.asc
Description: PGP signature