Skip to content

Commit

Permalink
Merge pull request #404 from pizhenwei/drain-dataout-pdu-on-timeout
Browse files Browse the repository at this point in the history
Drain DATAOUT PDU on timeout
  • Loading branch information
sahlberg authored Nov 22, 2023
2 parents 03e9ddc + addb11d commit fdd00ee
Showing 1 changed file with 54 additions and 0 deletions.
54 changes: 54 additions & 0 deletions lib/pdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,55 @@ iscsi_pdu_set_expxferlen(struct iscsi_pdu *pdu, uint32_t 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
iscsi_timeout_scan(struct iscsi_context *iscsi)
{
Expand All @@ -741,6 +790,8 @@ iscsi_timeout_scan(struct iscsi_context *iscsi)
(pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_DATA_OUT) {
iscsi->cmdsn--;
cmdsn_gap++;
} else {
continue;
}
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
iscsi_set_error(iscsi, "command timed out from outqueue");
Expand All @@ -762,6 +813,9 @@ iscsi_timeout_scan(struct iscsi_context *iscsi)
/* not expired yet */
continue;
}
if (iscsi_pdu_data_out_inprocess(iscsi, pdu)) {
continue;
}
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_set_error(iscsi, "command timed out from waitqueue");
iscsi_dump_pdu_header(iscsi, pdu->outdata.data);
Expand Down

0 comments on commit fdd00ee

Please sign in to comment.