aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2011-05-16 16:09:08 -0400
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2011-05-16 20:59:11 -0400
commit30f89ca021c3e584b61bc5a14eede89f74b2e826 (patch)
treea0499d96cacd5ca86117e45898d53f241ab5c6f3
parentb513d44751bfb609a3c20463f764c8ce822d63e9 (diff)
xhci: Fix memory leak in ring cache deallocation.
When an endpoint ring is freed, it is either cached in a per-device ring cache, or simply freed if the ring cache is full. If the ring was added to the cache, then virt_dev->num_rings_cached is incremented. The cache is designed to hold up to 31 endpoint rings, in array indexes 0 to 30. When the device is freed (when the slot was disabled), xhci_free_virt_device() is called, it would free the cached rings in array indexes 0 to virt_dev->num_rings_cached. Unfortunately, the original code in xhci_free_or_cache_endpoint_ring() would put the first entry into the ring cache in array index 1, instead of array index 0. This was caused by the second assignment to rings_cached: rings_cached = virt_dev->num_rings_cached; if (rings_cached < XHCI_MAX_RINGS_CACHED) { virt_dev->num_rings_cached++; rings_cached = virt_dev->num_rings_cached; virt_dev->ring_cache[rings_cached] = virt_dev->eps[ep_index].ring; This meant that when the device was freed, cached rings with indexes 0 to N would be freed, and the last cached ring in index N+1 would not be freed. When the driver was unloaded, this caused interesting messages like: xhci_hcd 0000:06:00.0: dma_pool_destroy xHCI ring segments, ffff880063040000 busy This should be queued to stable kernels back to 2.6.33. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Cc: stable@kernel.org
-rw-r--r--drivers/usb/host/xhci-mem.c7
1 files changed, 3 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 6938cc8d848f..26caba4c1950 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -209,14 +209,13 @@ void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
209 209
210 rings_cached = virt_dev->num_rings_cached; 210 rings_cached = virt_dev->num_rings_cached;
211 if (rings_cached < XHCI_MAX_RINGS_CACHED) { 211 if (rings_cached < XHCI_MAX_RINGS_CACHED) {
212 virt_dev->num_rings_cached++;
213 rings_cached = virt_dev->num_rings_cached;
214 virt_dev->ring_cache[rings_cached] = 212 virt_dev->ring_cache[rings_cached] =
215 virt_dev->eps[ep_index].ring; 213 virt_dev->eps[ep_index].ring;
214 virt_dev->num_rings_cached++;
216 xhci_dbg(xhci, "Cached old ring, " 215 xhci_dbg(xhci, "Cached old ring, "
217 "%d ring%s cached\n", 216 "%d ring%s cached\n",
218 rings_cached, 217 virt_dev->num_rings_cached,
219 (rings_cached > 1) ? "s" : ""); 218 (virt_dev->num_rings_cached > 1) ? "s" : "");
220 } else { 219 } else {
221 xhci_ring_free(xhci, virt_dev->eps[ep_index].ring); 220 xhci_ring_free(xhci, virt_dev->eps[ep_index].ring);
222 xhci_dbg(xhci, "Ring cache full (%d rings), " 221 xhci_dbg(xhci, "Ring cache full (%d rings), "