Delay SCSI commands in TRANSITIONING ALUA state to ease initiators load

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6583 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2015-11-06 03:50:37 +00:00
parent 3636664071
commit 55c46e4106
3 changed files with 201 additions and 61 deletions

View File

@@ -2204,6 +2204,9 @@ struct scst_cmd {
/* Set if cmd was pre-alloced by target driver */
unsigned int pre_alloced:1;
/* Set if cmd was already ALUA checked in TRANSITIONING state */
unsigned int already_transitioning:1;
/* Set if scst_cmd_set_write_not_received_data_len() was called */
unsigned int write_not_received_set:1;
@@ -3008,7 +3011,10 @@ struct scst_tgt_dev {
atomic_t tgt_dev_cmd_count ____cacheline_aligned_in_smp;
/* ALUA command filter */
bool (*alua_filter)(struct scst_cmd *cmd);
#define SCST_ALUA_CHECK_OK 0
#define SCST_ALUA_CHECK_DELAYED 1
#define SCST_ALUA_CHECK_ERROR -1
int (*alua_filter)(struct scst_cmd *cmd);
struct scst_order_data *curr_order_data;
struct scst_order_data tgt_dev_order_data;

View File

@@ -3247,15 +3247,40 @@ out_done:
goto out;
}
static inline bool scst_check_alua(struct scst_cmd *cmd, int *out_res)
{
int (*alua_filter)(struct scst_cmd *cmd);
bool res = false;
alua_filter = ACCESS_ONCE(cmd->tgt_dev->alua_filter);
if (unlikely(alua_filter)) {
int ac = alua_filter(cmd);
if (ac != SCST_ALUA_CHECK_OK) {
if (ac != SCST_ALUA_CHECK_DELAYED) {
EXTRACHECKS_BUG_ON(cmd->status == 0);
scst_set_cmd_abnormal_done_state(cmd);
*out_res = SCST_CMD_STATE_RES_CONT_SAME;
}
res = true;
}
}
return res;
}
static int scst_exec_check_blocking(struct scst_cmd **active_cmd)
{
struct scst_cmd *cmd = *active_cmd;
struct scst_cmd *ref_cmd;
int res = SCST_CMD_STATE_RES_CONT_NEXT;
TRACE_ENTRY();
cmd->state = SCST_CMD_STATE_EXEC_CHECK_BLOCKING;
if (unlikely(scst_check_alua(cmd, &res)))
goto out;
if (unlikely(scst_check_blocked_dev(cmd)))
goto out;
@@ -3319,6 +3344,9 @@ done:
cmd->state = SCST_CMD_STATE_EXEC_CHECK_BLOCKING;
if (unlikely(scst_check_alua(cmd, &res)))
goto out;
if (unlikely(scst_check_blocked_dev(cmd)))
break;
@@ -3338,8 +3366,8 @@ done:
/* !! At this point sess, dev and tgt_dev can be already freed !! */
out:
TRACE_EXIT();
return SCST_CMD_STATE_RES_CONT_NEXT;
TRACE_EXIT_RES(res);
return res;
}
static int scst_exec_check_sn(struct scst_cmd **active_cmd)
@@ -4514,7 +4542,6 @@ static int scst_translate_lun(struct scst_cmd *cmd)
*/
static int __scst_init_cmd(struct scst_cmd *cmd)
{
bool (*alua_filter)(struct scst_cmd *cmd);
int res = 0;
TRACE_ENTRY();
@@ -4555,12 +4582,6 @@ static int __scst_init_cmd(struct scst_cmd *cmd)
if (unlikely(failure))
goto out_busy;
alua_filter = ACCESS_ONCE(cmd->tgt_dev->alua_filter);
if (unlikely(alua_filter && !alua_filter(cmd))) {
scst_set_cmd_abnormal_done_state(cmd);
goto out;
}
/*
* SCST_IMPLICIT_HQ for unknown commands not implemented for
* case when set_sn_on_restart_cmd not set, because custom parse

View File

@@ -272,11 +272,14 @@ static struct kobj_type scst_tg_tgt_ktype = {
};
/*
* Whether or not to accept a command in the ALUA unavailable and transitioning
* states.
* Whether or not to accept a command in the ALUA standby state.
*/
static bool scst_tg_accept(struct scst_cmd *cmd)
static int scst_tg_accept_standby(struct scst_cmd *cmd)
{
int res;
TRACE_ENTRY();
switch (cmd->cdb[0]) {
case TEST_UNIT_READY:
case GET_EVENT_STATUS_NOTIFICATION:
@@ -292,41 +295,6 @@ static bool scst_tg_accept(struct scst_cmd *cmd)
case RESERVE_10:
case READ_BUFFER:
case WRITE_BUFFER:
return true;
case SERVICE_ACTION_IN_16:
switch (cmd->cdb[1] & 0x1f) {
case SAI_READ_CAPACITY_16:
return true;
}
break;
case MAINTENANCE_IN:
switch (cmd->cdb[1] & 0x1f) {
case MI_REPORT_TARGET_PGS:
return true;
}
break;
case MAINTENANCE_OUT:
switch (cmd->cdb[1] & 0x1f) {
case MO_SET_TARGET_PGS:
return true;
}
break;
}
return false;
}
/*
* Whether or not to accept a command in the ALUA standby state.
*/
static bool scst_tg_accept_standby(struct scst_cmd *cmd)
{
bool process_cmd = scst_tg_accept(cmd);
if (process_cmd)
return process_cmd;
switch (cmd->cdb[0]) {
case MODE_SELECT:
case MODE_SELECT_10:
case LOG_SELECT:
@@ -335,42 +303,187 @@ static bool scst_tg_accept_standby(struct scst_cmd *cmd)
case SEND_DIAGNOSTIC:
case PERSISTENT_RESERVE_IN:
case PERSISTENT_RESERVE_OUT:
return true;
res = SCST_ALUA_CHECK_OK;
goto out;
case SERVICE_ACTION_IN_16:
switch (cmd->cdb[1] & 0x1f) {
case SAI_READ_CAPACITY_16:
res = SCST_ALUA_CHECK_OK;
goto out;
}
break;
case MAINTENANCE_IN:
switch (cmd->cdb[1] & 0x1f) {
case MI_REPORT_TARGET_PGS:
res = SCST_ALUA_CHECK_OK;
goto out;
}
break;
case MAINTENANCE_OUT:
switch (cmd->cdb[1] & 0x1f) {
case MO_SET_TARGET_PGS:
res = SCST_ALUA_CHECK_OK;
goto out;
}
break;
}
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_alua_standby));
res = SCST_ALUA_CHECK_ERROR;
return false;
out:
TRACE_EXIT_RES(res);
return res;
}
/*
* Whether or not to accept a command in the ALUA unavailable state.
*/
static bool scst_tg_accept_unav(struct scst_cmd *cmd)
static int scst_tg_accept_unav(struct scst_cmd *cmd)
{
bool process_cmd = scst_tg_accept(cmd);
int res;
if (!process_cmd)
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_alua_unav));
TRACE_ENTRY();
return process_cmd;
switch (cmd->cdb[0]) {
case TEST_UNIT_READY:
case GET_EVENT_STATUS_NOTIFICATION:
case INQUIRY:
case MODE_SENSE:
case MODE_SENSE_10:
case READ_CAPACITY:
case REPORT_LUNS:
case REQUEST_SENSE:
case RELEASE:
case RELEASE_10:
case RESERVE:
case RESERVE_10:
case READ_BUFFER:
case WRITE_BUFFER:
res = SCST_ALUA_CHECK_OK;
goto out;
case SERVICE_ACTION_IN_16:
switch (cmd->cdb[1] & 0x1f) {
case SAI_READ_CAPACITY_16:
res = SCST_ALUA_CHECK_OK;
goto out;
}
break;
case MAINTENANCE_IN:
switch (cmd->cdb[1] & 0x1f) {
case MI_REPORT_TARGET_PGS:
res = SCST_ALUA_CHECK_OK;
goto out;
}
break;
case MAINTENANCE_OUT:
switch (cmd->cdb[1] & 0x1f) {
case MO_SET_TARGET_PGS:
res = SCST_ALUA_CHECK_OK;
goto out;
}
break;
}
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_alua_unav));
res = SCST_ALUA_CHECK_ERROR;
out:
TRACE_EXIT_RES(res);
return res;
}
struct scst_alua_retry {
struct scst_cmd *alua_retry_cmd;
struct delayed_work alua_retry_work;
};
static void scst_alua_transitioning_work_fn(struct delayed_work *work)
{
struct scst_alua_retry *retry = container_of(work, struct scst_alua_retry,
alua_retry_work);
struct scst_cmd *cmd = retry->alua_retry_cmd;
TRACE_ENTRY();
TRACE_DBG("Retrying transitioning cmd %p", cmd);
spin_lock_irq(&cmd->cmd_threads->cmd_list_lock);
list_add(&cmd->cmd_list_entry,
&cmd->cmd_threads->active_cmd_list);
wake_up(&cmd->cmd_threads->cmd_list_waitQ);
spin_unlock_irq(&cmd->cmd_threads->cmd_list_lock);
kfree(retry);
TRACE_EXIT();
return;
}
/*
* Whether or not to accept a command in the ALUA transitioning state.
*/
static bool scst_tg_accept_transitioning(struct scst_cmd *cmd)
static int scst_tg_accept_transitioning(struct scst_cmd *cmd)
{
bool process_cmd = scst_tg_accept(cmd);
int res;
if (!process_cmd)
scst_set_cmd_error(cmd,
TRACE_ENTRY();
switch (cmd->cdb[0]) {
case INQUIRY:
case READ_CAPACITY:
case REPORT_LUNS:
case REQUEST_SENSE:
case READ_BUFFER:
case WRITE_BUFFER:
res = SCST_ALUA_CHECK_OK;
goto out;
case SERVICE_ACTION_IN_16:
switch (cmd->cdb[1] & 0x1f) {
case SAI_READ_CAPACITY_16:
res = SCST_ALUA_CHECK_OK;
goto out;
}
break;
}
if (cmd->already_transitioning)
TRACE_DBG("cmd %p already transitioned checked, failing", cmd);
else {
struct scst_alua_retry *retry;
TRACE_DBG("ALUA transitioning: delaying cmd %p", cmd);
retry = kzalloc(sizeof(*retry), GFP_KERNEL);
if (retry == NULL) {
TRACE_DBG("Unable to allocate ALUA retry "
"struct, failing cmd %p", cmd);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_alua_transitioning));
res = SCST_ALUA_CHECK_ERROR;
goto out;
}
/* No get is needed, because cmd is sync here */
retry->alua_retry_cmd = cmd;
INIT_DELAYED_WORK(&retry->alua_retry_work,
(void (*)(struct work_struct *))scst_alua_transitioning_work_fn);
cmd->already_transitioning = 1;
schedule_delayed_work(&retry->alua_retry_work, HZ/2);
res = SCST_ALUA_CHECK_DELAYED;
goto out;
}
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_alua_transitioning));
res = SCST_ALUA_CHECK_ERROR;
return process_cmd;
out:
TRACE_EXIT_RES(res);
return res;
}
static bool (*scst_alua_filter[])(struct scst_cmd *cmd) = {
static int (*scst_alua_filter[])(struct scst_cmd *cmd) = {
[SCST_TG_STATE_OPTIMIZED] = NULL,
[SCST_TG_STATE_NONOPTIMIZED] = NULL,
[SCST_TG_STATE_STANDBY] = scst_tg_accept_standby,