diff options
author | Ming Lei <ming.lei@canonical.com> | 2013-02-22 19:34:22 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-23 20:50:16 -0500 |
commit | 4d769def244806562de1baa3acb39726131fbe6a (patch) | |
tree | 84987b35cf3915482790da45e97f4b62e9d97cbb /drivers/usb | |
parent | db88175f41a29c1ffff1a6938a7969d206a47326 (diff) |
usb: forbid memory allocation with I/O during bus reset
If one storage interface or usb network interface(iSCSI case) exists in
current configuration, memory allocation with GFP_KERNEL during
usb_device_reset() might trigger I/O transfer on the storage interface
itself and cause deadlock because the 'us->dev_mutex' is held in
.pre_reset() and the storage interface can't do I/O transfer when the
reset is triggered by other interface, or the error handling can't be
completed if the reset is triggered by the storage itself (error
handling path).
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: David Decotigny <david.decotigny@google.com>
Cc: Tom Herbert <therbert@google.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Oliver Neukum <oneukum@suse.de>
Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Cc: Mel Gorman <mel@csn.ul.ie>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Michal Hocko <mhocko@suse.cz>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/core/hub.c | 13 |
1 files changed, 13 insertions, 0 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1775ad471edd..5480352f984d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -5177,6 +5177,7 @@ int usb_reset_device(struct usb_device *udev) | |||
5177 | { | 5177 | { |
5178 | int ret; | 5178 | int ret; |
5179 | int i; | 5179 | int i; |
5180 | unsigned int noio_flag; | ||
5180 | struct usb_host_config *config = udev->actconfig; | 5181 | struct usb_host_config *config = udev->actconfig; |
5181 | 5182 | ||
5182 | if (udev->state == USB_STATE_NOTATTACHED || | 5183 | if (udev->state == USB_STATE_NOTATTACHED || |
@@ -5186,6 +5187,17 @@ int usb_reset_device(struct usb_device *udev) | |||
5186 | return -EINVAL; | 5187 | return -EINVAL; |
5187 | } | 5188 | } |
5188 | 5189 | ||
5190 | /* | ||
5191 | * Don't allocate memory with GFP_KERNEL in current | ||
5192 | * context to avoid possible deadlock if usb mass | ||
5193 | * storage interface or usbnet interface(iSCSI case) | ||
5194 | * is included in current configuration. The easist | ||
5195 | * approach is to do it for every device reset, | ||
5196 | * because the device 'memalloc_noio' flag may have | ||
5197 | * not been set before reseting the usb device. | ||
5198 | */ | ||
5199 | noio_flag = memalloc_noio_save(); | ||
5200 | |||
5189 | /* Prevent autosuspend during the reset */ | 5201 | /* Prevent autosuspend during the reset */ |
5190 | usb_autoresume_device(udev); | 5202 | usb_autoresume_device(udev); |
5191 | 5203 | ||
@@ -5230,6 +5242,7 @@ int usb_reset_device(struct usb_device *udev) | |||
5230 | } | 5242 | } |
5231 | 5243 | ||
5232 | usb_autosuspend_device(udev); | 5244 | usb_autosuspend_device(udev); |
5245 | memalloc_noio_restore(noio_flag); | ||
5233 | return ret; | 5246 | return ret; |
5234 | } | 5247 | } |
5235 | EXPORT_SYMBOL_GPL(usb_reset_device); | 5248 | EXPORT_SYMBOL_GPL(usb_reset_device); |