Protect outqueue and waitpdu with a spinlock

Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
This commit is contained in:
Ronnie Sahlberg
2025-04-25 11:05:37 +10:00
parent 4593746363
commit 91cc1e4197
9 changed files with 271 additions and 160 deletions

View File

@@ -170,11 +170,10 @@ struct iscsi_context {
iscsi_command_cb socket_status_cb;
void *connect_data;
struct iscsi_pdu *outqueue; // multithreading todo: may need mutex
struct iscsi_pdu *outqueue_current; // multithreading todo: may need mutex
struct iscsi_pdu *waitpdu; // multithreading todo: may need mutex
struct iscsi_in_pdu *incoming; // multithreading todo: may need mutex
struct iscsi_pdu *outqueue; /* Protected by iscsi_lock */
struct iscsi_pdu *outqueue_current; /* Protected by iscsi_lock */
struct iscsi_pdu *waitpdu; /* Protected by iscsi_lock */
struct iscsi_in_pdu *incoming; /* Protected by iscsi_lock */
uint32_t max_burst_length;
uint32_t first_burst_length;

View File

@@ -280,6 +280,7 @@ void iscsi_reconnect_cb(struct iscsi_context *iscsi, int status,
void *command_data, void *private_data)
{
struct iscsi_context *old_iscsi;
struct iscsi_pdu *tmp = NULL;
int i;
if (status != SCSI_STATUS_GOOD) {
@@ -305,16 +306,20 @@ void iscsi_reconnect_cb(struct iscsi_context *iscsi, int status,
old_iscsi = iscsi->old_iscsi;
iscsi->old_iscsi = NULL;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
while (old_iscsi->outqueue) {
struct iscsi_pdu *pdu = old_iscsi->outqueue;
ISCSI_LIST_REMOVE(&old_iscsi->outqueue, pdu);
ISCSI_LIST_ADD_END(&old_iscsi->waitpdu, pdu);
}
tmp = old_iscsi->waitpdu;
old_iscsi->waitpdu = NULL;
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
while (old_iscsi->waitpdu) {
struct iscsi_pdu *pdu = old_iscsi->waitpdu;
while (tmp) {
struct iscsi_pdu *pdu = tmp;
ISCSI_LIST_REMOVE(&old_iscsi->waitpdu, pdu);
ISCSI_LIST_REMOVE(&tmp, pdu);
if (pdu->itt == 0xffffffff) {
iscsi->drv->free_pdu(old_iscsi, pdu);
continue;
@@ -351,6 +356,7 @@ void iscsi_reconnect_cb(struct iscsi_context *iscsi, int status,
iscsi->drv->free_pdu(old_iscsi, pdu);
}
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
if (old_iscsi->incoming != NULL) {
iscsi_free_iscsi_in_pdu(old_iscsi, old_iscsi->incoming);
}
@@ -358,6 +364,7 @@ void iscsi_reconnect_cb(struct iscsi_context *iscsi, int status,
if (old_iscsi->outqueue_current != NULL && old_iscsi->outqueue_current->flags & ISCSI_PDU_DELETE_WHEN_SENT) {
iscsi->drv->free_pdu(old_iscsi, old_iscsi->outqueue_current);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi_free(old_iscsi, old_iscsi->opaque);

View File

@@ -407,6 +407,7 @@ iscsi_destroy_context(struct iscsi_context *iscsi)
iscsi_cancel_pdus(iscsi);
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
if (iscsi->outqueue_current != NULL && iscsi->outqueue_current->flags & ISCSI_PDU_DELETE_WHEN_SENT) {
iscsi->drv->free_pdu(iscsi, iscsi->outqueue_current);
}
@@ -414,6 +415,7 @@ iscsi_destroy_context(struct iscsi_context *iscsi)
if (iscsi->incoming != NULL) {
iscsi_free_iscsi_in_pdu(iscsi, iscsi->incoming);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->connect_data = NULL;

View File

@@ -136,8 +136,10 @@ iscsi_send_data_out(struct iscsi_context *iscsi, struct iscsi_pdu *cmd_pdu,
return 0;
error:
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->outqueue, cmd_pdu);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, cmd_pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
if (cmd_pdu->callback) {
cmd_pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
cmd_pdu->private_data);
@@ -2406,11 +2408,13 @@ iscsi_get_scsi_task_iovector_in(struct iscsi_context *iscsi, struct iscsi_in_pdu
}
itt = scsi_get_uint32(&in->hdr[16]);
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
if (pdu->itt == itt) {
break;
}
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
if (pdu == NULL) {
return NULL;
@@ -2669,11 +2673,14 @@ int iscsi_scsi_is_task_in_outqueue(struct iscsi_context *iscsi, struct scsi_task
{
struct iscsi_pdu *pdu;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->outqueue; pdu; pdu = pdu->next) {
if (pdu->itt == task->itt) {
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return 1;
}
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return 0;
}
@@ -2682,13 +2689,15 @@ int
iscsi_scsi_cancel_task(struct iscsi_context *iscsi,
struct scsi_task *task)
{
struct iscsi_pdu *pdu;
struct iscsi_pdu *pdu, *tmp;
struct iscsi_pdu *next_pdu;
uint32_t cmdsn_gap = 0;
int ret = -1;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
if (pdu->itt == task->itt) {
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
if (pdu->callback) {
pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL,
@@ -2698,6 +2707,8 @@ iscsi_scsi_cancel_task(struct iscsi_context *iscsi,
return 0;
}
}
tmp = NULL;
for (pdu = iscsi->outqueue; pdu; pdu = next_pdu) {
next_pdu = pdu->next;
@@ -2707,22 +2718,27 @@ iscsi_scsi_cancel_task(struct iscsi_context *iscsi,
if (pdu->itt == task->itt) {
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
if (pdu->callback) {
pdu->callback(iscsi, SCSI_STATUS_CANCELLED, NULL,
ISCSI_LIST_ADD_END(&tmp, pdu);
}
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
for (pdu = tmp; pdu; pdu = next_pdu) {
ISCSI_LIST_REMOVE(&tmp, 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);
ret = 0;
if (!cmdsn_gap) {
break;
}
}
}
}
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);
ret = 0;
if (!cmdsn_gap) {
break;
}
}
if (iscsi->old_iscsi) {
return iscsi_scsi_cancel_task(iscsi->old_iscsi, task);

View File

@@ -334,6 +334,7 @@ iser_free_queued_pdu_tx_desc(struct iscsi_context *iscsi)
struct iscsi_pdu *pdu;
struct iser_pdu *iser_pdu;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
iser_pdu = container_of(pdu, struct iser_pdu, iscsi_pdu);
if (iser_pdu->desc) {
@@ -349,6 +350,7 @@ iser_free_queued_pdu_tx_desc(struct iscsi_context *iscsi)
iser_pdu->desc = NULL;
}
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
}
/*
@@ -576,9 +578,11 @@ iscsi_iser_free_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
pdu->indata.data = NULL;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
if (iscsi->outqueue_current == pdu) {
iscsi->outqueue_current = NULL;
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi_sfree(iscsi, iser_pdu);
}
@@ -920,8 +924,10 @@ iscsi_iser_send_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) {
iser_pdu = container_of(pdu, struct iser_pdu, iscsi_pdu);
opcode = pdu->outdata.data[0];
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
iscsi_pdu_set_expstatsn(pdu, iscsi->statsn + 1);
ISCSI_LIST_ADD_END(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
/*
* because of async reconnection, before reconnecting successfully,
@@ -954,16 +960,20 @@ static int
iscsi_iser_revive_queued_pdus(struct iscsi_context *iscsi) {
struct iscsi_pdu *pdu;
while (iscsi->outqueue != NULL) {
while (iscsi->outqueue) {
if (iscsi_serial32_compare(iscsi->outqueue->cmdsn, iscsi->maxcmdsn) > 0) {
break;
}
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
pdu = iscsi->outqueue;
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
if (iscsi_iser_send_pdu(iscsi, pdu) < 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_ADD(&iscsi->outqueue, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return -1;
}
}
@@ -995,7 +1005,7 @@ iscsi_iser_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) {
return;
}
if (iscsi->outqueue != NULL ||
if (iscsi->outqueue ||
(iscsi_serial32_compare(pdu->cmdsn, iscsi->maxcmdsn) > 0
&& !(pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE))) {
iscsi_add_to_outqueue(iscsi, pdu);
@@ -1308,6 +1318,8 @@ iser_rcv_completion(struct iser_rx_desc *rx_desc,
struct iscsi_in_pdu in;
int empty, err;
struct iscsi_context *iscsi = iser_conn->cma_id->context;
struct iscsi_pdu *iscsi_pdu;
struct iser_pdu *iser_pdu;
in.hdr = (unsigned char*)rx_desc->iscsi_header;
in.data_pos = iscsi_get_pdu_data_size(&in.hdr[0]);
@@ -1322,12 +1334,12 @@ iser_rcv_completion(struct iser_rx_desc *rx_desc,
if (opcode == ISCSI_PDU_ASYNC_MSG)
goto no_waitpdu;
struct iscsi_pdu *iscsi_pdu;
struct iser_pdu *iser_pdu;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (iscsi_pdu = iscsi->waitpdu ; iscsi_pdu ; iscsi_pdu = iscsi_pdu->next) {
if(iscsi_pdu->itt == itt)
break;
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iser_pdu = container_of(iscsi_pdu, struct iser_pdu, iscsi_pdu);

View File

@@ -133,6 +133,7 @@ iscsi_process_nop_out_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
{
struct iscsi_data data;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LOG(iscsi, (iscsi->nops_in_flight > 1) ? 1 : 6,
"NOP-In received (pdu->itt %08x, pdu->ttt %08x, iscsi->maxcmdsn %08x, iscsi->expcmdsn %08x, iscsi->statsn %08x)",
pdu->itt, 0xffffffff, iscsi->maxcmdsn, iscsi->expcmdsn, iscsi->statsn);
@@ -147,6 +148,7 @@ iscsi_process_nop_out_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
iscsi->nops_in_flight = 0;
}
iscsi->min_cmdsn_waiting = iscsi->waitpdu->cmdsn;
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
if (pdu->callback == NULL) {
return 0;

307
lib/pdu.c
View File

@@ -458,11 +458,13 @@ int iscsi_process_reject(struct iscsi_context *iscsi,
iscsi_dump_pdu_header(iscsi, in->data);
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
if (pdu->itt == itt) {
break;
}
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
if (pdu == NULL) {
iscsi_set_error(iscsi, "Can not match REJECT with"
@@ -476,7 +478,9 @@ int iscsi_process_reject(struct iscsi_context *iscsi,
pdu->private_data);
}
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
return 0;
}
@@ -525,6 +529,8 @@ iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in)
enum iscsi_opcode opcode = in->hdr[0] & 0x3f;
uint8_t ahslen = in->hdr[4];
struct iscsi_pdu *pdu;
enum iscsi_opcode expected_response;
int is_finished = 1;
/* verify header checksum */
if (iscsi->header_digest != ISCSI_HEADER_DIGEST_NONE) {
@@ -623,125 +629,148 @@ iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in)
return 0;
}
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
enum iscsi_opcode expected_response = pdu->response_opcode;
int is_finished = 1;
if (pdu->itt != itt) {
continue;
if (pdu->itt == itt) {
break;
}
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
if (pdu == NULL) {
iscsi_set_error(iscsi, "Got unsolicited response with "
"itt:%d",
itt);
return -1;
}
/* we have a special case with scsi-command opcodes,
* they are replied to by either a scsi-response
* or a data-in, or a combination of both.
*/
expected_response = pdu->response_opcode;
if (opcode == ISCSI_PDU_DATA_IN
&& expected_response == ISCSI_PDU_SCSI_RESPONSE) {
expected_response = ISCSI_PDU_DATA_IN;
}
/* we have a special case with scsi-command opcodes,
* they are replied to by either a scsi-response
* or a data-in, or a combination of both.
*/
if (opcode == ISCSI_PDU_DATA_IN
&& expected_response == ISCSI_PDU_SCSI_RESPONSE) {
expected_response = ISCSI_PDU_DATA_IN;
}
/* Another special case is if we get a R2T.
* In this case we should find the original request and just send an additional
* DATAOUT segment for this task.
*/
if (opcode == ISCSI_PDU_R2T) {
expected_response = ISCSI_PDU_R2T;
}
/* Another special case is if we get a R2T.
* In this case we should find the original request and just send an additional
* DATAOUT segment for this task.
*/
if (opcode == ISCSI_PDU_R2T) {
expected_response = ISCSI_PDU_R2T;
}
if (opcode != expected_response) {
iscsi_set_error(iscsi, "Got wrong opcode back for "
"itt:%d got:%d expected %d",
itt, opcode, pdu->response_opcode);
return -1;
}
switch (opcode) {
case ISCSI_PDU_LOGIN_RESPONSE:
if (iscsi_process_login_reply(iscsi, pdu, in) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi login reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_TEXT_RESPONSE:
if (iscsi_process_text_reply(iscsi, pdu, in) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi text reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_LOGOUT_RESPONSE:
if (iscsi_process_logout_reply(iscsi, pdu, in) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi logout reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_SCSI_RESPONSE:
if (iscsi_process_scsi_reply(iscsi, pdu, in) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi response reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_DATA_IN:
if (iscsi_process_scsi_data_in(iscsi, pdu, in,
&is_finished) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi data in "
"failed");
return -1;
}
break;
case ISCSI_PDU_NOP_IN:
if (iscsi_process_nop_out_reply(iscsi, pdu, in) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi nop-in failed");
return -1;
}
break;
case ISCSI_PDU_SCSI_TASK_MANAGEMENT_RESPONSE:
if (iscsi_process_task_mgmt_reply(iscsi, pdu,
in) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi task-mgmt failed");
return -1;
}
break;
case ISCSI_PDU_R2T:
if (iscsi_process_r2t(iscsi, pdu, in) != 0) {
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi r2t "
"failed");
return -1;
}
is_finished = 0;
break;
default:
iscsi_set_error(iscsi, "Don't know how to handle "
"opcode 0x%02x", opcode);
return -1;
}
if (opcode != expected_response) {
iscsi_set_error(iscsi, "Got wrong opcode back for "
"itt:%d got:%d expected %d",
itt, opcode, pdu->response_opcode);
return -1;
}
switch (opcode) {
case ISCSI_PDU_LOGIN_RESPONSE:
if (iscsi_process_login_reply(iscsi, pdu, in) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi login reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_TEXT_RESPONSE:
if (iscsi_process_text_reply(iscsi, pdu, in) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi text reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_LOGOUT_RESPONSE:
if (iscsi_process_logout_reply(iscsi, pdu, in) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi logout reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_SCSI_RESPONSE:
if (iscsi_process_scsi_reply(iscsi, pdu, in) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi response reply "
"failed");
return -1;
}
break;
case ISCSI_PDU_DATA_IN:
if (iscsi_process_scsi_data_in(iscsi, pdu, in,
&is_finished) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi data in "
"failed");
return -1;
}
break;
case ISCSI_PDU_NOP_IN:
if (iscsi_process_nop_out_reply(iscsi, pdu, in) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi nop-in failed");
return -1;
}
break;
case ISCSI_PDU_SCSI_TASK_MANAGEMENT_RESPONSE:
if (iscsi_process_task_mgmt_reply(iscsi, pdu,
in) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi task-mgmt failed");
return -1;
}
break;
case ISCSI_PDU_R2T:
if (iscsi_process_r2t(iscsi, pdu, in) != 0) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi r2t "
"failed");
return -1;
}
is_finished = 0;
break;
default:
iscsi_set_error(iscsi, "Don't know how to handle "
"opcode 0x%02x", opcode);
return -1;
}
if (is_finished && iscsi->waitpdu != NULL) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
}
return 0;
}
return 0;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
if (is_finished && iscsi->waitpdu != NULL) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi->drv->free_pdu(iscsi, pdu);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return 0;
}
void
@@ -842,7 +871,8 @@ static int iscsi_pdu_data_out_inprocess(struct iscsi_context *iscsi, struct iscs
{
struct iscsi_pdu *tmp_pdu, *next_pdu;
enum scsi_opcode opcode = pdu->outdata.data[32];
int ret = 1;
/* only care DATA OUT command here */
if ((pdu->outdata.data[0] & 0x3f) != ISCSI_PDU_SCSI_REQUEST) {
return 0;
@@ -857,9 +887,10 @@ static int iscsi_pdu_data_out_inprocess(struct iscsi_context *iscsi, struct iscs
return 0;
};
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
/* current outgoing one is part of the PDU? */
if (iscsi->outqueue_current && (iscsi->outqueue_current->scsi_cbdata.task == pdu->scsi_cbdata.task)) {
return 1;
goto finished;
}
/* any child DATAOUT PDU in outqueue? */
@@ -867,21 +898,26 @@ static int iscsi_pdu_data_out_inprocess(struct iscsi_context *iscsi, struct iscs
next_pdu = tmp_pdu->next;
if (tmp_pdu->scsi_cbdata.task == pdu->scsi_cbdata.task) {
return 1;
goto finished;
}
}
return 0;
ret = 0;
finished:
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return ret;
}
void
iscsi_timeout_scan(struct iscsi_context *iscsi)
{
struct iscsi_pdu *pdu;
struct iscsi_pdu *pdu, *tmp;
struct iscsi_pdu *next_pdu;
time_t t = time(NULL);
uint32_t cmdsn_gap = 0;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
tmp = NULL;
for (pdu = iscsi->outqueue; pdu; pdu = next_pdu) {
next_pdu = pdu->next;
@@ -904,6 +940,11 @@ iscsi_timeout_scan(struct iscsi_context *iscsi)
continue;
}
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
ISCSI_LIST_ADD_END(&tmp, pdu);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
for (pdu = tmp; pdu; pdu = next_pdu) {
ISCSI_LIST_REMOVE(&tmp, pdu);
iscsi_set_error(iscsi, "command timed out from outqueue");
iscsi_dump_pdu_header(iscsi, pdu->outdata.data);
if (pdu->callback) {
@@ -912,6 +953,9 @@ iscsi_timeout_scan(struct iscsi_context *iscsi)
}
iscsi->drv->free_pdu(iscsi, pdu);
}
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
tmp = NULL;
for (pdu = iscsi->waitpdu; pdu; pdu = next_pdu) {
next_pdu = pdu->next;
@@ -927,6 +971,11 @@ iscsi_timeout_scan(struct iscsi_context *iscsi)
continue;
}
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
ISCSI_LIST_ADD_END(&tmp, pdu);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
for (pdu = tmp; pdu; pdu = next_pdu) {
ISCSI_LIST_REMOVE(&tmp, pdu);
iscsi_set_error(iscsi, "command timed out from waitqueue");
iscsi_dump_pdu_header(iscsi, pdu->outdata.data);
if (pdu->callback) {
@@ -946,8 +995,9 @@ iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
void
iscsi_cancel_pdus(struct iscsi_context *iscsi)
{
struct iscsi_pdu *pdu;
struct iscsi_pdu *pdu, *tmp;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
while ((pdu = iscsi->outqueue)) {
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
if (pdu->callback) {
@@ -960,8 +1010,12 @@ iscsi_cancel_pdus(struct iscsi_context *iscsi)
}
iscsi->drv->free_pdu(iscsi, pdu);
}
while ((pdu = iscsi->waitpdu)) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
tmp = iscsi->waitpdu;
iscsi->waitpdu = NULL;
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
while ((pdu = tmp)) {
ISCSI_LIST_REMOVE(&tmp, pdu);
if (pdu->callback) {
pdu->callback(iscsi, SCSI_STATUS_CANCELLED,
NULL, pdu->private_data);
@@ -973,11 +1027,13 @@ iscsi_cancel_pdus(struct iscsi_context *iscsi)
void
iscsi_cancel_lun_pdus(struct iscsi_context *iscsi, uint32_t lun)
{
struct iscsi_pdu *pdu;
struct iscsi_pdu *pdu, *tmp;
struct iscsi_pdu *next_pdu;
uint32_t cmdsn_gap = 0;
struct scsi_task * task = NULL;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
tmp = NULL;
for (pdu = iscsi->outqueue; pdu; pdu = next_pdu) {
next_pdu = pdu->next;
task = iscsi_scsi_get_task_from_pdu(pdu);
@@ -994,6 +1050,11 @@ iscsi_cancel_lun_pdus(struct iscsi_context *iscsi, uint32_t lun)
cmdsn_gap++;
}
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
ISCSI_LIST_ADD_END(&tmp, pdu);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
for (pdu = tmp; pdu; pdu = next_pdu) {
ISCSI_LIST_REMOVE(&tmp, pdu);
iscsi_set_error(iscsi, "command cancelled");
if (pdu->callback) {
pdu->callback(iscsi, SCSI_STATUS_CANCELLED,

View File

@@ -101,7 +101,7 @@ iscsi_add_to_outqueue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
pdu->scsi_timeout = 0;
}
iscsi_mt_mutex_lock(&iscsi->iscsi_mutex);
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
current = iscsi->outqueue;
if (iscsi->outqueue == NULL) {
@@ -133,22 +133,22 @@ iscsi_add_to_outqueue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
(pdu->outdata.data[0] & ISCSI_PDU_IMMEDIATE && !(current->outdata.data[0] & ISCSI_PDU_IMMEDIATE))) {
/* insert PDU before the current */
if (last != NULL) {
last->next=pdu;
last->next = pdu;
} else {
iscsi->outqueue=pdu;
iscsi->outqueue = pdu;
}
pdu->next = current;
goto finished;
}
last=current;
current=current->next;
last = current;
current = current->next;
} while (current != NULL);
last->next = pdu;
pdu->next = NULL;
finished:
iscsi_mt_mutex_unlock(&iscsi->iscsi_mutex);
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
/* TODO QQQ need to immediately send for the non multithreading case too
* and for the Windows API too */
@@ -491,14 +491,16 @@ iscsi_tcp_which_events(struct iscsi_context *iscsi)
return 0;
}
if (iscsi->outqueue_current != NULL ||
(iscsi->outqueue != NULL && !iscsi->is_corked &&
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
if (iscsi->outqueue_current ||
(iscsi->outqueue && !iscsi->is_corked &&
(iscsi_serial32_compare(iscsi->outqueue->cmdsn, iscsi->maxcmdsn) <= 0 ||
iscsi->outqueue->outdata.data[0] & ISCSI_PDU_IMMEDIATE)
)
) {
events |= POLLOUT;
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return events;
}
@@ -514,6 +516,7 @@ iscsi_queue_length(struct iscsi_context *iscsi)
int i = 0;
struct iscsi_pdu *pdu;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->outqueue; pdu; pdu = pdu->next) {
i++;
}
@@ -523,6 +526,7 @@ iscsi_queue_length(struct iscsi_context *iscsi)
if (iscsi->is_connected == 0) {
i++;
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return i;
}
@@ -533,9 +537,11 @@ iscsi_out_queue_length(struct iscsi_context *iscsi)
int i = 0;
struct iscsi_pdu *pdu;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
for (pdu = iscsi->outqueue; pdu; pdu = pdu->next) {
i++;
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return i;
}
@@ -830,7 +836,7 @@ iscsi_write_to_socket(struct iscsi_context *iscsi)
return -1;
}
while (iscsi->outqueue != NULL || iscsi->outqueue_current != NULL) {
while (iscsi->outqueue || iscsi->outqueue_current) {
if (iscsi->outqueue_current == NULL) {
if (iscsi->is_corked) {
/* connection is corked we are not allowed to send
@@ -855,6 +861,8 @@ iscsi_write_to_socket(struct iscsi_context *iscsi)
iscsi->outqueue->cmdsn, iscsi->expcmdsn, iscsi->outqueue->outdata.data[0] & 0x3f);
return -1;
}
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
iscsi->outqueue_current = iscsi->outqueue;
/* set exp statsn */
@@ -863,6 +871,7 @@ iscsi_write_to_socket(struct iscsi_context *iscsi)
/* calculate header checksum */
if (iscsi->header_digest != ISCSI_HEADER_DIGEST_NONE &&
iscsi_pdu_update_headerdigest(iscsi, iscsi->outqueue_current) != 0) {
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return -1;
}
@@ -874,6 +883,7 @@ iscsi_write_to_socket(struct iscsi_context *iscsi)
cmd PDU the R2T might get lost otherwise. */
ISCSI_LIST_ADD_END(&iscsi->waitpdu, iscsi->outqueue_current);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
}
pdu = iscsi->outqueue_current;

View File

@@ -561,6 +561,7 @@ wait_until_test_finished(struct iscsi_context *iscsi, struct iscsi_async_state *
state->finished = 1;
state->status = SCSI_STATUS_CANCELLED;
state->task->status = SCSI_STATUS_CANCELLED;
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
/* this may leak memory since we don't free the pdu */
while ((pdu = iscsi->outqueue)) {
ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
@@ -568,6 +569,7 @@ wait_until_test_finished(struct iscsi_context *iscsi, struct iscsi_async_state *
while ((pdu = iscsi->waitpdu)) {
ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
return;
}
continue;