aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Pugliese <thomas.pugliese@gmail.com>2013-12-02 16:39:44 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-02 18:21:04 -0500
commit6161ae5f1f371e8ff52306d9a1893f5dec6f60a4 (patch)
tree12461b6f78e9bbb74b4e92060891950d3d27b328
parentf4042c068ae53625e4a9f39543c2693d07a4e14c (diff)
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>
-rw-r--r--drivers/usb/wusbcore/devconnect.c43
1 files changed, 25 insertions, 18 deletions
diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c
index d1af4e89111e..5107ca999d4c 100644
--- a/drivers/usb/wusbcore/devconnect.c
+++ b/drivers/usb/wusbcore/devconnect.c
@@ -521,11 +521,19 @@ static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr)
521 * 521 *
522 * @wusbhc shall be referenced and unlocked 522 * @wusbhc shall be referenced and unlocked
523 */ 523 */
524static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) 524static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, u8 srcaddr)
525{ 525{
526 struct wusb_dev *wusb_dev;
527
526 mutex_lock(&wusbhc->mutex); 528 mutex_lock(&wusbhc->mutex);
527 wusb_dev->entry_ts = jiffies; 529 wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
528 __wusbhc_keep_alive(wusbhc); 530 if (wusb_dev == NULL) {
531 dev_dbg(wusbhc->dev, "ignoring DN_Alive from unconnected device %02x\n",
532 srcaddr);
533 } else {
534 wusb_dev->entry_ts = jiffies;
535 __wusbhc_keep_alive(wusbhc);
536 }
529 mutex_unlock(&wusbhc->mutex); 537 mutex_unlock(&wusbhc->mutex);
530} 538}
531 539
@@ -579,14 +587,22 @@ static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc,
579 * 587 *
580 * @wusbhc shall be referenced and unlocked 588 * @wusbhc shall be referenced and unlocked
581 */ 589 */
582static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) 590static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, u8 srcaddr)
583{ 591{
584 struct device *dev = wusbhc->dev; 592 struct device *dev = wusbhc->dev;
585 593 struct wusb_dev *wusb_dev;
586 dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n", wusb_dev->addr);
587 594
588 mutex_lock(&wusbhc->mutex); 595 mutex_lock(&wusbhc->mutex);
589 __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, wusb_dev->port_idx)); 596 wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
597 if (wusb_dev == NULL) {
598 dev_dbg(dev, "ignoring DN DISCONNECT from unconnected device %02x\n",
599 srcaddr);
600 } else {
601 dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n",
602 wusb_dev->addr);
603 __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc,
604 wusb_dev->port_idx));
605 }
590 mutex_unlock(&wusbhc->mutex); 606 mutex_unlock(&wusbhc->mutex);
591} 607}
592 608
@@ -608,30 +624,21 @@ void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr,
608 struct wusb_dn_hdr *dn_hdr, size_t size) 624 struct wusb_dn_hdr *dn_hdr, size_t size)
609{ 625{
610 struct device *dev = wusbhc->dev; 626 struct device *dev = wusbhc->dev;
611 struct wusb_dev *wusb_dev;
612 627
613 if (size < sizeof(struct wusb_dn_hdr)) { 628 if (size < sizeof(struct wusb_dn_hdr)) {
614 dev_err(dev, "DN data shorter than DN header (%d < %d)\n", 629 dev_err(dev, "DN data shorter than DN header (%d < %d)\n",
615 (int)size, (int)sizeof(struct wusb_dn_hdr)); 630 (int)size, (int)sizeof(struct wusb_dn_hdr));
616 return; 631 return;
617 } 632 }
618
619 wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
620 if (wusb_dev == NULL && dn_hdr->bType != WUSB_DN_CONNECT) {
621 dev_dbg(dev, "ignoring DN %d from unconnected device %02x\n",
622 dn_hdr->bType, srcaddr);
623 return;
624 }
625
626 switch (dn_hdr->bType) { 633 switch (dn_hdr->bType) {
627 case WUSB_DN_CONNECT: 634 case WUSB_DN_CONNECT:
628 wusbhc_handle_dn_connect(wusbhc, dn_hdr, size); 635 wusbhc_handle_dn_connect(wusbhc, dn_hdr, size);
629 break; 636 break;
630 case WUSB_DN_ALIVE: 637 case WUSB_DN_ALIVE:
631 wusbhc_handle_dn_alive(wusbhc, wusb_dev); 638 wusbhc_handle_dn_alive(wusbhc, srcaddr);
632 break; 639 break;
633 case WUSB_DN_DISCONNECT: 640 case WUSB_DN_DISCONNECT:
634 wusbhc_handle_dn_disconnect(wusbhc, wusb_dev); 641 wusbhc_handle_dn_disconnect(wusbhc, srcaddr);
635 break; 642 break;
636 case WUSB_DN_MASAVAILCHANGED: 643 case WUSB_DN_MASAVAILCHANGED:
637 case WUSB_DN_RWAKE: 644 case WUSB_DN_RWAKE: