All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ming Lei <ming.lei-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
To: Oliver Neukum <oneukum-l3A5Bk7waGM@public.gmane.org>
Cc: Alan Stern
	<stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz@public.gmane.org>,
	Greg Kroah-Hartman
	<gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>,
	Jiri Kosina <jkosina-AlSwsSmVLrQ@public.gmane.org>,
	linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	stable-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: Re: [PATCH] hid: usbhid: fix possible deadlock in __usbhid_submit_report
Date: Fri, 20 Apr 2012 18:17:51 +0800	[thread overview]
Message-ID: <CACVXFVP42WL2aVDGSn0BF0NJbg824VsU=Fs30XKEif6siOrQvw@mail.gmail.com> (raw)
In-Reply-To: <201204200957.34154.oneukum-l3A5Bk7waGM@public.gmane.org>

On Fri, Apr 20, 2012 at 3:57 PM, Oliver Neukum <oneukum-l3A5Bk7waGM@public.gmane.org> wrote:
>
> You are racing with hid_irq_out(). It calls hid_submit_out()
> under lock. So if hid_irq_out() is running between dropping
> the lock and usb_unlink_urb() you may kill the newly submitted
> urb, not the old urb that has timed out.

Yes, it is the race I missed, :-(

> You must make sure that between the times you check usbhid->last_out
> and calling unlink hid_submit_out() cannot be called.
> You can't just drop the lock (at least on SMP)

Looks it is not easy to avoid the race if the lock is to be dropped.

So how about not acquiring the lock during unlinking as below?

diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index aa1c503..b437223 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -429,7 +429,8 @@ static void hid_irq_out(struct urb *urb)
 			 urb->status);
 	}

-	spin_lock_irqsave(&usbhid->lock, flags);
+	if (!test_cpu_bit(HID_PCPU_TIMEOUT, usbhid->cpuiofl))
+		spin_lock_irqsave(&usbhid->lock, flags);

 	if (unplug)
 		usbhid->outtail = usbhid->outhead;
@@ -438,12 +439,14 @@ static void hid_irq_out(struct urb *urb)

 	if (usbhid->outhead != usbhid->outtail && !hid_submit_out(hid)) {
 		/* Successfully submitted next urb in queue */
-		spin_unlock_irqrestore(&usbhid->lock, flags);
+		if (!test_cpu_bit(HID_PCPU_TIMEOUT, usbhid->cpuiofl))
+			spin_unlock_irqrestore(&usbhid->lock, flags);
 		return;
 	}

 	clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
-	spin_unlock_irqrestore(&usbhid->lock, flags);
+	if (!test_cpu_bit(HID_PCPU_TIMEOUT, usbhid->cpuiofl))
+		spin_unlock_irqrestore(&usbhid->lock, flags);
 	usb_autopm_put_interface_async(usbhid->intf);
 	wake_up(&usbhid->wait);
 }
@@ -458,7 +461,8 @@ static void hid_ctrl(struct urb *urb)
 	struct usbhid_device *usbhid = hid->driver_data;
 	int unplug = 0, status = urb->status;

-	spin_lock(&usbhid->lock);
+	if (!test_cpu_bit(HID_PCPU_TIMEOUT, usbhid->cpuiofl))
+		spin_lock(&usbhid->lock);

 	switch (status) {
 	case 0:			/* success */
@@ -486,12 +490,14 @@ static void hid_ctrl(struct urb *urb)

 	if (usbhid->ctrlhead != usbhid->ctrltail && !hid_submit_ctrl(hid)) {
 		/* Successfully submitted next urb in queue */
-		spin_unlock(&usbhid->lock);
+		if (!test_cpu_bit(HID_PCPU_TIMEOUT, usbhid->cpuiofl))
+			spin_unlock(&usbhid->lock);
 		return;
 	}

 	clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
-	spin_unlock(&usbhid->lock);
+	if (!test_cpu_bit(HID_PCPU_TIMEOUT, usbhid->cpuiofl))
+		spin_unlock(&usbhid->lock);
 	usb_autopm_put_interface_async(usbhid->intf);
 	wake_up(&usbhid->wait);
 }
@@ -546,8 +552,11 @@ static void __usbhid_submit_report(struct
hid_device *hid, struct hid_report *re
 			 * no race because this is called under
 			 * spinlock
 			 */
-			if (time_after(jiffies, usbhid->last_out + HZ * 5))
+			if (time_after(jiffies, usbhid->last_out + HZ * 5)) {
+				set_cpu_bit(HID_PCPU_TIMEOUT, usbhid->cpuiofl);
 				usb_unlink_urb(usbhid->urbout);
+				clear_cpu_bit(HID_PCPU_TIMEOUT, usbhid->cpuiofl);
+			}
 		}
 		return;
 	}
@@ -594,8 +603,11 @@ static void __usbhid_submit_report(struct
hid_device *hid, struct hid_report *re
 		 * no race because this is called under
 		 * spinlock
 		 */
-		if (time_after(jiffies, usbhid->last_ctrl + HZ * 5))
-			usb_unlink_urb(usbhid->urbctrl);
+		if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) {
+				set_cpu_bit(HID_PCPU_TIMEOUT, usbhid->cpuiofl);
+				usb_unlink_urb(usbhid->urbctrl);
+				clear_cpu_bit(HID_PCPU_TIMEOUT, usbhid->cpuiofl);
+		}
 	}
 }

@@ -1294,6 +1306,12 @@ static int usbhid_probe(struct usb_interface
*intf, const struct usb_device_id *
 	usbhid->hid = hid;
 	usbhid->intf = intf;
 	usbhid->ifnum = interface->desc.bInterfaceNumber;
+	usbhid->cpuiofl = alloc_percpu(unsigned long);
+	if (!usbhid->cpuiofl) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
+

 	init_waitqueue_head(&usbhid->wait);
 	INIT_WORK(&usbhid->reset_work, hid_reset);
@@ -1306,10 +1324,12 @@ static int usbhid_probe(struct usb_interface
*intf, const struct usb_device_id *
 	if (ret) {
 		if (ret != -ENODEV)
 			hid_err(intf, "can't add hid device: %d\n", ret);
-		goto err_free;
+		goto err_add_dev;
 	}

 	return 0;
+err_add_dev:
+	free_percpu(usbhid->cpuiofl);
 err_free:
 	kfree(usbhid);
 err:
@@ -1327,6 +1347,7 @@ static void usbhid_disconnect(struct usb_interface *intf)

 	usbhid = hid->driver_data;
 	hid_destroy_device(hid);
+	free_percpu(usbhid->cpuiofl);
 	kfree(usbhid);
 }

diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index 1883d7b..8fd240e 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -57,6 +57,9 @@ struct usb_interface *usbhid_find_interface(int minor);
 #define HID_KEYS_PRESSED	10
 #define HID_NO_BANDWIDTH	11

+/*per cpu iofl flags */
+#define HID_PCPU_TIMEOUT	1
+
 /*
  * USB-specific HID struct, to be pointed to
  * from struct hid_device->driver_data
@@ -91,6 +94,7 @@ struct usbhid_device {

 	spinlock_t lock;						/* fifo spinlock */
 	unsigned long iofl;                                             /*
I/O flags (CTRL_RUNNING, OUT_RUNNING) */
+	unsigned long __percpu *cpuiofl;                                /*
per cpu I/O flags (PCPU_TIMEOUT) */
 	struct timer_list io_retry;                                     /*
Retry timer */
 	unsigned long stop_retry;                                       /*
Time to give up, in jiffies */
 	unsigned int retry_delay;                                       /*
Delay length in ms */
@@ -104,5 +108,23 @@ struct usbhid_device {
 #define	hid_to_usb_dev(hid_dev) \
 	container_of(hid_dev->dev.parent->parent, struct usb_device, dev)

+static inline void set_cpu_bit(int nr, unsigned long __percpu *addr)
+{
+	unsigned long *fl = __this_cpu_ptr(addr);
+	set_bit(nr, fl);
+}
+
+static inline void clear_cpu_bit(int nr, unsigned long __percpu *addr)
+{
+	unsigned long *fl = __this_cpu_ptr(addr);
+	clear_bit(nr, fl);
+}
+
+static inline int test_cpu_bit(int nr, unsigned long __percpu *addr)
+{
+	unsigned long *fl = __this_cpu_ptr(addr);
+	return test_bit(nr, fl);
+}
+
 #endif


thanks,
--
Ming Lei
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

  parent reply	other threads:[~2012-04-20 10:17 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-04-19 13:51 [PATCH] hid: usbhid: fix possible deadlock in __usbhid_submit_report Ming Lei
     [not found] ` <1334843464-1585-1-git-send-email-ming.lei-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
2012-04-19 16:11   ` Oliver Neukum
2012-04-20  2:10     ` Ming Lei
2012-04-20  7:57       ` Oliver Neukum
     [not found]         ` <201204200957.34154.oneukum-l3A5Bk7waGM@public.gmane.org>
2012-04-20 10:17           ` Ming Lei [this message]
2012-04-20 10:45             ` Oliver Neukum
2012-04-20 12:53               ` Ming Lei
2012-04-20 14:07                 ` Oliver Neukum
     [not found]               ` <201204201245.44981.oneukum-l3A5Bk7waGM@public.gmane.org>
2012-04-20 13:30                 ` Ming Lei
2012-04-21  0:37                 ` Alan Stern
     [not found]                   ` <Pine.LNX.4.44L0.1204202032530.19313-100000-pYrvlCTfrz9XsRXLowluHWD2FQJk+8+b@public.gmane.org>
2012-04-21 10:25                     ` Oliver Neukum
2012-04-21 13:40                       ` Ming Lei
2012-04-21 17:31                         ` Alan Stern
     [not found]                           ` <Pine.LNX.4.44L0.1204211327090.475-100000-pYrvlCTfrz9XsRXLowluHWD2FQJk+8+b@public.gmane.org>
2012-04-21 19:28                             ` Oliver Neukum
2012-04-21 21:49                               ` Alan Stern
     [not found]                                 ` <Pine.LNX.4.44L0.1204211717310.3981-100000-pYrvlCTfrz9XsRXLowluHWD2FQJk+8+b@public.gmane.org>
2012-04-22 10:51                                   ` Ming Lei
2012-04-22 12:50                                     ` Alan Stern
2012-04-22 13:52                                       ` Ming Lei
2012-04-23 15:42                                         ` Alan Stern
2012-04-24  4:19                                           ` Ming Lei
2012-04-24 14:22                                             ` Oliver Neukum
2012-04-24 15:46                                               ` Ming Lei
2012-04-24 18:57                                                 ` Oliver Neukum
2012-04-25  1:27                                                   ` Ming Lei
2012-04-25  6:19                                                     ` Oliver Neukum
2012-04-25  6:32                                                       ` Oliver Neukum
2012-04-25  7:02                                                       ` Ming Lei
     [not found]                                                         ` <CACVXFVMEttnWo34ZxBsm4vdW1y5f5mBjY1s6BVbbsjck-4cSbA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-04-25  8:08                                                           ` Oliver Neukum
     [not found]                                             ` <CACVXFVNhPKbFZN5AjT3BNdNP+3bZP7miJZrBEER97scMR5nNAQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-04-24 15:20                                               ` Alan Stern
     [not found]                                                 ` <Pine.LNX.4.44L0.1204241110160.1511-100000-IYeN2dnnYyZXsRXLowluHWD2FQJk+8+b@public.gmane.org>
2012-04-25  0:27                                                   ` Ming Lei
     [not found]                                           ` <Pine.LNX.4.44L0.1204231121200.1612-100000-IYeN2dnnYyZXsRXLowluHWD2FQJk+8+b@public.gmane.org>
2012-04-24 14:35                                             ` Oliver Neukum
2012-04-24 15:10                                               ` Alan Stern
2012-04-25  8:06                                                 ` Oliver Neukum
2012-04-25  9:14                                                   ` Ming Lei
     [not found]                                                     ` <CACVXFVM6KMeMcXy549x9XqhqvCzq73pXvhLki363=KjQu2Nfsg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-04-25 10:52                                                       ` Oliver Neukum
2012-04-25 11:24                                                         ` Huajun Li
     [not found]                                                           ` <CA+v9cxYi-LC-gXMbP7J81ArCjwQJZQ=9ceu66W0QQe+6UD_LvQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-04-25 11:33                                                             ` Oliver Neukum
2012-04-25 13:18                                                         ` Ming Lei
     [not found]                                                         ` <201204251252.55901.oneukum-l3A5Bk7waGM@public.gmane.org>
2012-04-25 15:19                                                           ` Alan Stern
2012-04-26 22:44                                                             ` Jiri Kosina
2012-04-26 23:40                                                               ` Greg Kroah-Hartman
2012-04-23  8:21                                     ` Oliver Neukum
2012-04-22 11:53                           ` Ming Lei
2012-04-22 12:54                             ` Alan Stern
     [not found]                             ` <CACVXFVOQpYcHUj3XApyCVWDuvUEKi+RSWC8Ly4Dnj7vrun68cg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-04-23  8:24                               ` Oliver Neukum
     [not found]             ` <CACVXFVP42WL2aVDGSn0BF0NJbg824VsU=Fs30XKEif6siOrQvw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-04-20 21:59               ` Dmitry Torokhov
2012-04-21  1:06                 ` Ming Lei

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CACVXFVP42WL2aVDGSn0BF0NJbg824VsU=Fs30XKEif6siOrQvw@mail.gmail.com' \
    --to=ming.lei-z7wlfzj8ewms+fvcfc7uqw@public.gmane.org \
    --cc=gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org \
    --cc=jkosina-AlSwsSmVLrQ@public.gmane.org \
    --cc=linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=oneukum-l3A5Bk7waGM@public.gmane.org \
    --cc=stable-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=stern-nwvwT67g6+6dFdvTe/nMLpVzexx5G7lz@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.