diff options
author | Petr Mladek <pmladek@suse.cz> | 2014-09-19 19:32:21 +0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-09-24 09:33:19 +0400 |
commit | 32a6958998c52e2b00c2f6459acf9a1f09f054ad (patch) | |
tree | 54c95791c1248cdafbec15844dac3b2a56815c18 /drivers/usb/core/hub.h | |
parent | eb6e29248714d767d5338b8b82d286293e8a041a (diff) | |
download | linux-32a6958998c52e2b00c2f6459acf9a1f09f054ad.tar.xz |
usb: hub: convert khubd into workqueue
There is no need to have separate kthread for handling USB hub events.
It is more elegant to use the workqueue framework.
The workqueue is allocated as freezable because the original thread was
freezable as well.
Also it is allocated as ordered because the code is not ready for parallel
processing of hub events, see choose_devnum().
struct usb_hub is passed via the work item. Therefore we do not need
hub_event_list.
Also hub_thread() is not longer needed. It would call only hub_event().
The rest of the code did manipulate the kthread and it is handled by the
workqueue framework now.
kick_khubd is renamed to kick_hub_wq() to make the function clear. And the
protection against races is done another way, see below.
hub_event_lock has been removed. It cannot longer be used to protect struct
usb_hub between hub_event() and hub_disconnect(). Instead we need to get
hub->kref already in kick_hub_wq().
The lock is not really needed for the other scenarios as well. queue_work()
returns whether it succeeded. We could revert the needed operations
accordingly. This is enough to avoid duplicity and inconsistencies.
Yes, the removed lock causes that there is not longer such a strong
synchronization between scheduling the work and manipulating
hub->disconnected.
But kick_hub_wq() must never be called together with hub_disconnect()
otherwise even the original code would have failed. Any callers are
responsible for this.
Therefore the only problem is that hub_disconnect() could be called in parallel
with hub_event(). But this was possible even in the past. struct usb_hub is
still guarded by hub->kref and released in hub_events() when needed.
Note that the source file is still full of the obsolete "khubd" strings.
Let's remove them in a follow up patch. This patch already is complex enough.
Thanks a lot Alan Stern <stern@rowland.harvard.edu> for code review, many useful
tips and guidance. Also thanks to Tejun Heo <tj@kernel.org> for hints how to
allocate the workqueue.
Signed-off-by: Petr Mladek <pmladek@suse.cz>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core/hub.h')
-rw-r--r-- | drivers/usb/core/hub.h | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index c77d8778af4b..688817fb3246 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -41,7 +41,6 @@ struct usb_hub { int error; /* last reported error */ int nerrors; /* track consecutive errors */ - struct list_head event_list; /* hubs w/data or errs ready */ unsigned long event_bits[1]; /* status change bitmask */ unsigned long change_bits[1]; /* ports with logical connect status change */ @@ -77,6 +76,7 @@ struct usb_hub { u8 indicator[USB_MAXCHILDREN]; struct delayed_work leds; struct delayed_work init_work; + struct work_struct events; struct usb_port **ports; }; |