Blame 0139-ehci-Fix-memory-leak-in-handling-of-NAK-ed-packets.patch

5544c1
From 5d369bd44cf2611f47fec52c7402472cd2436b4a Mon Sep 17 00:00:00 2001
Hans de Goede c8dfc6
From: Hans de Goede <hdegoede@redhat.com>
Hans de Goede c8dfc6
Date: Mon, 3 Sep 2012 11:01:13 +0200
5544c1
Subject: [PATCH] ehci: Fix memory leak in handling of NAK-ed packets
Hans de Goede c8dfc6
Hans de Goede c8dfc6
Currently each time we try to execute a NAK-ed packet we redo
Hans de Goede c8dfc6
ehci_init_transfer, and usb_packet_map, re-allocing (without freeing) the
Hans de Goede c8dfc6
sg list every time.
Hans de Goede c8dfc6
Hans de Goede c8dfc6
This patch fixes this, it does this by introducing another async state, so
Hans de Goede c8dfc6
that we also properly cleanup a NAK-ed packet on cancel.
Hans de Goede c8dfc6
Hans de Goede c8dfc6
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Hans de Goede c8dfc6
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
5544c1
(cherry picked from commit ef5b234477df80700b128f561f5877a0688a70c8)
5544c1
5544c1
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
Hans de Goede c8dfc6
---
Hans de Goede c8dfc6
 hw/usb/hcd-ehci.c | 38 +++++++++++++++++++++++++++-----------
Hans de Goede c8dfc6
 1 file changed, 27 insertions(+), 11 deletions(-)
Hans de Goede c8dfc6
Hans de Goede c8dfc6
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
Hans de Goede c8dfc6
index 5a88268..d87aca8 100644
Hans de Goede c8dfc6
--- a/hw/usb/hcd-ehci.c
Hans de Goede c8dfc6
+++ b/hw/usb/hcd-ehci.c
Hans de Goede c8dfc6
@@ -345,6 +345,7 @@ typedef struct EHCIState EHCIState;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
 enum async_state {
Hans de Goede c8dfc6
     EHCI_ASYNC_NONE = 0,
Hans de Goede c8dfc6
+    EHCI_ASYNC_INITIALIZED,
Hans de Goede c8dfc6
     EHCI_ASYNC_INFLIGHT,
Hans de Goede c8dfc6
     EHCI_ASYNC_FINISHED,
Hans de Goede c8dfc6
 };
Hans de Goede c8dfc6
@@ -764,6 +765,10 @@ static void ehci_free_packet(EHCIPacket *p)
Hans de Goede c8dfc6
         return;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
     trace_usb_ehci_packet_action(p->queue, p, "free");
Hans de Goede c8dfc6
+    if (p->async == EHCI_ASYNC_INITIALIZED) {
Hans de Goede c8dfc6
+        usb_packet_unmap(&p->packet, &p->sgl);
Hans de Goede c8dfc6
+        qemu_sglist_destroy(&p->sgl);
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
     if (p->async == EHCI_ASYNC_INFLIGHT) {
Hans de Goede c8dfc6
         usb_cancel_packet(&p->packet);
Hans de Goede c8dfc6
         usb_packet_unmap(&p->packet, &p->sgl);
Hans de Goede c8dfc6
@@ -1485,8 +1490,8 @@ static void ehci_execute_complete(EHCIQueue *q)
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     assert(p != NULL);
Hans de Goede c8dfc6
     assert(p->qtdaddr == q->qtdaddr);
Hans de Goede c8dfc6
-    assert(p->async != EHCI_ASYNC_INFLIGHT);
Hans de Goede c8dfc6
-    p->async = EHCI_ASYNC_NONE;
Hans de Goede c8dfc6
+    assert(p->async == EHCI_ASYNC_INITIALIZED ||
Hans de Goede c8dfc6
+           p->async == EHCI_ASYNC_FINISHED);
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n",
Hans de Goede c8dfc6
             q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status);
Hans de Goede c8dfc6
@@ -1531,6 +1536,7 @@ static void ehci_execute_complete(EHCIQueue *q)
Hans de Goede c8dfc6
     ehci_finish_transfer(q, p->usb_status);
Hans de Goede c8dfc6
     usb_packet_unmap(&p->packet, &p->sgl);
Hans de Goede c8dfc6
     qemu_sglist_destroy(&p->sgl);
Hans de Goede c8dfc6
+    p->async = EHCI_ASYNC_NONE;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     q->qh.token ^= QTD_TOKEN_DTOGGLE;
Hans de Goede c8dfc6
     q->qh.token &= ~QTD_TOKEN_ACTIVE;
Hans de Goede c8dfc6
@@ -1548,6 +1554,9 @@ static int ehci_execute(EHCIPacket *p, const char *action)
Hans de Goede c8dfc6
     int ret;
Hans de Goede c8dfc6
     int endp;
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
+    assert(p->async == EHCI_ASYNC_NONE ||
Hans de Goede c8dfc6
+           p->async == EHCI_ASYNC_INITIALIZED);
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
     if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) {
Hans de Goede c8dfc6
         fprintf(stderr, "Attempting to execute inactive qtd\n");
Hans de Goede c8dfc6
         return USB_RET_PROCERR;
Hans de Goede c8dfc6
@@ -1576,15 +1585,18 @@ static int ehci_execute(EHCIPacket *p, const char *action)
Hans de Goede c8dfc6
         break;
Hans de Goede c8dfc6
     }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    if (ehci_init_transfer(p) != 0) {
Hans de Goede c8dfc6
-        return USB_RET_PROCERR;
Hans de Goede c8dfc6
-    }
Hans de Goede c8dfc6
-
Hans de Goede c8dfc6
     endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP);
Hans de Goede c8dfc6
     ep = usb_ep_get(p->queue->dev, p->pid, endp);
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
-    usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr);
Hans de Goede c8dfc6
-    usb_packet_map(&p->packet, &p->sgl);
Hans de Goede c8dfc6
+    if (p->async == EHCI_ASYNC_NONE) {
Hans de Goede c8dfc6
+        if (ehci_init_transfer(p) != 0) {
Hans de Goede c8dfc6
+            return USB_RET_PROCERR;
Hans de Goede c8dfc6
+        }
Hans de Goede c8dfc6
+
Hans de Goede c8dfc6
+        usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr);
Hans de Goede c8dfc6
+        usb_packet_map(&p->packet, &p->sgl);
Hans de Goede c8dfc6
+        p->async = EHCI_ASYNC_INITIALIZED;
Hans de Goede c8dfc6
+    }
Hans de Goede c8dfc6
 
Hans de Goede c8dfc6
     trace_usb_ehci_packet_action(p->queue, p, action);
Hans de Goede c8dfc6
     ret = usb_handle_packet(p->queue->dev, &p->packet);
Hans de Goede c8dfc6
@@ -2021,11 +2033,15 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
Hans de Goede c8dfc6
     } else if (p != NULL) {
Hans de Goede c8dfc6
         switch (p->async) {
Hans de Goede c8dfc6
         case EHCI_ASYNC_NONE:
Hans de Goede c8dfc6
+            /* Should never happen packet should at least be initialized */
Hans de Goede c8dfc6
+            assert(0);
Hans de Goede c8dfc6
+            break;
Hans de Goede c8dfc6
+        case EHCI_ASYNC_INITIALIZED:
Hans de Goede c8dfc6
             /* Previously nacked packet (likely interrupt ep) */
Hans de Goede c8dfc6
-           ehci_set_state(q->ehci, q->async, EST_EXECUTE);
Hans de Goede c8dfc6
-           break;
Hans de Goede c8dfc6
+            ehci_set_state(q->ehci, q->async, EST_EXECUTE);
Hans de Goede c8dfc6
+            break;
Hans de Goede c8dfc6
         case EHCI_ASYNC_INFLIGHT:
Hans de Goede c8dfc6
-            /* Unfinyshed async handled packet, go horizontal */
Hans de Goede c8dfc6
+            /* Unfinished async handled packet, go horizontal */
Hans de Goede c8dfc6
             ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
Hans de Goede c8dfc6
             break;
Hans de Goede c8dfc6
         case EHCI_ASYNC_FINISHED:
Hans de Goede c8dfc6
-- 
5544c1
1.7.12.1
Hans de Goede c8dfc6