All of lore.kernel.org
 help / color / mirror / Atom feed
From: Huajun Li <huajun.li.lee@gmail.com>
To: Oliver Neukum <oneukum@suse.de>
Cc: Ming Lei <ming.lei@canonical.com>,
	Alan Stern <stern@rowland.harvard.edu>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Jiri Kosina <jkosina@suse.cz>,
	linux-usb@vger.kernel.org, linux-input@vger.kernel.org,
	stable@vger.kernel.org
Subject: Re: [PATCH] hid: usbhid: fix possible deadlock in __usbhid_submit_report
Date: Wed, 25 Apr 2012 19:24:14 +0800	[thread overview]
Message-ID: <CA+v9cxYi-LC-gXMbP7J81ArCjwQJZQ=9ceu66W0QQe+6UD_LvQ@mail.gmail.com> (raw)
In-Reply-To: <201204251252.55901.oneukum@suse.de>

On Wed, Apr 25, 2012 at 6:52 PM, Oliver Neukum <oneukum@suse.de> wrote:
> Am Mittwoch, 25. April 2012, 11:14:19 schrieb Ming Lei:
>> > -                       if (time_after(jiffies, usbhid->last_out + HZ * 5))
>> > +                       if (time_after(jiffies, usbhid->last_out + HZ * 5)) {
>> > +                               usb_block_urb(usbhid->urbout);
>> > +                               /* drop lock to not deadlock if the callback is called */
>> > +                               spin_unlock(&usbhid->lock);
>> >                                usb_unlink_urb(usbhid->urbout);
>> > +                               spin_lock(&usbhid->lock);
>> > +                               usb_unblock_urb(usbhid->urbout);
>> > +                               /*
>> > +                                * if the unlinking has already completed
>> > +                                * the pump will have been stopped
>> > +                                * it must be restarted now
>> > +                                */
>> > +                               if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl))
>> > +                                       if (!hid_submit_out(hid))
>>
>> You need to add check of "usbhid->outtail != usbhid->outhead" above.
>
> Done. Could you test?
>
>        Regards
>                Oliver
> From 9ff6b78dc59c98b9844dc9922549fd338828a889 Mon Sep 17 00:00:00 2001
> From: Oliver Neukum <oliver@neukum.org>
> Date: Wed, 25 Apr 2012 12:50:37 +0200
> Subject: [PATCH] usbhid: prevent deadlock during timeout
>
> On some HCDs usb_unlink_urb() can directly call the
> completion handler. That limits the spinlocks that can
> be taken in the handler to locks not held while calling
> usb_unlink_urb()
> To prevent a race with resubmission, this patch exposes
> usbcore's infrastructure for blocking submission, uses it
> and so drops the lock without causing a race in usbhid.
>
> Signed-off-by: Oliver Neukum <oneukum@suse.de>
> ---
>  drivers/hid/usbhid/hid-core.c |   61 +++++++++++++++++++++++++++++++++++++----
>  drivers/usb/core/urb.c        |   30 ++++++++++++++++++++
>  include/linux/usb.h           |    2 +
>  3 files changed, 87 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
> index 5bf91db..c8eab8d 100644
> --- a/drivers/hid/usbhid/hid-core.c
> +++ b/drivers/hid/usbhid/hid-core.c
> @@ -399,6 +399,16 @@ static int hid_submit_ctrl(struct hid_device *hid)
>  * Output interrupt completion handler.
>  */
>
> +static int irq_out_pump_restart(struct hid_device *hid)
> +{
> +       struct usbhid_device *usbhid = hid->driver_data;
> +
> +       if (usbhid->outhead != usbhid->outtail)
> +               return hid_submit_out(hid);
> +       else
> +               return -1;
> +}
> +
>  static void hid_irq_out(struct urb *urb)
>  {
>        struct hid_device *hid = urb->context;
> @@ -428,7 +438,7 @@ static void hid_irq_out(struct urb *urb)
>        else
>                usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
>
> -       if (usbhid->outhead != usbhid->outtail && !hid_submit_out(hid)) {
> +       if (!irq_out_pump_restart(hid)) {
>                /* Successfully submitted next urb in queue */
>                spin_unlock_irqrestore(&usbhid->lock, flags);
>                return;
> @@ -443,6 +453,15 @@ static void hid_irq_out(struct urb *urb)
>  /*
>  * Control pipe completion handler.
>  */
> +static int ctrl_pump_restart(struct hid_device *hid)
> +{
> +       struct usbhid_device *usbhid = hid->driver_data;
> +
> +        if (usbhid->ctrlhead != usbhid->ctrltail)
> +               return hid_submit_ctrl(hid);
> +       else
> +               return -1;
> +}
>
>  static void hid_ctrl(struct urb *urb)
>  {
> @@ -476,7 +495,7 @@ static void hid_ctrl(struct urb *urb)
>        else
>                usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
>
> -       if (usbhid->ctrlhead != usbhid->ctrltail && !hid_submit_ctrl(hid)) {
> +       if (!ctrl_pump_restart(hid)) {
>                /* Successfully submitted next urb in queue */
>                spin_unlock(&usbhid->lock);
>                return;
> @@ -535,11 +554,27 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
>                         * the queue is known to run
>                         * but an earlier request may be stuck
>                         * we may need to time out
> -                        * no race because this is called under
> +                        * no race because the URB is blocked under
>                         * spinlock
>                         */
> -                       if (time_after(jiffies, usbhid->last_out + HZ * 5))
> +                       if (time_after(jiffies, usbhid->last_out + HZ * 5)) {
> +                               usb_block_urb(usbhid->urbout);
> +                               /* drop lock to not deadlock if the callback is called */
> +                               spin_unlock(&usbhid->lock);
>                                usb_unlink_urb(usbhid->urbout);
> +                               spin_lock(&usbhid->lock);
> +                               usb_unblock_urb(usbhid->urbout);
> +                               /*
> +                                * if the unlinking has already completed
> +                                * the pump will have been stopped
> +                                * it must be restarted now
> +                                */
> +                               if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl))
> +                                       if (!irq_out_pump_restart(hid))
> +                                               set_bit(HID_OUT_RUNNING, &usbhid->iofl);
> +
> +
> +                       }
>                }
>                return;
>        }
> @@ -583,11 +618,25 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
>                 * the queue is known to run
>                 * but an earlier request may be stuck
>                 * we may need to time out
> -                * no race because this is called under
> +                * no race because the URB is blocked under
>                 * spinlock
>                 */
> -               if (time_after(jiffies, usbhid->last_ctrl + HZ * 5))
> +               if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) {
> +                       usb_block_urb(usbhid->urbctrl);
> +                       /* drop lock to not deadlock if the callback is called */
> +                       spin_unlock(&usbhid->lock);
>                        usb_unlink_urb(usbhid->urbctrl);
> +                       spin_lock(&usbhid->lock);
> +                       usb_unblock_urb(usbhid->urbctrl);
> +                       /*
> +                        * if the unlinking has already completed
> +                        * the pump will have been stopped
> +                        * it must be restarted now
> +                        */
> +                       if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
> +                               if (!ctrl_pump_restart(hid))
> +                                       set_bit(HID_CTRL_RUNNING, &usbhid->iofl);
> +               }
>        }
>  }
>
> diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
> index cd9b3a2..1d1b010 100644
> --- a/drivers/usb/core/urb.c
> +++ b/drivers/usb/core/urb.c
> @@ -681,6 +681,36 @@ void usb_unpoison_urb(struct urb *urb)
>  EXPORT_SYMBOL_GPL(usb_unpoison_urb);
>
>  /**
> + * usb_block_urb - reliably prevent further use of an URB
> + * @urb: pointer to URB to be blocked, may be NULL
> + *
> + * After the routine has run, attempts to resubmit the URB will fail
> + * with error -EPERM.  Thus even if the URB's completion handler always
> + * tries to resubmit, it will not succeed and the URB will become idle.
> + *
> + * The URB must not be deallocated while this routine is running.  In
> + * particular, when a driver calls this routine, it must insure that the
> + * completion handler cannot deallocate the URB.
> + */
> +void usb_block_urb(struct urb *urb)
> +{
> +        if (!urb)
> +                return;
> +
> +        atomic_inc(&urb->reject);
> +}
> +EXPORT_SYMBOL_GPL(usb_block_urb);
> +
> +void usb_unblock_urb(struct urb *urb)
> +{
> +        if (!urb)
> +                return;
> +
> +        atomic_dec(&urb->reject);
> +}
> +EXPORT_SYMBOL_GPL(usb_unblock_urb);
> +

Hi,
  So far, usb_unblock_urb() does same thing as usb_unpoison_urb(), so
is it possible reusing it just by adding a macro define?

> +/**
>  * usb_kill_anchored_urbs - cancel transfer requests en masse
>  * @anchor: anchor the requests are bound to
>  *
> diff --git a/include/linux/usb.h b/include/linux/usb.h
> index 73b68d1..23df8ae 100644
> --- a/include/linux/usb.h
> +++ b/include/linux/usb.h
> @@ -1379,6 +1379,8 @@ extern int usb_unlink_urb(struct urb *urb);
>  extern void usb_kill_urb(struct urb *urb);
>  extern void usb_poison_urb(struct urb *urb);
>  extern void usb_unpoison_urb(struct urb *urb);
> +extern void usb_block_urb(struct urb *urb);
> +extern void usb_unblock_urb(struct urb *urb);
>  extern void usb_kill_anchored_urbs(struct usb_anchor *anchor);
>  extern void usb_poison_anchored_urbs(struct usb_anchor *anchor);
>  extern void usb_unpoison_anchored_urbs(struct usb_anchor *anchor);
> --
> 1.7.1
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

  reply	other threads:[~2012-04-25 11:24 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
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 [this message]
     [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='CA+v9cxYi-LC-gXMbP7J81ArCjwQJZQ=9ceu66W0QQe+6UD_LvQ@mail.gmail.com' \
    --to=huajun.li.lee@gmail.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=jkosina@suse.cz \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=ming.lei@canonical.com \
    --cc=oneukum@suse.de \
    --cc=stable@vger.kernel.org \
    --cc=stern@rowland.harvard.edu \
    /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.