diff --git a/include/iscsi-private.h b/include/iscsi-private.h index c65d407..1be0f61 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -103,6 +103,7 @@ struct iscsi_context { void *connect_data; struct iscsi_pdu *outqueue; + struct iscsi_pdu *outqueue_current; struct iscsi_pdu *waitpdu; struct iscsi_in_pdu *incoming; diff --git a/lib/init.c b/lib/init.c index 1451906..b08e3c3 100644 --- a/lib/init.c +++ b/lib/init.c @@ -268,6 +268,10 @@ iscsi_destroy_context(struct iscsi_context *iscsi) iscsi_free_pdu(iscsi, pdu); } + if (iscsi->outqueue_current != NULL && iscsi->outqueue_current->flags & ISCSI_PDU_DELETE_WHEN_SENT) { + iscsi_free_pdu(iscsi, iscsi->outqueue_current); + } + if (iscsi->incoming != NULL) { iscsi_free_iscsi_in_pdu(iscsi, iscsi->incoming); } diff --git a/lib/pdu.c b/lib/pdu.c index d4392e0..4ae3139 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -369,7 +369,7 @@ iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in) */ if (opcode == ISCSI_PDU_R2T) { expected_response = ISCSI_PDU_R2T; - } + } if (opcode != expected_response) { iscsi_set_error(iscsi, "Got wrong opcode back for " diff --git a/lib/socket.c b/lib/socket.c index 88f1a2a..048802a 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -65,8 +65,8 @@ iscsi_add_to_outqueue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) * queue pdus with itt = 0xffffffff (SNACK / DataACK) in order but at head of queue. */ do { - if (current->written == 0 && (iscsi_serial32_compare(pdu->itt, current->itt) < 0 - || (pdu->itt == 0xffffffff && current->itt != 0xffffffff))) { + if (iscsi_serial32_compare(pdu->itt, current->itt) < 0 + || (pdu->itt == 0xffffffff && current->itt != 0xffffffff)) { /* insert PDU before the current */ if (last != NULL) { last->next=pdu; @@ -332,7 +332,7 @@ iscsi_which_events(struct iscsi_context *iscsi) { int events = iscsi->is_connected ? POLLIN : POLLOUT; - if (iscsi->outqueue && iscsi_serial32_compare(iscsi->outqueue->cmdsn, iscsi->maxcmdsn) <= 0) { + if (iscsi->outqueue_current != NULL || (iscsi->outqueue != NULL && iscsi_serial32_compare(iscsi->outqueue->cmdsn, iscsi->maxcmdsn) <= 0)) { events |= POLLOUT; } return events; @@ -470,14 +470,28 @@ iscsi_write_to_socket(struct iscsi_context *iscsi) return -1; } - while ((pdu = iscsi->outqueue) != NULL) { + while (iscsi->outqueue != NULL || iscsi->outqueue_current != NULL) { ssize_t total; - if (iscsi_serial32_compare(iscsi->outqueue->cmdsn, iscsi->maxcmdsn) > 0) { - /* stop sending. maxcmdsn is reached */ - return 0; + if (iscsi->outqueue_current == NULL) { + if (iscsi_serial32_compare(iscsi->outqueue->cmdsn, iscsi->maxcmdsn) > 0) { + /* stop sending. maxcmdsn is reached */ + return 0; + } + /* pop first element of the outqueue */ + iscsi->outqueue_current = iscsi->outqueue; + SLIST_REMOVE(&iscsi->outqueue, iscsi->outqueue_current); + if (!(iscsi->outqueue_current->flags & ISCSI_PDU_DELETE_WHEN_SENT)) { + /* we have to add the pdu to the waitqueue already here + since the storage might sent a R2T as soon as it has + received the header. if we sent immediate data in a + cmd PDU the R2T might get lost otherwise. */ + SLIST_ADD_END(&iscsi->waitpdu, iscsi->outqueue_current); + } } + pdu = iscsi->outqueue_current; + total = pdu->outdata.size; total = (total + 3) & 0xfffffffc; @@ -530,12 +544,10 @@ iscsi_write_to_socket(struct iscsi_context *iscsi) } if (pdu->written == total) { - SLIST_REMOVE(&iscsi->outqueue, pdu); if (pdu->flags & ISCSI_PDU_DELETE_WHEN_SENT) { iscsi_free_pdu(iscsi, pdu); - } else { - SLIST_ADD_END(&iscsi->waitpdu, pdu); } + iscsi->outqueue_current = NULL; } } return 0; @@ -625,7 +637,7 @@ iscsi_service(struct iscsi_context *iscsi, int revents) return 0; } - if (revents & POLLOUT && iscsi->outqueue != NULL) { + if (revents & POLLOUT && (iscsi->outqueue != NULL || iscsi->outqueue_current != NULL)) { if (iscsi_write_to_socket(iscsi) != 0) { return iscsi_service_reconnect_if_loggedin(iscsi); }