usb: wusbcore: do device lookup while holding the hc mutex

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>
This commit is contained in:
Thomas Pugliese 2013-12-02 15:39:44 -06:00 committed by Greg Kroah-Hartman
parent f4042c068a
commit 6161ae5f1f

View File

@ -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);
}
@ -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);
}
@ -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: