Skip to content

Commit

Permalink
usb: wusbcore: do device lookup while holding the hc mutex
Browse files Browse the repository at this point in the history
This patch modifies the device notification handler to not look up the
wusb_dev object before it calls the lower-level handler routines since
the wusbhc mutex is not held when calling those routines and the device
could go away in the meantime.  Instead, let the individual notification
handlers get the device ptr if they need to after they have taken the
mutex.

Signed-off-by: Thomas Pugliese <thomas.pugliese@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Thomas Pugliese authored and Greg Kroah-Hartman committed Dec 2, 2013
1 parent f4042c0 commit 6161ae5
Showing 1 changed file with 25 additions and 18 deletions.
43 changes: 25 additions & 18 deletions drivers/usb/wusbcore/devconnect.c
Original file line number Diff line number Diff line change
Expand Up @@ -521,11 +521,19 @@ static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr)
*
* @wusbhc shall be referenced and unlocked
*/
static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, u8 srcaddr)
{
struct wusb_dev *wusb_dev;

mutex_lock(&wusbhc->mutex);
wusb_dev->entry_ts = jiffies;
__wusbhc_keep_alive(wusbhc);
wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
if (wusb_dev == NULL) {
dev_dbg(wusbhc->dev, "ignoring DN_Alive from unconnected device %02x\n",
srcaddr);
} else {
wusb_dev->entry_ts = jiffies;
__wusbhc_keep_alive(wusbhc);
}
mutex_unlock(&wusbhc->mutex);
}

Expand Down Expand Up @@ -579,14 +587,22 @@ static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc,
*
* @wusbhc shall be referenced and unlocked
*/
static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, u8 srcaddr)
{
struct device *dev = wusbhc->dev;

dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n", wusb_dev->addr);
struct wusb_dev *wusb_dev;

mutex_lock(&wusbhc->mutex);
__wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, wusb_dev->port_idx));
wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
if (wusb_dev == NULL) {
dev_dbg(dev, "ignoring DN DISCONNECT from unconnected device %02x\n",
srcaddr);
} else {
dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n",
wusb_dev->addr);
__wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc,
wusb_dev->port_idx));
}
mutex_unlock(&wusbhc->mutex);
}

Expand All @@ -608,30 +624,21 @@ void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr,
struct wusb_dn_hdr *dn_hdr, size_t size)
{
struct device *dev = wusbhc->dev;
struct wusb_dev *wusb_dev;

if (size < sizeof(struct wusb_dn_hdr)) {
dev_err(dev, "DN data shorter than DN header (%d < %d)\n",
(int)size, (int)sizeof(struct wusb_dn_hdr));
return;
}

wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
if (wusb_dev == NULL && dn_hdr->bType != WUSB_DN_CONNECT) {
dev_dbg(dev, "ignoring DN %d from unconnected device %02x\n",
dn_hdr->bType, srcaddr);
return;
}

switch (dn_hdr->bType) {
case WUSB_DN_CONNECT:
wusbhc_handle_dn_connect(wusbhc, dn_hdr, size);
break;
case WUSB_DN_ALIVE:
wusbhc_handle_dn_alive(wusbhc, wusb_dev);
wusbhc_handle_dn_alive(wusbhc, srcaddr);
break;
case WUSB_DN_DISCONNECT:
wusbhc_handle_dn_disconnect(wusbhc, wusb_dev);
wusbhc_handle_dn_disconnect(wusbhc, srcaddr);
break;
case WUSB_DN_MASAVAILCHANGED:
case WUSB_DN_RWAKE:
Expand Down

0 comments on commit 6161ae5

Please sign in to comment.