nvmf: verify each NVMe commands for reservation enabled's NS

The filter function can be used for IO commands, because all
the Admin commands related with reservations are not supported
in SPDK for now.

Change-Id: I44f0bf0017bafaee87d5f8ac03b0fd368f44c810
Signed-off-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/436941
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
This commit is contained in:
Changpeng Liu 2019-03-01 01:21:47 -05:00
parent a9fc7e1db8
commit ca76e519f8

View File

@ -2075,6 +2075,106 @@ spdk_nvmf_ctrlr_abort_aer(struct spdk_nvmf_ctrlr *ctrlr)
ctrlr->aer_req = NULL;
}
/* Check from subsystem poll group's namespace information data structure */
static bool
nvmf_ns_info_ctrlr_is_registrant(struct spdk_nvmf_subsystem_pg_ns_info *ns_info,
struct spdk_nvmf_ctrlr *ctrlr)
{
uint32_t i;
for (i = 0; i < SPDK_NVMF_MAX_NUM_REGISTRANTS; i++) {
if (!spdk_uuid_compare(&ns_info->reg_hostid[i], &ctrlr->hostid)) {
return true;
}
}
return false;
}
/*
* Check the NVMe command is permitted or not for current controller(Host).
*/
static int
nvmf_ns_reservation_request_check(struct spdk_nvmf_subsystem_pg_ns_info *ns_info,
struct spdk_nvmf_ctrlr *ctrlr,
struct spdk_nvmf_request *req)
{
struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
enum spdk_nvme_reservation_type rtype = ns_info->rtype;
uint8_t status = SPDK_NVME_SC_SUCCESS;
uint8_t racqa;
bool is_registrant;
/* No valid reservation */
if (!rtype) {
return 0;
}
is_registrant = nvmf_ns_info_ctrlr_is_registrant(ns_info, ctrlr);
/* All registrants type and current ctrlr is a valid registrant */
if ((rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS ||
rtype == SPDK_NVME_RESERVE_EXCLUSIVE_ACCESS_ALL_REGS) && is_registrant) {
return 0;
} else if (!spdk_uuid_compare(&ns_info->holder_id, &ctrlr->hostid)) {
return 0;
}
/* Non-holder for current controller */
switch (cmd->opc) {
case SPDK_NVME_OPC_READ:
case SPDK_NVME_OPC_COMPARE:
if (rtype == SPDK_NVME_RESERVE_EXCLUSIVE_ACCESS) {
status = SPDK_NVME_SC_RESERVATION_CONFLICT;
goto exit;
}
if ((rtype == SPDK_NVME_RESERVE_EXCLUSIVE_ACCESS_REG_ONLY ||
rtype == SPDK_NVME_RESERVE_EXCLUSIVE_ACCESS_ALL_REGS) && !is_registrant) {
status = SPDK_NVME_SC_RESERVATION_CONFLICT;
goto exit;
}
break;
case SPDK_NVME_OPC_FLUSH:
case SPDK_NVME_OPC_WRITE:
case SPDK_NVME_OPC_WRITE_UNCORRECTABLE:
case SPDK_NVME_OPC_WRITE_ZEROES:
case SPDK_NVME_OPC_DATASET_MANAGEMENT:
if (rtype == SPDK_NVME_RESERVE_WRITE_EXCLUSIVE ||
rtype == SPDK_NVME_RESERVE_EXCLUSIVE_ACCESS) {
status = SPDK_NVME_SC_RESERVATION_CONFLICT;
goto exit;
}
if (!is_registrant) {
status = SPDK_NVME_SC_RESERVATION_CONFLICT;
goto exit;
}
break;
case SPDK_NVME_OPC_RESERVATION_ACQUIRE:
case SPDK_NVME_OPC_RESERVATION_RELEASE:
racqa = cmd->cdw10 & 0x7u;
if (cmd->opc == SPDK_NVME_OPC_RESERVATION_ACQUIRE &&
racqa == SPDK_NVME_RESERVE_ACQUIRE) {
status = SPDK_NVME_SC_RESERVATION_CONFLICT;
goto exit;
}
if (!is_registrant) {
status = SPDK_NVME_SC_RESERVATION_CONFLICT;
goto exit;
}
break;
default:
break;
}
exit:
req->rsp->nvme_cpl.status.sct = SPDK_NVME_SCT_GENERIC;
req->rsp->nvme_cpl.status.sc = status;
if (status == SPDK_NVME_SC_RESERVATION_CONFLICT) {
return -EPERM;
}
return 0;
}
int
spdk_nvmf_ctrlr_process_io_cmd(struct spdk_nvmf_request *req)
{
@ -2087,6 +2187,7 @@ spdk_nvmf_ctrlr_process_io_cmd(struct spdk_nvmf_request *req)
struct spdk_nvmf_ctrlr *ctrlr = req->qpair->ctrlr;
struct spdk_nvme_cmd *cmd = &req->cmd->nvme_cmd;
struct spdk_nvme_cpl *response = &req->rsp->nvme_cpl;
struct spdk_nvmf_subsystem_pg_ns_info *ns_info;
/* pre-set response details for this command */
response->status.sc = SPDK_NVME_SC_SUCCESS;
@ -2114,9 +2215,15 @@ spdk_nvmf_ctrlr_process_io_cmd(struct spdk_nvmf_request *req)
return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
}
ns_info = &group->sgroups[ctrlr->subsys->id].ns_info[nsid - 1];
if (nvmf_ns_reservation_request_check(ns_info, ctrlr, req)) {
SPDK_NOTICELOG("Reservation Conflict for nsid %u, opcode %u\n", cmd->nsid, cmd->opc);
return SPDK_NVMF_REQUEST_EXEC_STATUS_COMPLETE;
}
bdev = ns->bdev;
desc = ns->desc;
ch = group->sgroups[ctrlr->subsys->id].ns_info[nsid - 1].channel;
ch = ns_info->channel;
switch (cmd->opc) {
case SPDK_NVME_OPC_READ:
return spdk_nvmf_bdev_ctrlr_read_cmd(bdev, desc, ch, req);