aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci-mem.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-06-01 04:06:24 -0400
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2012-06-13 19:37:30 -0400
commit32f1d2c536d0c26c5814cb0e6a0606c42d02fac1 (patch)
tree76f9d51f81cf29d07a988b0283e2ea4d874a0971 /drivers/usb/host/xhci-mem.c
parent46ed8f00d8982e49f8fe2c1a9cea192f640cb3ba (diff)
xhci: Don't free endpoints in xhci_mem_cleanup()
This patch fixes a few issues introduced in the recent fix [f8a9e72d: USB: fix resource leak in xhci power loss path] - The endpoints listed in bw table are just links and each entry is an array member of dev->eps[]. But the commit above adds a kfree() call to these instances, and thus it results in memory corruption. - It clears only the first entry of rh_bw[], but there can be multiple ports. - It'd be safer to clear the list_head of ep as well, not only removing from the list, as it's checked in xhci_discover_or_reset_device(). This patch should be backported to kernels as old as 3.2, that contain the commit 839c817ce67178ca3c7c7ad534c571bba1e69ebe "xhci: Store information about roothubs and TTs." Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Reviewed-by: Oliver Neukum <oneukum@suse.de> Cc: <stable@vger.kernel.org>
Diffstat (limited to 'drivers/usb/host/xhci-mem.c')
-rw-r--r--drivers/usb/host/xhci-mem.c35
1 files changed, 14 insertions, 21 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 898dfc8bc520..77689bd64cac 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1772,17 +1772,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
1772{ 1772{
1773 struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); 1773 struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
1774 struct dev_info *dev_info, *next; 1774 struct dev_info *dev_info, *next;
1775 struct list_head *tt_list_head;
1776 struct list_head *tt;
1777 struct list_head *endpoints;
1778 struct list_head *ep, *q;
1779 struct xhci_tt_bw_info *tt_info;
1780 struct xhci_interval_bw_table *bwt;
1781 struct xhci_virt_ep *virt_ep;
1782
1783 unsigned long flags; 1775 unsigned long flags;
1784 int size; 1776 int size;
1785 int i; 1777 int i, j, num_ports;
1786 1778
1787 /* Free the Event Ring Segment Table and the actual Event Ring */ 1779 /* Free the Event Ring Segment Table and the actual Event Ring */
1788 size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); 1780 size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
@@ -1841,21 +1833,22 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
1841 } 1833 }
1842 spin_unlock_irqrestore(&xhci->lock, flags); 1834 spin_unlock_irqrestore(&xhci->lock, flags);
1843 1835
1844 bwt = &xhci->rh_bw->bw_table; 1836 num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
1845 for (i = 0; i < XHCI_MAX_INTERVAL; i++) { 1837 for (i = 0; i < num_ports; i++) {
1846 endpoints = &bwt->interval_bw[i].endpoints; 1838 struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table;
1847 list_for_each_safe(ep, q, endpoints) { 1839 for (j = 0; j < XHCI_MAX_INTERVAL; j++) {
1848 virt_ep = list_entry(ep, struct xhci_virt_ep, bw_endpoint_list); 1840 struct list_head *ep = &bwt->interval_bw[j].endpoints;
1849 list_del(&virt_ep->bw_endpoint_list); 1841 while (!list_empty(ep))
1850 kfree(virt_ep); 1842 list_del_init(ep->next);
1851 } 1843 }
1852 } 1844 }
1853 1845
1854 tt_list_head = &xhci->rh_bw->tts; 1846 for (i = 0; i < num_ports; i++) {
1855 list_for_each_safe(tt, q, tt_list_head) { 1847 struct xhci_tt_bw_info *tt, *n;
1856 tt_info = list_entry(tt, struct xhci_tt_bw_info, tt_list); 1848 list_for_each_entry_safe(tt, n, &xhci->rh_bw[i].tts, tt_list) {
1857 list_del(tt); 1849 list_del(&tt->tt_list);
1858 kfree(tt_info); 1850 kfree(tt);
1851 }
1859 } 1852 }
1860 1853
1861 xhci->num_usb2_ports = 0; 1854 xhci->num_usb2_ports = 0;