diff options
author | Ming Lei <ming.lei@canonical.com> | 2013-02-22 19:34:11 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-23 20:50:16 -0500 |
commit | e823407f7b11fa06ba8e7a2801eb9ed11268a7ec (patch) | |
tree | 7fa1131c6607b2df9975c890b0a22a7cf0d6e15f /drivers/base | |
parent | 21caf2fc1931b485483ddd254b634fa8f0099963 (diff) |
pm / runtime: introduce pm_runtime_set_memalloc_noio()
Introduce the flag memalloc_noio in 'struct dev_pm_info' to help PM core
to teach mm not allocating memory with GFP_KERNEL flag for avoiding
probable deadlock.
As explained in the comment, any GFP_KERNEL allocation inside
runtime_resume() or runtime_suspend() on any one of device in the path
from one block or network device to the root device in the device tree
may cause deadlock, the introduced pm_runtime_set_memalloc_noio() sets
or clears the flag on device in the path recursively.
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Oliver Neukum <oneukum@suse.de>
Cc: Jiri Kosina <jiri.kosina@suse.com>
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>
Cc: Jens Axboe <axboe@kernel.dk>
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>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/power/runtime.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 3148b10dc2e5..cd92e1c77cb7 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c | |||
@@ -124,6 +124,76 @@ unsigned long pm_runtime_autosuspend_expiration(struct device *dev) | |||
124 | } | 124 | } |
125 | EXPORT_SYMBOL_GPL(pm_runtime_autosuspend_expiration); | 125 | EXPORT_SYMBOL_GPL(pm_runtime_autosuspend_expiration); |
126 | 126 | ||
127 | static int dev_memalloc_noio(struct device *dev, void *data) | ||
128 | { | ||
129 | return dev->power.memalloc_noio; | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * pm_runtime_set_memalloc_noio - Set a device's memalloc_noio flag. | ||
134 | * @dev: Device to handle. | ||
135 | * @enable: True for setting the flag and False for clearing the flag. | ||
136 | * | ||
137 | * Set the flag for all devices in the path from the device to the | ||
138 | * root device in the device tree if @enable is true, otherwise clear | ||
139 | * the flag for devices in the path whose siblings don't set the flag. | ||
140 | * | ||
141 | * The function should only be called by block device, or network | ||
142 | * device driver for solving the deadlock problem during runtime | ||
143 | * resume/suspend: | ||
144 | * | ||
145 | * If memory allocation with GFP_KERNEL is called inside runtime | ||
146 | * resume/suspend callback of any one of its ancestors(or the | ||
147 | * block device itself), the deadlock may be triggered inside the | ||
148 | * memory allocation since it might not complete until the block | ||
149 | * device becomes active and the involed page I/O finishes. The | ||
150 | * situation is pointed out first by Alan Stern. Network device | ||
151 | * are involved in iSCSI kind of situation. | ||
152 | * | ||
153 | * The lock of dev_hotplug_mutex is held in the function for handling | ||
154 | * hotplug race because pm_runtime_set_memalloc_noio() may be called | ||
155 | * in async probe(). | ||
156 | * | ||
157 | * The function should be called between device_add() and device_del() | ||
158 | * on the affected device(block/network device). | ||
159 | */ | ||
160 | void pm_runtime_set_memalloc_noio(struct device *dev, bool enable) | ||
161 | { | ||
162 | static DEFINE_MUTEX(dev_hotplug_mutex); | ||
163 | |||
164 | mutex_lock(&dev_hotplug_mutex); | ||
165 | for (;;) { | ||
166 | bool enabled; | ||
167 | |||
168 | /* hold power lock since bitfield is not SMP-safe. */ | ||
169 | spin_lock_irq(&dev->power.lock); | ||
170 | enabled = dev->power.memalloc_noio; | ||
171 | dev->power.memalloc_noio = enable; | ||
172 | spin_unlock_irq(&dev->power.lock); | ||
173 | |||
174 | /* | ||
175 | * not need to enable ancestors any more if the device | ||
176 | * has been enabled. | ||
177 | */ | ||
178 | if (enabled && enable) | ||
179 | break; | ||
180 | |||
181 | dev = dev->parent; | ||
182 | |||
183 | /* | ||
184 | * clear flag of the parent device only if all the | ||
185 | * children don't set the flag because ancestor's | ||
186 | * flag was set by any one of the descendants. | ||
187 | */ | ||
188 | if (!dev || (!enable && | ||
189 | device_for_each_child(dev, NULL, | ||
190 | dev_memalloc_noio))) | ||
191 | break; | ||
192 | } | ||
193 | mutex_unlock(&dev_hotplug_mutex); | ||
194 | } | ||
195 | EXPORT_SYMBOL_GPL(pm_runtime_set_memalloc_noio); | ||
196 | |||
127 | /** | 197 | /** |
128 | * rpm_check_suspend_allowed - Test whether a device may be suspended. | 198 | * rpm_check_suspend_allowed - Test whether a device may be suspended. |
129 | * @dev: Device to test. | 199 | * @dev: Device to test. |