lib/iscsi: Fix iscsi_del_transfer_task deletes from both array and tailq

Previously iscsi_del_transfer_task() dequeued the task only from
the array conn->outstanding_r2t_tasks[].

process_non_read_task_completion() had dequeued the task from
the tailq conn->active_r2t_tasks then.

However abort_transfer_task_in_task_mgmt_resp had not dequeued the
task from the tailq conn->active_r2t_tasks then.

This was an apparent bug, and is fixed here. Update unit tests
accordingly.

Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: I93f02b2fb670dcee4c32d61c264e3ad5b4f9f43e
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/3108
Community-CI: Mellanox Build Bot
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Shuhei Matsumoto 2020-06-29 13:18:43 +09:00 committed by Tomasz Zawadzki
parent 41f59559e1
commit d5f3f48b60
4 changed files with 72 additions and 37 deletions

View File

@ -1226,14 +1226,11 @@ process_non_read_task_completion(struct spdk_iscsi_conn *conn,
* iscsi_clear_all_transfer_task() in iscsi.c.)
*/
if (primary->is_r2t_active) {
iscsi_del_transfer_task(conn, primary->tag);
if (primary->rsp_scsi_status != SPDK_SCSI_STATUS_GOOD) {
iscsi_task_copy_from_rsp_scsi_status(&primary->scsi, primary);
}
iscsi_task_response(conn, primary);
TAILQ_REMOVE(&conn->active_r2t_tasks, primary, link);
primary->is_r2t_active = false;
iscsi_task_put(primary);
iscsi_del_transfer_task(conn, primary->tag);
}
} else {
iscsi_task_response(conn, task);

View File

@ -2827,6 +2827,12 @@ iscsi_del_transfer_task(struct spdk_iscsi_conn *conn, uint32_t task_tag)
conn->outstanding_r2t_tasks[i] = conn->outstanding_r2t_tasks[i + 1];
}
conn->outstanding_r2t_tasks[conn->pending_r2t] = NULL;
assert(task->is_r2t_active == true);
TAILQ_REMOVE(&conn->active_r2t_tasks, task, link);
task->is_r2t_active = false;
iscsi_task_put(task);
start_queued_transfer_tasks(conn);
return true;
}

View File

@ -209,8 +209,22 @@ DEFINE_STUB_V(iscsi_task_mgmt_response,
DEFINE_STUB_V(iscsi_send_nopin, (struct spdk_iscsi_conn *conn));
DEFINE_STUB(iscsi_del_transfer_task, bool,
(struct spdk_iscsi_conn *conn, uint32_t task_tag), true);
bool
iscsi_del_transfer_task(struct spdk_iscsi_conn *conn, uint32_t task_tag)
{
struct spdk_iscsi_task *task;
task = TAILQ_FIRST(&conn->active_r2t_tasks);
if (task == NULL || task->tag != task_tag) {
return false;
}
TAILQ_REMOVE(&conn->active_r2t_tasks, task, link);
task->is_r2t_active = false;
iscsi_task_put(task);
return true;
}
DEFINE_STUB(iscsi_handle_incoming_pdus, int, (struct spdk_iscsi_conn *conn), 0);
@ -424,6 +438,7 @@ process_non_read_task_completion_test(void)
primary.scsi.ref = 1;
TAILQ_INSERT_TAIL(&conn.active_r2t_tasks, &primary, link);
primary.is_r2t_active = true;
primary.tag = 1;
/* First subtask which failed. */
task.scsi.length = 4096;

View File

@ -779,7 +779,7 @@ del_transfer_task_test(void)
{
struct spdk_iscsi_sess sess = {};
struct spdk_iscsi_conn conn = {};
struct spdk_iscsi_task task1 = {}, task2 = {}, task3 = {}, task4 = {}, task5 = {}, *task;
struct spdk_iscsi_task *task1, *task2, *task3, *task4, *task5;
struct spdk_iscsi_pdu *pdu1, *pdu2, *pdu3, *pdu4, *pdu5, *pdu;
int rc;
@ -794,83 +794,100 @@ del_transfer_task_test(void)
SPDK_CU_ASSERT_FATAL(pdu1 != NULL);
pdu1->data_segment_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
task1.scsi.transfer_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
iscsi_task_set_pdu(&task1, pdu1);
task1.tag = 11;
rc = add_transfer_task(&conn, &task1);
task1 = iscsi_task_get(&conn, NULL, NULL);
SPDK_CU_ASSERT_FATAL(task1 != NULL);
task1->scsi.transfer_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
iscsi_task_set_pdu(task1, pdu1);
task1->tag = 11;
rc = add_transfer_task(&conn, task1);
CU_ASSERT(rc == 0);
pdu2 = iscsi_get_pdu(&conn);
SPDK_CU_ASSERT_FATAL(pdu2 != NULL);
pdu2->data_segment_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
task2.scsi.transfer_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
iscsi_task_set_pdu(&task2, pdu2);
task2.tag = 12;
rc = add_transfer_task(&conn, &task2);
task2 = iscsi_task_get(&conn, NULL, NULL);
SPDK_CU_ASSERT_FATAL(task2 != NULL);
task2->scsi.transfer_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
iscsi_task_set_pdu(task2, pdu2);
task2->tag = 12;
rc = add_transfer_task(&conn, task2);
CU_ASSERT(rc == 0);
pdu3 = iscsi_get_pdu(&conn);
SPDK_CU_ASSERT_FATAL(pdu3 != NULL);
pdu3->data_segment_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
task3.scsi.transfer_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
iscsi_task_set_pdu(&task3, pdu3);
task3.tag = 13;
rc = add_transfer_task(&conn, &task3);
task3 = iscsi_task_get(&conn, NULL, NULL);
SPDK_CU_ASSERT_FATAL(task3 != NULL);
task3->scsi.transfer_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
iscsi_task_set_pdu(task3, pdu3);
task3->tag = 13;
rc = add_transfer_task(&conn, task3);
CU_ASSERT(rc == 0);
pdu4 = iscsi_get_pdu(&conn);
SPDK_CU_ASSERT_FATAL(pdu4 != NULL);
pdu4->data_segment_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
task4.scsi.transfer_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
iscsi_task_set_pdu(&task4, pdu4);
task4.tag = 14;
rc = add_transfer_task(&conn, &task4);
task4 = iscsi_task_get(&conn, NULL, NULL);
SPDK_CU_ASSERT_FATAL(task4 != NULL);
task4->scsi.transfer_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
iscsi_task_set_pdu(task4, pdu4);
task4->tag = 14;
rc = add_transfer_task(&conn, task4);
CU_ASSERT(rc == 0);
pdu5 = iscsi_get_pdu(&conn);
SPDK_CU_ASSERT_FATAL(pdu5 != NULL);
pdu5->data_segment_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
task5.scsi.transfer_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
iscsi_task_set_pdu(&task5, pdu5);
task5.tag = 15;
rc = add_transfer_task(&conn, &task5);
task5 = iscsi_task_get(&conn, NULL, NULL);
SPDK_CU_ASSERT_FATAL(task5 != NULL);
task5->scsi.transfer_len = SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH;
iscsi_task_set_pdu(task5, pdu5);
task5->tag = 15;
rc = add_transfer_task(&conn, task5);
CU_ASSERT(rc == 0);
CU_ASSERT(get_transfer_task(&conn, 1) == &task1);
CU_ASSERT(get_transfer_task(&conn, 1) == task1);
CU_ASSERT(get_transfer_task(&conn, 5) == NULL);
iscsi_del_transfer_task(&conn, 11);
CU_ASSERT(get_transfer_task(&conn, 1) == NULL);
CU_ASSERT(get_transfer_task(&conn, 5) == &task5);
CU_ASSERT(get_transfer_task(&conn, 5) == task5);
CU_ASSERT(get_transfer_task(&conn, 2) == &task2);
CU_ASSERT(get_transfer_task(&conn, 2) == task2);
iscsi_del_transfer_task(&conn, 12);
CU_ASSERT(get_transfer_task(&conn, 2) == NULL);
CU_ASSERT(get_transfer_task(&conn, 3) == &task3);
CU_ASSERT(get_transfer_task(&conn, 3) == task3);
iscsi_del_transfer_task(&conn, 13);
CU_ASSERT(get_transfer_task(&conn, 3) == NULL);
CU_ASSERT(get_transfer_task(&conn, 4) == &task4);
CU_ASSERT(get_transfer_task(&conn, 4) == task4);
iscsi_del_transfer_task(&conn, 14);
CU_ASSERT(get_transfer_task(&conn, 4) == NULL);
CU_ASSERT(get_transfer_task(&conn, 5) == &task5);
CU_ASSERT(get_transfer_task(&conn, 5) == task5);
iscsi_del_transfer_task(&conn, 15);
CU_ASSERT(get_transfer_task(&conn, 5) == NULL);
while (!TAILQ_EMPTY(&conn.active_r2t_tasks)) {
task = TAILQ_FIRST(&conn.active_r2t_tasks);
TAILQ_REMOVE(&conn.active_r2t_tasks, task, link);
}
CU_ASSERT(TAILQ_EMPTY(&conn.active_r2t_tasks));
while (!TAILQ_EMPTY(&g_write_pdu_list)) {
pdu = TAILQ_FIRST(&g_write_pdu_list);