mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-25 00:26:43 +00:00
Rework iSCSI aborts to make them more correct and remove recent workarounds (one more post-IET cleanup)
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@3444 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
+13
-16
@@ -620,9 +620,9 @@ void iscsi_check_tm_data_wait_timeouts(struct iscsi_conn *conn, bool force)
|
|||||||
|
|
||||||
TRACE_ENTRY();
|
TRACE_ENTRY();
|
||||||
|
|
||||||
TRACE_DBG_FLAG(force ? TRACE_CONN_OC_DBG : TRACE_MGMT_DEBUG,
|
TRACE_DBG_FLAG(TRACE_MGMT_DEBUG, "conn %p, read_cmnd %p, read_state "
|
||||||
"conn %p, read_cmnd %p, read_state %d, j %ld (TIMEOUT %d, "
|
"%d, j %ld (TIMEOUT %d, force %d)", conn, conn->read_cmnd,
|
||||||
"force %d)", conn, conn->read_cmnd, conn->read_state, j,
|
conn->read_state, j,
|
||||||
ISCSI_TM_DATA_WAIT_TIMEOUT + ISCSI_ADD_SCHED_TIME, force);
|
ISCSI_TM_DATA_WAIT_TIMEOUT + ISCSI_ADD_SCHED_TIME, force);
|
||||||
|
|
||||||
iscsi_extracheck_is_rd_thread(conn);
|
iscsi_extracheck_is_rd_thread(conn);
|
||||||
@@ -635,23 +635,19 @@ again:
|
|||||||
list_for_each_entry(cmnd, &conn->write_timeout_list,
|
list_for_each_entry(cmnd, &conn->write_timeout_list,
|
||||||
write_timeout_list_entry) {
|
write_timeout_list_entry) {
|
||||||
if (test_bit(ISCSI_CMD_ABORTED, &cmnd->prelim_compl_flags)) {
|
if (test_bit(ISCSI_CMD_ABORTED, &cmnd->prelim_compl_flags)) {
|
||||||
TRACE_DBG_FLAG(force ? TRACE_CONN_OC_DBG : TRACE_MGMT_DEBUG,
|
TRACE_DBG_FLAG(TRACE_MGMT_DEBUG, "Checking aborted "
|
||||||
"Checking aborted cmnd %p (scst_state %d, "
|
"cmnd %p (scst_state %d, on_write_timeout_list "
|
||||||
"on_write_timeout_list %d, write_start %ld, "
|
"%d, write_start %ld, r2t_len_to_receive %d)",
|
||||||
"r2t_len_to_receive %d)", cmnd, cmnd->scst_state,
|
cmnd, cmnd->scst_state,
|
||||||
cmnd->on_write_timeout_list, cmnd->write_start,
|
cmnd->on_write_timeout_list, cmnd->write_start,
|
||||||
cmnd->r2t_len_to_receive);
|
cmnd->r2t_len_to_receive);
|
||||||
if (cmnd == conn->read_cmnd) {
|
if (cmnd == conn->read_cmnd) {
|
||||||
TRACE_DBG_FLAG(force ? TRACE_CONN_OC_DBG : TRACE_MGMT_DEBUG,
|
TRACE_DBG_FLAG(TRACE_MGMT_DEBUG,
|
||||||
"cmnd %p is read cmd", cmnd);
|
"cmnd %p is read cmd", cmnd);
|
||||||
sBUG_ON(force);
|
sBUG_ON(force);
|
||||||
if ((conn->read_state == RX_INIT_BHS) ||
|
sBUG_ON((conn->read_state == RX_INIT_BHS) ||
|
||||||
(conn->read_state == RX_BHS)) {
|
(conn->read_state == RX_BHS));
|
||||||
TRACE_MGMT_DBG("Unabort not yet received cmnd %p",
|
if (cmnd->scst_state == ISCSI_CMD_STATE_RX_CMD) {
|
||||||
cmnd);
|
|
||||||
clear_bit(ISCSI_CMD_ABORTED, &cmnd->prelim_compl_flags);
|
|
||||||
continue;
|
|
||||||
} else if (cmnd->scst_state == ISCSI_CMD_STATE_RX_CMD) {
|
|
||||||
TRACE_MGMT_DBG("Aborted cmnd %p is RX_CMD, "
|
TRACE_MGMT_DBG("Aborted cmnd %p is RX_CMD, "
|
||||||
"keep waiting", cmnd);
|
"keep waiting", cmnd);
|
||||||
goto cont;
|
goto cont;
|
||||||
@@ -661,7 +657,8 @@ again:
|
|||||||
(time_after_eq(j, cmnd->write_start + ISCSI_TM_DATA_WAIT_TIMEOUT) ||
|
(time_after_eq(j, cmnd->write_start + ISCSI_TM_DATA_WAIT_TIMEOUT) ||
|
||||||
force)) {
|
force)) {
|
||||||
if (cmnd == conn->read_cmnd) {
|
if (cmnd == conn->read_cmnd) {
|
||||||
TRACE_MGMT_DBG("Clearing read_cmnd for conn %p", conn);
|
TRACE_MGMT_DBG("Clearing read_cmnd for "
|
||||||
|
"conn %p", conn);
|
||||||
conn->read_cmnd = NULL;
|
conn->read_cmnd = NULL;
|
||||||
conn->read_state = RX_INIT_BHS;
|
conn->read_state = RX_INIT_BHS;
|
||||||
}
|
}
|
||||||
|
|||||||
+84
-64
@@ -61,7 +61,6 @@ static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status);
|
|||||||
static void iscsi_check_send_delayed_tm_resp(struct iscsi_session *sess);
|
static void iscsi_check_send_delayed_tm_resp(struct iscsi_session *sess);
|
||||||
static void req_cmnd_release(struct iscsi_cmnd *req);
|
static void req_cmnd_release(struct iscsi_cmnd *req);
|
||||||
static int cmnd_insert_data_wait_hash(struct iscsi_cmnd *cmnd);
|
static int cmnd_insert_data_wait_hash(struct iscsi_cmnd *cmnd);
|
||||||
static void __cmnd_abort(struct iscsi_cmnd *cmnd);
|
|
||||||
static void iscsi_cmnd_init_write(struct iscsi_cmnd *rsp, int flags);
|
static void iscsi_cmnd_init_write(struct iscsi_cmnd *rsp, int flags);
|
||||||
static void iscsi_set_resid_no_scst_cmd(struct iscsi_cmnd *rsp);
|
static void iscsi_set_resid_no_scst_cmd(struct iscsi_cmnd *rsp);
|
||||||
static void iscsi_set_resid(struct iscsi_cmnd *rsp);
|
static void iscsi_set_resid(struct iscsi_cmnd *rsp);
|
||||||
@@ -2250,7 +2249,7 @@ static void __cmnd_abort(struct iscsi_cmnd *cmnd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Must be called from the read or conn close thread */
|
/* Must be called from the read or conn close thread */
|
||||||
static int cmnd_abort(struct iscsi_cmnd *req, int *status)
|
static int cmnd_abort_pre_checks(struct iscsi_cmnd *req, int *status)
|
||||||
{
|
{
|
||||||
struct iscsi_task_mgt_hdr *req_hdr =
|
struct iscsi_task_mgt_hdr *req_hdr =
|
||||||
(struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
|
(struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
|
||||||
@@ -2268,7 +2267,6 @@ static int cmnd_abort(struct iscsi_cmnd *req, int *status)
|
|||||||
|
|
||||||
cmnd = cmnd_find_itt_get(req->conn, req_hdr->rtt);
|
cmnd = cmnd_find_itt_get(req->conn, req_hdr->rtt);
|
||||||
if (cmnd) {
|
if (cmnd) {
|
||||||
struct iscsi_conn *conn = cmnd->conn;
|
|
||||||
struct iscsi_scsi_cmd_hdr *hdr = cmnd_hdr(cmnd);
|
struct iscsi_scsi_cmd_hdr *hdr = cmnd_hdr(cmnd);
|
||||||
|
|
||||||
if (req_hdr->lun != hdr->lun) {
|
if (req_hdr->lun != hdr->lun) {
|
||||||
@@ -2310,10 +2308,6 @@ static int cmnd_abort(struct iscsi_cmnd *req, int *status)
|
|||||||
goto out_put;
|
goto out_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_bh(&conn->cmd_list_lock);
|
|
||||||
__cmnd_abort(cmnd);
|
|
||||||
spin_unlock_bh(&conn->cmd_list_lock);
|
|
||||||
|
|
||||||
cmnd_put(cmnd);
|
cmnd_put(cmnd);
|
||||||
res = 0;
|
res = 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -2351,69 +2345,86 @@ out_put:
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Must be called from the read or conn close thread */
|
struct iscsi_cmnd_abort_params {
|
||||||
static int target_abort(struct iscsi_cmnd *req, int all)
|
struct work_struct iscsi_cmnd_abort_work;
|
||||||
|
struct scst_cmd *scst_cmd;
|
||||||
|
};
|
||||||
|
|
||||||
|
static mempool_t *iscsi_cmnd_abort_mempool;
|
||||||
|
|
||||||
|
static void iscsi_cmnd_abort_fn(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct iscsi_target *target = req->conn->session->target;
|
struct iscsi_cmnd_abort_params *params = container_of(work,
|
||||||
struct iscsi_task_mgt_hdr *req_hdr =
|
struct iscsi_cmnd_abort_params, iscsi_cmnd_abort_work);
|
||||||
(struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
|
struct scst_cmd *scst_cmd = params->scst_cmd;
|
||||||
struct iscsi_session *session;
|
struct iscsi_session *session = scst_sess_get_tgt_priv(scst_cmd->sess);
|
||||||
struct iscsi_conn *conn;
|
struct iscsi_conn *conn;
|
||||||
struct iscsi_cmnd *cmnd;
|
struct iscsi_cmnd *cmnd = scst_cmd_get_tgt_priv(scst_cmd);
|
||||||
|
bool done = false;
|
||||||
|
|
||||||
mutex_lock(&target->target_mutex);
|
TRACE_ENTRY();
|
||||||
|
|
||||||
list_for_each_entry(session, &target->session_list,
|
TRACE_MGMT_DBG("Checking aborted scst_cmd %p (cmnd %p)", scst_cmd, cmnd);
|
||||||
session_list_entry) {
|
|
||||||
list_for_each_entry(conn, &session->conn_list,
|
|
||||||
conn_list_entry) {
|
|
||||||
spin_lock_bh(&conn->cmd_list_lock);
|
|
||||||
list_for_each_entry(cmnd, &conn->cmd_list,
|
|
||||||
cmd_list_entry) {
|
|
||||||
if (cmnd == req)
|
|
||||||
continue;
|
|
||||||
if (all)
|
|
||||||
__cmnd_abort(cmnd);
|
|
||||||
else if (req_hdr->lun == cmnd_hdr(cmnd)->lun)
|
|
||||||
__cmnd_abort(cmnd);
|
|
||||||
}
|
|
||||||
spin_unlock_bh(&conn->cmd_list_lock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&target->target_mutex);
|
mutex_lock(&session->target->target_mutex);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Must be called from the read or conn close thread */
|
|
||||||
static void task_set_abort(struct iscsi_cmnd *req)
|
|
||||||
{
|
|
||||||
struct iscsi_session *session = req->conn->session;
|
|
||||||
struct iscsi_task_mgt_hdr *req_hdr =
|
|
||||||
(struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
|
|
||||||
struct iscsi_target *target = session->target;
|
|
||||||
struct iscsi_conn *conn;
|
|
||||||
struct iscsi_cmnd *cmnd;
|
|
||||||
|
|
||||||
mutex_lock(&target->target_mutex);
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cmnd pointer is valid only under cmd_list_lock, but we can't know the
|
||||||
|
* corresponding conn without dereferencing cmnd at first, so let's
|
||||||
|
* check all conns and cmnds to find out if our cmnd is still valid
|
||||||
|
* under lock.
|
||||||
|
*/
|
||||||
list_for_each_entry(conn, &session->conn_list, conn_list_entry) {
|
list_for_each_entry(conn, &session->conn_list, conn_list_entry) {
|
||||||
|
struct iscsi_cmnd *c;
|
||||||
spin_lock_bh(&conn->cmd_list_lock);
|
spin_lock_bh(&conn->cmd_list_lock);
|
||||||
list_for_each_entry(cmnd, &conn->cmd_list, cmd_list_entry) {
|
list_for_each_entry(c, &conn->cmd_list, cmd_list_entry) {
|
||||||
struct iscsi_scsi_cmd_hdr *hdr = cmnd_hdr(cmnd);
|
if (c == cmnd) {
|
||||||
if (cmnd == req)
|
__cmnd_abort(cmnd);
|
||||||
continue;
|
done = true;
|
||||||
if (req_hdr->lun != hdr->lun)
|
break;
|
||||||
continue;
|
}
|
||||||
if (before(req_hdr->cmd_sn, hdr->cmd_sn) ||
|
|
||||||
req_hdr->cmd_sn == hdr->cmd_sn)
|
|
||||||
continue;
|
|
||||||
__cmnd_abort(cmnd);
|
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&conn->cmd_list_lock);
|
spin_unlock_bh(&conn->cmd_list_lock);
|
||||||
|
if (done)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&target->target_mutex);
|
mutex_unlock(&session->target->target_mutex);
|
||||||
|
|
||||||
|
scst_cmd_put(scst_cmd);
|
||||||
|
|
||||||
|
mempool_free(params, iscsi_cmnd_abort_mempool);
|
||||||
|
|
||||||
|
TRACE_EXIT();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iscsi_on_abort_cmd(struct scst_cmd *scst_cmd)
|
||||||
|
{
|
||||||
|
struct iscsi_cmnd_abort_params *params;
|
||||||
|
|
||||||
|
TRACE_ENTRY();
|
||||||
|
|
||||||
|
params = mempool_alloc(iscsi_cmnd_abort_mempool, GFP_ATOMIC);
|
||||||
|
if (params == NULL) {
|
||||||
|
PRINT_CRIT_ERROR("Unable to create iscsi_cmnd_abort_params, "
|
||||||
|
"iSCSI cmnd for scst_cmd %p may not be aborted",
|
||||||
|
scst_cmd);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(params, 0, sizeof(*params));
|
||||||
|
INIT_WORK(¶ms->iscsi_cmnd_abort_work, iscsi_cmnd_abort_fn);
|
||||||
|
params->scst_cmd = scst_cmd;
|
||||||
|
|
||||||
|
scst_cmd_get(scst_cmd);
|
||||||
|
|
||||||
|
TRACE_MGMT_DBG("Scheduling abort check for scst_cmd %p", scst_cmd);
|
||||||
|
|
||||||
|
schedule_work(¶ms->iscsi_cmnd_abort_work);
|
||||||
|
|
||||||
|
out:
|
||||||
|
TRACE_EXIT();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2516,7 +2527,7 @@ static void execute_task_management(struct iscsi_cmnd *req)
|
|||||||
|
|
||||||
switch (function) {
|
switch (function) {
|
||||||
case ISCSI_FUNCTION_ABORT_TASK:
|
case ISCSI_FUNCTION_ABORT_TASK:
|
||||||
rc = cmnd_abort(req, &status);
|
rc = cmnd_abort_pre_checks(req, &status);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
params.fn = SCST_ABORT_TASK;
|
params.fn = SCST_ABORT_TASK;
|
||||||
params.tag = (__force u32)req_hdr->rtt;
|
params.tag = (__force u32)req_hdr->rtt;
|
||||||
@@ -2532,7 +2543,6 @@ static void execute_task_management(struct iscsi_cmnd *req)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ISCSI_FUNCTION_ABORT_TASK_SET:
|
case ISCSI_FUNCTION_ABORT_TASK_SET:
|
||||||
task_set_abort(req);
|
|
||||||
params.fn = SCST_ABORT_TASK_SET;
|
params.fn = SCST_ABORT_TASK_SET;
|
||||||
params.lun = (uint8_t *)&req_hdr->lun;
|
params.lun = (uint8_t *)&req_hdr->lun;
|
||||||
params.lun_len = sizeof(req_hdr->lun);
|
params.lun_len = sizeof(req_hdr->lun);
|
||||||
@@ -2544,7 +2554,6 @@ static void execute_task_management(struct iscsi_cmnd *req)
|
|||||||
status = ISCSI_RESPONSE_FUNCTION_REJECTED;
|
status = ISCSI_RESPONSE_FUNCTION_REJECTED;
|
||||||
break;
|
break;
|
||||||
case ISCSI_FUNCTION_CLEAR_TASK_SET:
|
case ISCSI_FUNCTION_CLEAR_TASK_SET:
|
||||||
task_set_abort(req);
|
|
||||||
params.fn = SCST_CLEAR_TASK_SET;
|
params.fn = SCST_CLEAR_TASK_SET;
|
||||||
params.lun = (uint8_t *)&req_hdr->lun;
|
params.lun = (uint8_t *)&req_hdr->lun;
|
||||||
params.lun_len = sizeof(req_hdr->lun);
|
params.lun_len = sizeof(req_hdr->lun);
|
||||||
@@ -2568,7 +2577,6 @@ static void execute_task_management(struct iscsi_cmnd *req)
|
|||||||
break;
|
break;
|
||||||
case ISCSI_FUNCTION_TARGET_COLD_RESET:
|
case ISCSI_FUNCTION_TARGET_COLD_RESET:
|
||||||
case ISCSI_FUNCTION_TARGET_WARM_RESET:
|
case ISCSI_FUNCTION_TARGET_WARM_RESET:
|
||||||
target_abort(req, 1);
|
|
||||||
params.fn = SCST_TARGET_RESET;
|
params.fn = SCST_TARGET_RESET;
|
||||||
params.cmd_sn = req_hdr->cmd_sn;
|
params.cmd_sn = req_hdr->cmd_sn;
|
||||||
params.cmd_sn_set = 1;
|
params.cmd_sn_set = 1;
|
||||||
@@ -2577,7 +2585,6 @@ static void execute_task_management(struct iscsi_cmnd *req)
|
|||||||
status = ISCSI_RESPONSE_FUNCTION_REJECTED;
|
status = ISCSI_RESPONSE_FUNCTION_REJECTED;
|
||||||
break;
|
break;
|
||||||
case ISCSI_FUNCTION_LOGICAL_UNIT_RESET:
|
case ISCSI_FUNCTION_LOGICAL_UNIT_RESET:
|
||||||
target_abort(req, 0);
|
|
||||||
params.fn = SCST_LUN_RESET;
|
params.fn = SCST_LUN_RESET;
|
||||||
params.lun = (uint8_t *)&req_hdr->lun;
|
params.lun = (uint8_t *)&req_hdr->lun;
|
||||||
params.lun_len = sizeof(req_hdr->lun);
|
params.lun_len = sizeof(req_hdr->lun);
|
||||||
@@ -3827,6 +3834,7 @@ struct scst_tgt_template iscsi_template = {
|
|||||||
.pre_exec = iscsi_pre_exec,
|
.pre_exec = iscsi_pre_exec,
|
||||||
.task_mgmt_affected_cmds_done = iscsi_task_mgmt_affected_cmds_done,
|
.task_mgmt_affected_cmds_done = iscsi_task_mgmt_affected_cmds_done,
|
||||||
.task_mgmt_fn_done = iscsi_task_mgmt_fn_done,
|
.task_mgmt_fn_done = iscsi_task_mgmt_fn_done,
|
||||||
|
.on_abort_cmd = iscsi_on_abort_cmd,
|
||||||
.report_aen = iscsi_report_aen,
|
.report_aen = iscsi_report_aen,
|
||||||
.get_initiator_port_transport_id = iscsi_get_initiator_port_transport_id,
|
.get_initiator_port_transport_id = iscsi_get_initiator_port_transport_id,
|
||||||
.get_scsi_transport_version = iscsi_get_scsi_transport_version,
|
.get_scsi_transport_version = iscsi_get_scsi_transport_version,
|
||||||
@@ -4016,12 +4024,19 @@ static int __init iscsi_init(void)
|
|||||||
sg_init_table(&dummy_sg, 1);
|
sg_init_table(&dummy_sg, 1);
|
||||||
sg_set_page(&dummy_sg, dummy_page, PAGE_SIZE, 0);
|
sg_set_page(&dummy_sg, dummy_page, PAGE_SIZE, 0);
|
||||||
|
|
||||||
|
iscsi_cmnd_abort_mempool = mempool_create_kmalloc_pool(2500,
|
||||||
|
sizeof(struct iscsi_cmnd_abort_params));
|
||||||
|
if (iscsi_cmnd_abort_mempool == NULL) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto out_free_dummy;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||||
err = net_set_get_put_page_callbacks(iscsi_get_page_callback,
|
err = net_set_get_put_page_callbacks(iscsi_get_page_callback,
|
||||||
iscsi_put_page_callback);
|
iscsi_put_page_callback);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
PRINT_INFO("Unable to set page callbackes: %d", err);
|
PRINT_INFO("Unable to set page callbackes: %d", err);
|
||||||
goto out_free_dummy;
|
goto out_destroy_mempool;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#ifndef GENERATING_UPSTREAM_PATCH
|
#ifndef GENERATING_UPSTREAM_PATCH
|
||||||
@@ -4092,6 +4107,9 @@ out_callb:
|
|||||||
#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
|
||||||
net_set_get_put_page_callbacks(NULL, NULL);
|
net_set_get_put_page_callbacks(NULL, NULL);
|
||||||
|
|
||||||
|
out_destroy_mempool:
|
||||||
|
mempool_destroy(iscsi_cmnd_abort_mempool);
|
||||||
|
|
||||||
out_free_dummy:
|
out_free_dummy:
|
||||||
#endif
|
#endif
|
||||||
__free_pages(dummy_page, 0);
|
__free_pages(dummy_page, 0);
|
||||||
@@ -4119,6 +4137,8 @@ static void __exit iscsi_exit(void)
|
|||||||
net_set_get_put_page_callbacks(NULL, NULL);
|
net_set_get_put_page_callbacks(NULL, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
mempool_destroy(iscsi_cmnd_abort_mempool);
|
||||||
|
|
||||||
__free_pages(dummy_page, 0);
|
__free_pages(dummy_page, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -672,7 +672,7 @@ static inline void iscsi_cmnd_set_length(struct iscsi_pdu *pdu)
|
|||||||
extern struct scst_tgt_template iscsi_template;
|
extern struct scst_tgt_template iscsi_template;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip this command if result is not 0. Must be called under
|
* Skip this command if result is true. Must be called under
|
||||||
* corresponding lock.
|
* corresponding lock.
|
||||||
*/
|
*/
|
||||||
static inline bool cmnd_get_check(struct iscsi_cmnd *cmnd)
|
static inline bool cmnd_get_check(struct iscsi_cmnd *cmnd)
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/file.h>
|
#include <linux/file.h>
|
||||||
#include <linux/kthread.h>
|
#include <linux/kthread.h>
|
||||||
#include <asm/ioctls.h>
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <net/tcp.h>
|
#include <net/tcp.h>
|
||||||
|
|
||||||
@@ -839,17 +838,10 @@ static int process_read_io(struct iscsi_conn *conn, int *closed)
|
|||||||
res = do_recv(conn);
|
res = do_recv(conn);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
/*
|
/*
|
||||||
* Clear aborted status if this command was
|
* This command not yet received on the aborted
|
||||||
* accidentally aborted with other commands of
|
* time, so shouldn't be affected by any abort.
|
||||||
* this connection. This command not yet
|
|
||||||
* received on the aborted time, so shouldn't be
|
|
||||||
* affected by the abort.
|
|
||||||
*/
|
*/
|
||||||
if (cmnd->prelim_compl_flags != 0)
|
EXTRACHECKS_BUG_ON(cmnd->prelim_compl_flags != 0);
|
||||||
TRACE_MGMT_DBG("Unabort not yet "
|
|
||||||
"received cmnd %p (flags %lx)",
|
|
||||||
cmnd, cmnd->prelim_compl_flags);
|
|
||||||
cmnd->prelim_compl_flags = 0;
|
|
||||||
|
|
||||||
iscsi_cmnd_get_length(&cmnd->pdu);
|
iscsi_cmnd_get_length(&cmnd->pdu);
|
||||||
|
|
||||||
|
|||||||
+20
-2
@@ -810,6 +810,15 @@ struct scst_tgt_template {
|
|||||||
*/
|
*/
|
||||||
void (*task_mgmt_fn_done) (struct scst_mgmt_cmd *mgmt_cmd);
|
void (*task_mgmt_fn_done) (struct scst_mgmt_cmd *mgmt_cmd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called to notify target driver that the command is being aborted.
|
||||||
|
* If target driver wants to redirect processing to some outside
|
||||||
|
* processing, it should get it using scst_cmd_get().
|
||||||
|
*
|
||||||
|
* OPTIONAL
|
||||||
|
*/
|
||||||
|
void (*on_abort_cmd) (struct scst_cmd *cmd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function should detect the target adapters that
|
* This function should detect the target adapters that
|
||||||
* are present in the system. The function should return a value
|
* are present in the system. The function should return a value
|
||||||
@@ -1232,7 +1241,13 @@ struct scst_dev_type {
|
|||||||
* - SCST_DEV_TM_NOT_COMPLETED - regular standard actions for the
|
* - SCST_DEV_TM_NOT_COMPLETED - regular standard actions for the
|
||||||
* command should be done
|
* command should be done
|
||||||
*
|
*
|
||||||
* Called without any locks held from a thread context.
|
* Can be called under many internal SCST locks, including under
|
||||||
|
* disabled IRQs, so dev handler should be careful with locking and,
|
||||||
|
* if necessary, pass processing somewhere outside (in a work, e.g.)
|
||||||
|
*
|
||||||
|
* But at the moment it's called under disabled IRQs only for
|
||||||
|
* SCST_ABORT_TASK, however dev handler using it should add a BUG_ON
|
||||||
|
* trap to catch if it's changed in future.
|
||||||
*
|
*
|
||||||
* OPTIONAL
|
* OPTIONAL
|
||||||
*/
|
*/
|
||||||
@@ -1862,7 +1877,10 @@ struct scst_cmd {
|
|||||||
/* Set if cmd is done */
|
/* Set if cmd is done */
|
||||||
unsigned int done:1;
|
unsigned int done:1;
|
||||||
|
|
||||||
/* Set if cmd is finished */
|
/*
|
||||||
|
* Set if cmd is finished. Used under sess_list_lock to sync
|
||||||
|
* between scst_finish_cmd() and scst_abort_cmd()
|
||||||
|
*/
|
||||||
unsigned int finished:1;
|
unsigned int finished:1;
|
||||||
|
|
||||||
#ifdef CONFIG_SCST_DEBUG_TM
|
#ifdef CONFIG_SCST_DEBUG_TM
|
||||||
|
|||||||
@@ -2408,6 +2408,7 @@ again:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Can be called under some spinlock and IRQs off */
|
||||||
static int dev_user_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
|
static int dev_user_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
|
||||||
struct scst_tgt_dev *tgt_dev)
|
struct scst_tgt_dev *tgt_dev)
|
||||||
{
|
{
|
||||||
@@ -2458,7 +2459,7 @@ static int dev_user_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
|
|||||||
dev_user_abort_ready_commands(dev);
|
dev_user_abort_ready_commands(dev);
|
||||||
|
|
||||||
/* We can't afford missing TM command due to memory shortage */
|
/* We can't afford missing TM command due to memory shortage */
|
||||||
ucmd = dev_user_alloc_ucmd(dev, GFP_KERNEL|__GFP_NOFAIL);
|
ucmd = dev_user_alloc_ucmd(dev, GFP_ATOMIC|__GFP_NOFAIL);
|
||||||
|
|
||||||
ucmd->user_cmd_payload_len =
|
ucmd->user_cmd_payload_len =
|
||||||
offsetof(struct scst_user_get_cmd, tm_cmd) +
|
offsetof(struct scst_user_get_cmd, tm_cmd) +
|
||||||
|
|||||||
+21
-12
@@ -508,7 +508,7 @@ int scst_pre_parse(struct scst_cmd *cmd)
|
|||||||
|
|
||||||
TRACE_DBG("op_name <%s> (cmd %p), direction=%d "
|
TRACE_DBG("op_name <%s> (cmd %p), direction=%d "
|
||||||
"(expected %d, set %s), bufflen=%d, out_bufflen=%d (expected "
|
"(expected %d, set %s), bufflen=%d, out_bufflen=%d (expected "
|
||||||
"len %d, out expected len %d), flags=%d", cmd->op_name, cmd,
|
"len %d, out expected len %d), flags=0x%x", cmd->op_name, cmd,
|
||||||
cmd->data_direction, cmd->expected_data_direction,
|
cmd->data_direction, cmd->expected_data_direction,
|
||||||
scst_cmd_is_expected_set(cmd) ? "yes" : "no",
|
scst_cmd_is_expected_set(cmd) ? "yes" : "no",
|
||||||
cmd->bufflen, cmd->out_bufflen, cmd->expected_transfer_len,
|
cmd->bufflen, cmd->out_bufflen, cmd->expected_transfer_len,
|
||||||
@@ -3641,10 +3641,13 @@ static int scst_finish_cmd(struct scst_cmd *cmd)
|
|||||||
|
|
||||||
list_del(&cmd->sess_cmd_list_entry);
|
list_del(&cmd->sess_cmd_list_entry);
|
||||||
|
|
||||||
spin_unlock_irq(&sess->sess_list_lock);
|
/*
|
||||||
|
* Done under sess_list_lock to sync with scst_abort_cmd() without
|
||||||
|
* using extra barrier.
|
||||||
|
*/
|
||||||
cmd->finished = 1;
|
cmd->finished = 1;
|
||||||
smp_mb(); /* to sync with scst_abort_cmd() */
|
|
||||||
|
spin_unlock_irq(&sess->sess_list_lock);
|
||||||
|
|
||||||
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
|
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) {
|
||||||
TRACE_MGMT_DBG("Aborted cmd %p finished (cmd_ref %d)",
|
TRACE_MGMT_DBG("Aborted cmd %p finished (cmd_ref %d)",
|
||||||
@@ -4613,7 +4616,6 @@ static int scst_call_dev_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
|
|||||||
if (h->task_mgmt_fn) {
|
if (h->task_mgmt_fn) {
|
||||||
TRACE_MGMT_DBG("Calling dev handler %s task_mgmt_fn(fn=%d)",
|
TRACE_MGMT_DBG("Calling dev handler %s task_mgmt_fn(fn=%d)",
|
||||||
h->name, mcmd->fn);
|
h->name, mcmd->fn);
|
||||||
EXTRACHECKS_BUG_ON(in_irq() || irqs_disabled());
|
|
||||||
res = h->task_mgmt_fn(mcmd, tgt_dev);
|
res = h->task_mgmt_fn(mcmd, tgt_dev);
|
||||||
TRACE_MGMT_DBG("Dev handler %s task_mgmt_fn() returned %d",
|
TRACE_MGMT_DBG("Dev handler %s task_mgmt_fn() returned %d",
|
||||||
h->name, res);
|
h->name, res);
|
||||||
@@ -4639,7 +4641,10 @@ static inline int scst_is_strict_mgmt_fn(int mgmt_fn)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Might be called under sess_list_lock and IRQ off + BHs also off */
|
/*
|
||||||
|
* Must be called under sess_list_lock to sync with finished flag assignment in
|
||||||
|
* scst_finish_cmd()
|
||||||
|
*/
|
||||||
void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
|
void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
|
||||||
bool other_ini, bool call_dev_task_mgmt_fn)
|
bool other_ini, bool call_dev_task_mgmt_fn)
|
||||||
{
|
{
|
||||||
@@ -4684,9 +4689,9 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
|
|||||||
spin_unlock_irqrestore(&other_ini_lock, flags);
|
spin_unlock_irqrestore(&other_ini_lock, flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To sync with cmd->finished/done set in
|
* To sync with setting cmd->done in scst_pre_xmit_response() (with
|
||||||
* scst_finish_cmd()/scst_pre_xmit_response() and with setting UA for
|
* scst_finish_cmd() we synced by using sess_list_lock) and with
|
||||||
* aborted cmd in scst_set_pending_UA().
|
* setting UA for aborted cmd in scst_set_pending_UA().
|
||||||
*/
|
*/
|
||||||
smp_mb__after_set_bit();
|
smp_mb__after_set_bit();
|
||||||
|
|
||||||
@@ -4697,10 +4702,8 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
|
|||||||
wake_up(&scst_init_cmd_list_waitQ);
|
wake_up(&scst_init_cmd_list_waitQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (call_dev_task_mgmt_fn && (cmd->tgt_dev != NULL)) {
|
if (!cmd->finished && call_dev_task_mgmt_fn && (cmd->tgt_dev != NULL))
|
||||||
EXTRACHECKS_BUG_ON(irqs_disabled());
|
|
||||||
scst_call_dev_task_mgmt_fn(mcmd, cmd->tgt_dev, 1);
|
scst_call_dev_task_mgmt_fn(mcmd, cmd->tgt_dev, 1);
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irqsave(&scst_mcmd_lock, flags);
|
spin_lock_irqsave(&scst_mcmd_lock, flags);
|
||||||
if ((mcmd != NULL) && !cmd->finished) {
|
if ((mcmd != NULL) && !cmd->finished) {
|
||||||
@@ -4766,6 +4769,9 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
|
|||||||
/* We don't need to wait for this cmd */
|
/* We don't need to wait for this cmd */
|
||||||
mempool_free(mstb, scst_mgmt_stub_mempool);
|
mempool_free(mstb, scst_mgmt_stub_mempool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cmd->tgtt->on_abort_cmd)
|
||||||
|
cmd->tgtt->on_abort_cmd(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
@@ -5495,7 +5501,10 @@ static int scst_abort_task(struct scst_mgmt_cmd *mcmd)
|
|||||||
cmd->tgt_sn, (long long unsigned int)mcmd->tag);
|
cmd->tgt_sn, (long long unsigned int)mcmd->tag);
|
||||||
mcmd->status = SCST_MGMT_STATUS_REJECTED;
|
mcmd->status = SCST_MGMT_STATUS_REJECTED;
|
||||||
} else {
|
} else {
|
||||||
|
spin_lock_irq(&cmd->sess->sess_list_lock);
|
||||||
scst_abort_cmd(cmd, mcmd, 0, 1);
|
scst_abort_cmd(cmd, mcmd, 0, 1);
|
||||||
|
spin_unlock_irq(&cmd->sess->sess_list_lock);
|
||||||
|
|
||||||
scst_unblock_aborted_cmds(0);
|
scst_unblock_aborted_cmds(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user