Protect outqueue and waitpdu with a spinlock
Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
20
lib/iser.c
20
lib/iser.c
@@ -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);
|
||||
|
||||
|
||||
@@ -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
307
lib/pdu.c
@@ -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,
|
||||
|
||||
28
lib/socket.c
28
lib/socket.c
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user