Drain DATAOUT PDU on timeout
Describe the reason again:
A WRITE16 command[w] handles R2T, and queues DATAOUT PDU m,x,y,z:
outqueue->DATAOUT[x]->DATAOUT[y]->DATAOUT[z]...
outqueue_current->DATAOUT[m]
waitqueue->WRITE16[w]...
1, Once x, y, z gets released in initiator side, the target still expects the remaining
DATAOUT PDUs.
2, Once command w timeout and callback to uplayer, uplayers usually releases memory of
iscsi task(include memory referenced by iovec.iov_base). DATAOUT[m] would access
invalid memory iovce.iov_base.
So invoke WRITEx command callback until draining DATAOUT PDUs.
Co-developed-by: Rui Zhang <zhangrui.1203@bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
This commit is contained in:
54
lib/pdu.c
54
lib/pdu.c
@@ -715,6 +715,55 @@ iscsi_pdu_set_expxferlen(struct iscsi_pdu *pdu, uint32_t expxferlen)
|
|||||||
scsi_set_uint32(&pdu->outdata.data[20], expxferlen);
|
scsi_set_uint32(&pdu->outdata.data[20], expxferlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A WRITE16 command[w] handles R2T, and queues DATAOUT PDU m,x,y,z:
|
||||||
|
*
|
||||||
|
* outqueue->DATAOUT[x]->DATAOUT[y]->DATAOUT[z]...
|
||||||
|
* outqueue_current->DATAOUT[m]
|
||||||
|
* waitqueue->WRITE16[w]...
|
||||||
|
*
|
||||||
|
* 1, Once x, y, z gets released in initiator side, the target still expects the remaining
|
||||||
|
* DATAOUT PDUs.
|
||||||
|
* 2, Once command w timeout and callback to uplayer, uplayers usually releases memory of
|
||||||
|
* iscsi task(include memory referenced by iovec.iov_base). DATAOUT[m] would access
|
||||||
|
* invalid memory iovce.iov_base.
|
||||||
|
*/
|
||||||
|
static int iscsi_pdu_data_out_inprocess(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
|
||||||
|
{
|
||||||
|
struct iscsi_pdu *tmp_pdu, *next_pdu;
|
||||||
|
enum scsi_opcode opcode = pdu->outdata.data[32];
|
||||||
|
|
||||||
|
/* only care DATA OUT command here */
|
||||||
|
if ((pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_SCSI_REQUEST) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case SCSI_OPCODE_WRITE10:
|
||||||
|
case SCSI_OPCODE_WRITE12:
|
||||||
|
case SCSI_OPCODE_WRITE16:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* current outgoing one is part of the PDU? */
|
||||||
|
if (iscsi->outqueue_current && (iscsi->outqueue_current->scsi_cbdata.task == pdu->scsi_cbdata.task)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* any child DATAOUT PDU in outqueue? */
|
||||||
|
for (tmp_pdu = iscsi->outqueue; tmp_pdu; tmp_pdu = next_pdu) {
|
||||||
|
next_pdu = tmp_pdu->next;
|
||||||
|
|
||||||
|
if (tmp_pdu->scsi_cbdata.task == pdu->scsi_cbdata.task) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
iscsi_timeout_scan(struct iscsi_context *iscsi)
|
iscsi_timeout_scan(struct iscsi_context *iscsi)
|
||||||
{
|
{
|
||||||
@@ -741,6 +790,8 @@ iscsi_timeout_scan(struct iscsi_context *iscsi)
|
|||||||
(pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_DATA_OUT) {
|
(pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_DATA_OUT) {
|
||||||
iscsi->cmdsn--;
|
iscsi->cmdsn--;
|
||||||
cmdsn_gap++;
|
cmdsn_gap++;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
|
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
|
||||||
iscsi_set_error(iscsi, "command timed out from outqueue");
|
iscsi_set_error(iscsi, "command timed out from outqueue");
|
||||||
@@ -762,6 +813,9 @@ iscsi_timeout_scan(struct iscsi_context *iscsi)
|
|||||||
/* not expired yet */
|
/* not expired yet */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (iscsi_pdu_data_out_inprocess(iscsi, pdu)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
|
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
|
||||||
iscsi_set_error(iscsi, "command timed out from waitqueue");
|
iscsi_set_error(iscsi, "command timed out from waitqueue");
|
||||||
iscsi_dump_pdu_header(iscsi, pdu->outdata.data);
|
iscsi_dump_pdu_header(iscsi, pdu->outdata.data);
|
||||||
|
|||||||
Reference in New Issue
Block a user