libiscsi: Avoid discontinuities in cmdsn ordering in some cases

We should plug the cmdsn gap in order to continue
to use the session when the pdus is cancelled before
sending out.

Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
This commit is contained in:
Xie Yongji
2020-06-02 20:15:50 +08:00
parent 7258fbfd83
commit 10868c491d
3 changed files with 39 additions and 5 deletions

View File

@@ -271,7 +271,7 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun,
iscsi_pdu_set_expxferlen(pdu, task->expxferlen);
/* cmdsn */
iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn++);
iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn);
/* cdb */
iscsi_pdu_set_cdb(pdu, task);
@@ -285,6 +285,7 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun,
iscsi->drv->free_pdu(iscsi, pdu);
return -1;
}
iscsi->cmdsn++;
/* The F flag is not set. This means we haven't sent all the unsolicited
* data yet. Sent as much as we are allowed as a train of DATA-OUT PDUs.
@@ -2667,6 +2668,9 @@ iscsi_scsi_cancel_task(struct iscsi_context *iscsi,
struct scsi_task *task)
{
struct iscsi_pdu *pdu;
struct iscsi_pdu *next_pdu;
uint32_t cmdsn_gap = 0;
int ret = -1;
for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
if (pdu->itt == task->itt) {
@@ -2679,18 +2683,32 @@ iscsi_scsi_cancel_task(struct iscsi_context *iscsi,
return 0;
}
}
for (pdu = iscsi->outqueue; pdu; pdu = pdu->next) {
for (pdu = iscsi->outqueue; pdu; pdu = next_pdu) {
next_pdu = pdu->next;
if (cmdsn_gap > 0) {
iscsi_pdu_set_cmdsn(pdu, pdu->cmdsn - cmdsn_gap);
}
if (pdu->itt == task->itt) {
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
if (pdu->callback) {
pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL,
pdu->private_data);
}
if (!(pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE) &&
(pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_DATA_OUT) {
iscsi->cmdsn--;
cmdsn_gap++;
}
iscsi->drv->free_pdu(iscsi, pdu);
return 0;
ret = 0;
if (!cmdsn_gap) {
break;
}
}
}
return -1;
return ret;
}
void

View File

@@ -64,7 +64,7 @@ iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
iscsi_pdu_set_lun(pdu, 0);
/* cmdsn */
iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn++);
iscsi_pdu_set_cmdsn(pdu, iscsi->cmdsn);
pdu->callback = cb;
pdu->private_data = private_data;
@@ -83,6 +83,7 @@ iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
return -1;
}
iscsi->cmdsn++;
iscsi->nops_in_flight++;
ISCSI_LOG(iscsi, (iscsi->nops_in_flight > 1) ? 1 : 6,
"NOP Out Send (nops_in_flight: %d, pdu->cmdsn %08x, pdu->itt %08x, pdu->ttt %08x, iscsi->maxcmdsn %08x, iscsi->expcmdsn %08x)",

View File

@@ -719,10 +719,14 @@ iscsi_timeout_scan(struct iscsi_context *iscsi)
struct iscsi_pdu *pdu;
struct iscsi_pdu *next_pdu;
time_t t = time(NULL);
uint32_t cmdsn_gap = 0;
for (pdu = iscsi->outqueue; pdu; pdu = next_pdu) {
next_pdu = pdu->next;
if (cmdsn_gap > 0) {
iscsi_pdu_set_cmdsn(pdu, pdu->cmdsn - cmdsn_gap);
}
if (pdu->scsi_timeout == 0) {
/* no timeout for this pdu */
continue;
@@ -731,6 +735,11 @@ iscsi_timeout_scan(struct iscsi_context *iscsi)
/* not expired yet */
continue;
}
if (!(pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE) &&
(pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_DATA_OUT) {
iscsi->cmdsn--;
cmdsn_gap++;
}
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
iscsi_set_error(iscsi, "command timed out");
iscsi_dump_pdu_header(iscsi, pdu->outdata.data);
@@ -783,6 +792,12 @@ iscsi_cancel_pdus(struct iscsi_context *iscsi)
NULL, pdu->private_data);
}
iscsi->drv->free_pdu(iscsi, pdu);
if (!(pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE) &&
(pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_DATA_OUT) {
iscsi->cmdsn--;
}
}
while ((pdu = iscsi->waitpdu)) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);