scsi: add persistent reservation SCSI commands check
All the SCSI commands have two states: allowed and conflict, based on different reservation types and I_T nexus, the SCSI module will check each commands before sending to the backend device. Change-Id: Ib05cece1c237873360f85c68d139362200d2d47e Signed-off-by: Changpeng Liu <changpeng.liu@intel.com> Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/436097 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
parent
94e9f0ab8b
commit
8c0c8e5333
@ -169,7 +169,14 @@ _scsi_lun_execute_task(struct spdk_scsi_lun *lun, struct spdk_scsi_task *task)
|
||||
spdk_trace_record(TRACE_SCSI_TASK_START, lun->dev->id, task->length, (uintptr_t)task, 0);
|
||||
TAILQ_INSERT_TAIL(&lun->tasks, task, scsi_link);
|
||||
if (!lun->removed) {
|
||||
/* Check the command is allowed or not when reservation is exist */
|
||||
rc = spdk_scsi_pr_check(task);
|
||||
if (spdk_unlikely(rc < 0)) {
|
||||
/* Reservation Conflict */
|
||||
rc = SPDK_SCSI_TASK_COMPLETE;
|
||||
} else {
|
||||
rc = spdk_bdev_scsi_execute(task);
|
||||
}
|
||||
} else {
|
||||
spdk_scsi_task_process_abort(task);
|
||||
rc = SPDK_SCSI_TASK_COMPLETE;
|
||||
|
@ -203,6 +203,7 @@ bool spdk_scsi_bdev_get_dif_ctx(struct spdk_bdev *bdev, uint8_t *cdb, uint32_t o
|
||||
|
||||
int spdk_scsi_pr_out(struct spdk_scsi_task *task, uint8_t *cdb, uint8_t *data, uint16_t data_len);
|
||||
int spdk_scsi_pr_in(struct spdk_scsi_task *task, uint8_t *cdb, uint8_t *data, uint16_t data_len);
|
||||
int spdk_scsi_pr_check(struct spdk_scsi_task *task);
|
||||
|
||||
struct spdk_scsi_globals {
|
||||
pthread_mutex_t mutex;
|
||||
|
@ -730,3 +730,142 @@ invalid:
|
||||
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_scsi_pr_check(struct spdk_scsi_task *task)
|
||||
{
|
||||
struct spdk_scsi_lun *lun = task->lun;
|
||||
uint8_t *cdb = task->cdb;
|
||||
enum spdk_scsi_pr_type_code rtype;
|
||||
enum spdk_scsi_pr_out_service_action_code action;
|
||||
struct spdk_scsi_pr_registrant *reg;
|
||||
bool dma_to_device = false;
|
||||
|
||||
/* no reservation holders */
|
||||
if (lun->reservation.holder == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rtype = lun->reservation.rtype;
|
||||
assert(rtype != 0);
|
||||
|
||||
reg = spdk_scsi_pr_get_registrant(lun, task->initiator_port, task->target_port);
|
||||
/* current I_T nexus hold the reservation */
|
||||
if (spdk_scsi_pr_registrant_is_holder(lun, reg)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* reservation is held by other I_T nexus */
|
||||
switch (cdb[0]) {
|
||||
case SPDK_SPC_INQUIRY:
|
||||
case SPDK_SPC_REPORT_LUNS:
|
||||
case SPDK_SPC_REQUEST_SENSE:
|
||||
case SPDK_SPC_LOG_SENSE:
|
||||
case SPDK_SPC_TEST_UNIT_READY:
|
||||
case SPDK_SBC_START_STOP_UNIT:
|
||||
case SPDK_SBC_READ_CAPACITY_10:
|
||||
case SPDK_SPC_PERSISTENT_RESERVE_IN:
|
||||
case SPDK_SPC_SERVICE_ACTION_IN_16:
|
||||
return 0;
|
||||
case SPDK_SPC_MODE_SELECT_6:
|
||||
case SPDK_SPC_MODE_SELECT_10:
|
||||
case SPDK_SPC_MODE_SENSE_6:
|
||||
case SPDK_SPC_MODE_SENSE_10:
|
||||
case SPDK_SPC_LOG_SELECT:
|
||||
/* I_T nexus is registrant but not holder */
|
||||
if (!reg) {
|
||||
SPDK_DEBUGLOG(SPDK_LOG_SCSI, "CHECK: current I_T nexus "
|
||||
"is not registered, cdb 0x%x\n", cdb[0]);
|
||||
goto conflict;
|
||||
}
|
||||
break;
|
||||
case SPDK_SPC_PERSISTENT_RESERVE_OUT:
|
||||
action = cdb[1] & 0x1f;
|
||||
SPDK_DEBUGLOG(SPDK_LOG_SCSI, "CHECK: PR OUT action %u\n", action);
|
||||
switch (action) {
|
||||
case SPDK_SCSI_PR_OUT_RELEASE:
|
||||
case SPDK_SCSI_PR_OUT_CLEAR:
|
||||
case SPDK_SCSI_PR_OUT_PREEMPT:
|
||||
case SPDK_SCSI_PR_OUT_PREEMPT_AND_ABORT:
|
||||
if (!reg) {
|
||||
SPDK_ERRLOG("CHECK: PR OUT action %u\n", action);
|
||||
goto conflict;
|
||||
}
|
||||
break;
|
||||
case SPDK_SCSI_PR_OUT_REGISTER:
|
||||
case SPDK_SCSI_PR_OUT_REG_AND_IGNORE_KEY:
|
||||
return 0;
|
||||
case SPDK_SCSI_PR_OUT_REG_AND_MOVE:
|
||||
SPDK_ERRLOG("CHECK: PR OUT action %u\n", action);
|
||||
goto conflict;
|
||||
default:
|
||||
SPDK_ERRLOG("CHECK: PR OUT invalid action %u\n", action);
|
||||
goto conflict;
|
||||
}
|
||||
|
||||
/* For most SBC R/W commands */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cdb[0]) {
|
||||
case SPDK_SBC_READ_6:
|
||||
case SPDK_SBC_READ_10:
|
||||
case SPDK_SBC_READ_12:
|
||||
case SPDK_SBC_READ_16:
|
||||
break;
|
||||
case SPDK_SBC_WRITE_6:
|
||||
case SPDK_SBC_WRITE_10:
|
||||
case SPDK_SBC_WRITE_12:
|
||||
case SPDK_SBC_WRITE_16:
|
||||
case SPDK_SBC_UNMAP:
|
||||
case SPDK_SBC_SYNCHRONIZE_CACHE_10:
|
||||
case SPDK_SBC_SYNCHRONIZE_CACHE_16:
|
||||
dma_to_device = true;
|
||||
break;
|
||||
default:
|
||||
SPDK_ERRLOG("CHECK: unsupported SCSI command cdb 0x%x\n", cdb[0]);
|
||||
goto conflict;
|
||||
}
|
||||
|
||||
switch (rtype) {
|
||||
case SPDK_SCSI_PR_WRITE_EXCLUSIVE:
|
||||
if (dma_to_device) {
|
||||
SPDK_ERRLOG("CHECK: Write Exclusive reservation type "
|
||||
"rejects command 0x%x\n", cdb[0]);
|
||||
goto conflict;
|
||||
}
|
||||
break;
|
||||
case SPDK_SCSI_PR_EXCLUSIVE_ACCESS:
|
||||
SPDK_ERRLOG("CHECK: Exclusive Access reservation type "
|
||||
"rejects command 0x%x\n", cdb[0]);
|
||||
goto conflict;
|
||||
case SPDK_SCSI_PR_WRITE_EXCLUSIVE_REGS_ONLY:
|
||||
case SPDK_SCSI_PR_WRITE_EXCLUSIVE_ALL_REGS:
|
||||
if (!reg && dma_to_device) {
|
||||
SPDK_ERRLOG("CHECK: Registrants only reservation "
|
||||
"type reject command 0x%x\n", cdb[0]);
|
||||
goto conflict;
|
||||
}
|
||||
break;
|
||||
case SPDK_SCSI_PR_EXCLUSIVE_ACCESS_REGS_ONLY:
|
||||
case SPDK_SCSI_PR_EXCLUSIVE_ACCESS_ALL_REGS:
|
||||
if (!reg) {
|
||||
SPDK_ERRLOG("CHECK: All Registrants reservation "
|
||||
"type reject command 0x%x\n", cdb[0]);
|
||||
goto conflict;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
conflict:
|
||||
spdk_scsi_task_set_status(task, SPDK_SCSI_STATUS_RESERVATION_CONFLICT,
|
||||
SPDK_SCSI_SENSE_NO_SENSE,
|
||||
SPDK_SCSI_ASC_NO_ADDITIONAL_SENSE,
|
||||
SPDK_SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
|
||||
return -1;
|
||||
}
|
||||
|
@ -111,6 +111,8 @@ DEFINE_STUB_V(spdk_scsi_dev_queue_mgmt_task,
|
||||
DEFINE_STUB_V(spdk_scsi_dev_delete_lun,
|
||||
(struct spdk_scsi_dev *dev, struct spdk_scsi_lun *lun));
|
||||
|
||||
DEFINE_STUB(spdk_scsi_pr_check, int, (struct spdk_scsi_task *task), 0);
|
||||
|
||||
void
|
||||
spdk_bdev_scsi_reset(struct spdk_scsi_task *task)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user