Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6161ae5f authored by Thomas Pugliese's avatar Thomas Pugliese Committed by Greg Kroah-Hartman
Browse files

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: default avatarThomas Pugliese <thomas.pugliese@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent f4042c06
Loading
Loading
Loading
Loading
+25 −18
Original line number Original line Diff line number Diff line
@@ -521,11 +521,19 @@ static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr)
 *
 *
 * @wusbhc shall be referenced and unlocked
 * @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);
	mutex_lock(&wusbhc->mutex);
	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;
		wusb_dev->entry_ts = jiffies;
		__wusbhc_keep_alive(wusbhc);
		__wusbhc_keep_alive(wusbhc);
	}
	mutex_unlock(&wusbhc->mutex);
	mutex_unlock(&wusbhc->mutex);
}
}


@@ -579,14 +587,22 @@ static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc,
 *
 *
 * @wusbhc shall be referenced and unlocked
 * @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;
	struct device *dev = wusbhc->dev;

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


	mutex_lock(&wusbhc->mutex);
	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);
	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 wusb_dn_hdr *dn_hdr, size_t size)
{
{
	struct device *dev = wusbhc->dev;
	struct device *dev = wusbhc->dev;
	struct wusb_dev *wusb_dev;


	if (size < sizeof(struct wusb_dn_hdr)) {
	if (size < sizeof(struct wusb_dn_hdr)) {
		dev_err(dev, "DN data shorter than DN header (%d < %d)\n",
		dev_err(dev, "DN data shorter than DN header (%d < %d)\n",
			(int)size, (int)sizeof(struct wusb_dn_hdr));
			(int)size, (int)sizeof(struct wusb_dn_hdr));
		return;
		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) {
	switch (dn_hdr->bType) {
	case WUSB_DN_CONNECT:
	case WUSB_DN_CONNECT:
		wusbhc_handle_dn_connect(wusbhc, dn_hdr, size);
		wusbhc_handle_dn_connect(wusbhc, dn_hdr, size);
		break;
		break;
	case WUSB_DN_ALIVE:
	case WUSB_DN_ALIVE:
		wusbhc_handle_dn_alive(wusbhc, wusb_dev);
		wusbhc_handle_dn_alive(wusbhc, srcaddr);
		break;
		break;
	case WUSB_DN_DISCONNECT:
	case WUSB_DN_DISCONNECT:
		wusbhc_handle_dn_disconnect(wusbhc, wusb_dev);
		wusbhc_handle_dn_disconnect(wusbhc, srcaddr);
		break;
		break;
	case WUSB_DN_MASAVAILCHANGED:
	case WUSB_DN_MASAVAILCHANGED:
	case WUSB_DN_RWAKE:
	case WUSB_DN_RWAKE: