From 91cc1e4197f3536f53f9bf0fb6ca56502c3540c9 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Fri, 25 Apr 2025 11:05:37 +1000 Subject: [PATCH] Protect outqueue and waitpdu with a spinlock Signed-off-by: Ronnie Sahlberg --- include/iscsi-private.h | 9 +- lib/connect.c | 13 +- lib/init.c | 2 + lib/iscsi-command.c | 48 ++++-- lib/iser.c | 20 ++- lib/nop.c | 2 + lib/pdu.c | 307 +++++++++++++++++++++++--------------- lib/socket.c | 28 ++-- test-tool/iscsi-support.c | 2 + 9 files changed, 271 insertions(+), 160 deletions(-) diff --git a/include/iscsi-private.h b/include/iscsi-private.h index 918b192..f68a37a 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -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; diff --git a/lib/connect.c b/lib/connect.c index 2d3b85d..4dc98f6 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -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); diff --git a/lib/init.c b/lib/init.c index 0c27271..fcae7f3 100644 --- a/lib/init.c +++ b/lib/init.c @@ -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; diff --git a/lib/iscsi-command.c b/lib/iscsi-command.c index 047cd8f..5fe6135 100644 --- a/lib/iscsi-command.c +++ b/lib/iscsi-command.c @@ -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); diff --git a/lib/iser.c b/lib/iser.c index 025bf6b..c1a6350 100644 --- a/lib/iser.c +++ b/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); diff --git a/lib/nop.c b/lib/nop.c index e59f169..9e62fae 100644 --- a/lib/nop.c +++ b/lib/nop.c @@ -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; diff --git a/lib/pdu.c b/lib/pdu.c index 935972a..3c0aa71 100644 --- a/lib/pdu.c +++ b/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, diff --git a/lib/socket.c b/lib/socket.c index ce10811..ce7fd0f 100644 --- a/lib/socket.c +++ b/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; diff --git a/test-tool/iscsi-support.c b/test-tool/iscsi-support.c index 9375952..117017e 100644 --- a/test-tool/iscsi-support.c +++ b/test-tool/iscsi-support.c @@ -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;