From 1f4a66abc85279f67c93d0f8b7e8ef226fc444b2 Mon Sep 17 00:00:00 2001 From: Peter Lieven Date: Wed, 28 Nov 2012 14:04:14 +0100 Subject: [PATCH] PDU queue out PDUs in order of itt. This patch fixes a deadlock case where all available cmdsns have been used for command PDUs which need additional Data-OUT PDUs to succeed (e.g. a write16 which is larger than first_burst_len). In this case the target will never increase the maxcmdsn leading to a deadlock in iscsi_write_to_socket(). If we receive the R2T for such a write request we will queue the Data-OUT PDUs but at the end of queue. As a result they will never be sent as the outqueue is already stuck. We fix this by sorting the outqueue by ascending itt. Signed-off-by: Peter Lieven --- lib/socket.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/socket.c b/lib/socket.c index 113fc58..44bde4e 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -51,8 +51,37 @@ static uint32_t iface_rr = 0; void iscsi_add_to_outqueue(struct iscsi_context *iscsi, struct iscsi_pdu *pdu) { - SLIST_ADD_END(&iscsi->outqueue, pdu); - return; + if (iscsi->outqueue == NULL) { + iscsi->outqueue = pdu; + pdu->next = NULL; + return; + } + + struct iscsi_pdu *current = iscsi->outqueue; + struct iscsi_pdu *last = NULL; + + /* queue pdus in ascending order of itt. + * ensure that pakets with the same itt are kept in order. + * 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))) { + /* insert PDU before the current */ + if (last != NULL) { + last->next=pdu; + } else { + iscsi->outqueue=pdu; + } + pdu->next = current; + return; + } + last=current; + current=current->next; + } while (current != NULL); + + last->next = pdu; + pdu->next = NULL; } void iscsi_decrement_iface_rr() {