Commit 538e72ad authored by Johannes Erdfelt's avatar Johannes Erdfelt Committed by Greg Kroah-Hartman

[PATCH] USB uhci bugfix

The issue was that the poisoning would posing the data *before* it gave
it to us as well, but I didn't clear out a pointer (qh->urbp) and later
dereferenced it.

Thanks for the report again and for the pci_pool patch so I could
troubleshoot it.

JE
parent dc00b7a3
...@@ -337,6 +337,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci *uhci, struct usb_device *dev) ...@@ -337,6 +337,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci *uhci, struct usb_device *dev)
qh->link = UHCI_PTR_TERM; qh->link = UHCI_PTR_TERM;
qh->dev = dev; qh->dev = dev;
qh->urbp = NULL;
INIT_LIST_HEAD(&qh->list); INIT_LIST_HEAD(&qh->list);
INIT_LIST_HEAD(&qh->remove_list); INIT_LIST_HEAD(&qh->remove_list);
...@@ -411,20 +412,19 @@ static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb ...@@ -411,20 +412,19 @@ static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb
spin_unlock_irqrestore(&uhci->frame_list_lock, flags); spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
} }
static void uhci_remove_qh(struct uhci *uhci, struct urb *urb) static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
{ {
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
unsigned long flags; unsigned long flags;
struct uhci_qh *qh = urbp->qh, *pqh; struct uhci_qh *pqh;
if (!qh) if (!qh)
return; return;
qh->urbp = NULL;
/* Only go through the hoops if it's actually linked in */ /* Only go through the hoops if it's actually linked in */
spin_lock_irqsave(&uhci->frame_list_lock, flags); spin_lock_irqsave(&uhci->frame_list_lock, flags);
if (!list_empty(&qh->list)) { if (!list_empty(&qh->list)) {
qh->urbp = NULL;
pqh = list_entry(qh->list.prev, struct uhci_qh, list); pqh = list_entry(qh->list.prev, struct uhci_qh, list);
if (pqh->urbp) { if (pqh->urbp) {
...@@ -1043,7 +1043,7 @@ static int usb_control_retrigger_status(struct urb *urb) ...@@ -1043,7 +1043,7 @@ static int usb_control_retrigger_status(struct urb *urb)
urbp->short_control_packet = 1; urbp->short_control_packet = 1;
/* Create a new QH to avoid pointer overwriting problems */ /* Create a new QH to avoid pointer overwriting problems */
uhci_remove_qh(uhci, urb); uhci_remove_qh(uhci, urbp->qh);
/* Delete all of the TD's except for the status TD at the end */ /* Delete all of the TD's except for the status TD at the end */
head = &urbp->td_list; head = &urbp->td_list;
...@@ -1746,7 +1746,8 @@ static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb) ...@@ -1746,7 +1746,8 @@ static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb)
uhci_delete_queued_urb(uhci, urb); uhci_delete_queued_urb(uhci, urb);
/* The interrupt loop will reclaim the QH's */ /* The interrupt loop will reclaim the QH's */
uhci_remove_qh(uhci, urb); uhci_remove_qh(uhci, urbp->qh);
urbp->qh = NULL;
} }
static int uhci_unlink_urb(struct urb *urb) static int uhci_unlink_urb(struct urb *urb)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment