lib/iscsi: Remove iSCSI task left in PDU receive process due to connection exit
Previously iSCSI task was created after allocating data buffer and reading all data, and hence creating iSCSI task and processing iSCSI task were not separated. However, the recent refactoring separate PDU header handling and PDU payload handling, and then inserted allocating data buffer and reading data segment in the middle. If any critical error occurs during allocating data buffer or reading data segment, PDU payload handling is not done, and hence created iSCSI task is left in PDU receive process. If any critical error occurs, the current connection starts exiting and there is no way to continue PDU receive process. The task left in PDU receive process is never freed, and hence LUN hotplug or exiting connection never complete. This patch do the following: - Consolidate freeing pre-allocated PDU to spdk_iscsi_conn_destruct() because this is the only path to exit connection. - Abort SCSI task of the task left in PDU receive process if found when freeing pre-allocated PDU. If the task is not SCSI or Data Out, remove it simply. Fix issues #1018. Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Change-Id: I8a2464c446c43bf4cfb5afbc0cd78b5bdef7d080 Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/472896 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
parent
832d90c1e2
commit
cd654cc512
@ -377,12 +377,6 @@ _iscsi_conn_free(struct spdk_iscsi_conn *conn)
|
||||
|
||||
spdk_iscsi_param_free(conn->params);
|
||||
|
||||
/*
|
||||
* Each connection pre-allocates its next PDU - make sure these get
|
||||
* freed here.
|
||||
*/
|
||||
spdk_put_pdu(conn->pdu_in_progress);
|
||||
|
||||
free_conn(conn);
|
||||
}
|
||||
|
||||
@ -675,6 +669,10 @@ _iscsi_conn_check_pending_tasks(void *arg)
|
||||
void
|
||||
spdk_iscsi_conn_destruct(struct spdk_iscsi_conn *conn)
|
||||
{
|
||||
struct spdk_iscsi_pdu *pdu;
|
||||
struct spdk_iscsi_task *task;
|
||||
int opcode;
|
||||
|
||||
/* If a connection is already in exited status, just return */
|
||||
if (conn->state >= ISCSI_CONN_STATE_EXITED) {
|
||||
return;
|
||||
@ -682,6 +680,32 @@ spdk_iscsi_conn_destruct(struct spdk_iscsi_conn *conn)
|
||||
|
||||
conn->state = ISCSI_CONN_STATE_EXITED;
|
||||
|
||||
/*
|
||||
* Each connection pre-allocates its next PDU - make sure these get
|
||||
* freed here.
|
||||
*/
|
||||
pdu = conn->pdu_in_progress;
|
||||
if (pdu) {
|
||||
/* remove the task left in the PDU too. */
|
||||
task = pdu->task;
|
||||
if (task) {
|
||||
opcode = pdu->bhs.opcode;
|
||||
switch (opcode) {
|
||||
case ISCSI_OP_SCSI:
|
||||
case ISCSI_OP_SCSI_DATAOUT:
|
||||
spdk_scsi_task_process_abort(&task->scsi);
|
||||
spdk_iscsi_task_cpl(&task->scsi);
|
||||
break;
|
||||
default:
|
||||
SPDK_ERRLOG("unexpected opcode %x\n", opcode);
|
||||
spdk_iscsi_task_put(task);
|
||||
break;
|
||||
}
|
||||
}
|
||||
spdk_put_pdu(pdu);
|
||||
conn->pdu_in_progress = NULL;
|
||||
}
|
||||
|
||||
if (conn->sess != NULL && conn->pending_task_cnt > 0) {
|
||||
iscsi_conn_cleanup_backend(conn);
|
||||
}
|
||||
|
@ -4970,8 +4970,6 @@ iscsi_read_pdu(struct spdk_iscsi_conn *conn)
|
||||
}
|
||||
break;
|
||||
case ISCSI_PDU_RECV_STATE_ERROR:
|
||||
spdk_put_pdu(pdu);
|
||||
conn->pdu_in_progress = NULL;
|
||||
return SPDK_ISCSI_CONNECTION_FATAL;
|
||||
default:
|
||||
assert(false);
|
||||
|
Loading…
Reference in New Issue
Block a user