diff options
-rw-r--r-- | include/linux/kmod.h | 21 | ||||
-rw-r--r-- | kernel/kmod.c | 47 | ||||
-rw-r--r-- | kernel/power/process.c | 3 |
3 files changed, 58 insertions, 13 deletions
diff --git a/include/linux/kmod.h b/include/linux/kmod.h index b087377ae2c4..dd99c329e161 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h | |||
@@ -110,10 +110,27 @@ call_usermodehelper(char *path, char **argv, char **envp, int wait) | |||
110 | 110 | ||
111 | extern struct ctl_table usermodehelper_table[]; | 111 | extern struct ctl_table usermodehelper_table[]; |
112 | 112 | ||
113 | enum umh_disable_depth { | ||
114 | UMH_ENABLED = 0, | ||
115 | UMH_FREEZING, | ||
116 | UMH_DISABLED, | ||
117 | }; | ||
118 | |||
113 | extern void usermodehelper_init(void); | 119 | extern void usermodehelper_init(void); |
114 | 120 | ||
115 | extern int usermodehelper_disable(void); | 121 | extern int __usermodehelper_disable(enum umh_disable_depth depth); |
116 | extern void usermodehelper_enable(void); | 122 | extern void __usermodehelper_set_disable_depth(enum umh_disable_depth depth); |
123 | |||
124 | static inline int usermodehelper_disable(void) | ||
125 | { | ||
126 | return __usermodehelper_disable(UMH_DISABLED); | ||
127 | } | ||
128 | |||
129 | static inline void usermodehelper_enable(void) | ||
130 | { | ||
131 | __usermodehelper_set_disable_depth(UMH_ENABLED); | ||
132 | } | ||
133 | |||
117 | extern int usermodehelper_read_trylock(void); | 134 | extern int usermodehelper_read_trylock(void); |
118 | extern long usermodehelper_read_lock_wait(long timeout); | 135 | extern long usermodehelper_read_lock_wait(long timeout); |
119 | extern void usermodehelper_read_unlock(void); | 136 | extern void usermodehelper_read_unlock(void); |
diff --git a/kernel/kmod.c b/kernel/kmod.c index da7fcca279f9..05698a7415fe 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
@@ -322,7 +322,7 @@ static void __call_usermodehelper(struct work_struct *work) | |||
322 | * land has been frozen during a system-wide hibernation or suspend operation). | 322 | * land has been frozen during a system-wide hibernation or suspend operation). |
323 | * Should always be manipulated under umhelper_sem acquired for write. | 323 | * Should always be manipulated under umhelper_sem acquired for write. |
324 | */ | 324 | */ |
325 | static int usermodehelper_disabled = 1; | 325 | static enum umh_disable_depth usermodehelper_disabled = UMH_DISABLED; |
326 | 326 | ||
327 | /* Number of helpers running */ | 327 | /* Number of helpers running */ |
328 | static atomic_t running_helpers = ATOMIC_INIT(0); | 328 | static atomic_t running_helpers = ATOMIC_INIT(0); |
@@ -347,13 +347,30 @@ static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_disabled_waitq); | |||
347 | 347 | ||
348 | int usermodehelper_read_trylock(void) | 348 | int usermodehelper_read_trylock(void) |
349 | { | 349 | { |
350 | DEFINE_WAIT(wait); | ||
350 | int ret = 0; | 351 | int ret = 0; |
351 | 352 | ||
352 | down_read(&umhelper_sem); | 353 | down_read(&umhelper_sem); |
353 | if (usermodehelper_disabled) { | 354 | for (;;) { |
355 | prepare_to_wait(&usermodehelper_disabled_waitq, &wait, | ||
356 | TASK_INTERRUPTIBLE); | ||
357 | if (!usermodehelper_disabled) | ||
358 | break; | ||
359 | |||
360 | if (usermodehelper_disabled == UMH_DISABLED) | ||
361 | ret = -EAGAIN; | ||
362 | |||
354 | up_read(&umhelper_sem); | 363 | up_read(&umhelper_sem); |
355 | ret = -EAGAIN; | 364 | |
365 | if (ret) | ||
366 | break; | ||
367 | |||
368 | schedule(); | ||
369 | try_to_freeze(); | ||
370 | |||
371 | down_read(&umhelper_sem); | ||
356 | } | 372 | } |
373 | finish_wait(&usermodehelper_disabled_waitq, &wait); | ||
357 | return ret; | 374 | return ret; |
358 | } | 375 | } |
359 | EXPORT_SYMBOL_GPL(usermodehelper_read_trylock); | 376 | EXPORT_SYMBOL_GPL(usermodehelper_read_trylock); |
@@ -392,25 +409,35 @@ void usermodehelper_read_unlock(void) | |||
392 | EXPORT_SYMBOL_GPL(usermodehelper_read_unlock); | 409 | EXPORT_SYMBOL_GPL(usermodehelper_read_unlock); |
393 | 410 | ||
394 | /** | 411 | /** |
395 | * usermodehelper_enable - allow new helpers to be started again | 412 | * __usermodehelper_set_disable_depth - Modify usermodehelper_disabled. |
413 | * depth: New value to assign to usermodehelper_disabled. | ||
414 | * | ||
415 | * Change the value of usermodehelper_disabled (under umhelper_sem locked for | ||
416 | * writing) and wakeup tasks waiting for it to change. | ||
396 | */ | 417 | */ |
397 | void usermodehelper_enable(void) | 418 | void __usermodehelper_set_disable_depth(enum umh_disable_depth depth) |
398 | { | 419 | { |
399 | down_write(&umhelper_sem); | 420 | down_write(&umhelper_sem); |
400 | usermodehelper_disabled = 0; | 421 | usermodehelper_disabled = depth; |
401 | wake_up(&usermodehelper_disabled_waitq); | 422 | wake_up(&usermodehelper_disabled_waitq); |
402 | up_write(&umhelper_sem); | 423 | up_write(&umhelper_sem); |
403 | } | 424 | } |
404 | 425 | ||
405 | /** | 426 | /** |
406 | * usermodehelper_disable - prevent new helpers from being started | 427 | * __usermodehelper_disable - Prevent new helpers from being started. |
428 | * @depth: New value to assign to usermodehelper_disabled. | ||
429 | * | ||
430 | * Set usermodehelper_disabled to @depth and wait for running helpers to exit. | ||
407 | */ | 431 | */ |
408 | int usermodehelper_disable(void) | 432 | int __usermodehelper_disable(enum umh_disable_depth depth) |
409 | { | 433 | { |
410 | long retval; | 434 | long retval; |
411 | 435 | ||
436 | if (!depth) | ||
437 | return -EINVAL; | ||
438 | |||
412 | down_write(&umhelper_sem); | 439 | down_write(&umhelper_sem); |
413 | usermodehelper_disabled = 1; | 440 | usermodehelper_disabled = depth; |
414 | up_write(&umhelper_sem); | 441 | up_write(&umhelper_sem); |
415 | 442 | ||
416 | /* | 443 | /* |
@@ -425,7 +452,7 @@ int usermodehelper_disable(void) | |||
425 | if (retval) | 452 | if (retval) |
426 | return 0; | 453 | return 0; |
427 | 454 | ||
428 | usermodehelper_enable(); | 455 | __usermodehelper_set_disable_depth(UMH_ENABLED); |
429 | return -EAGAIN; | 456 | return -EAGAIN; |
430 | } | 457 | } |
431 | 458 | ||
diff --git a/kernel/power/process.c b/kernel/power/process.c index 56eaac7e88ab..19db29f67558 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
@@ -123,7 +123,7 @@ int freeze_processes(void) | |||
123 | { | 123 | { |
124 | int error; | 124 | int error; |
125 | 125 | ||
126 | error = usermodehelper_disable(); | 126 | error = __usermodehelper_disable(UMH_FREEZING); |
127 | if (error) | 127 | if (error) |
128 | return error; | 128 | return error; |
129 | 129 | ||
@@ -135,6 +135,7 @@ int freeze_processes(void) | |||
135 | error = try_to_freeze_tasks(true); | 135 | error = try_to_freeze_tasks(true); |
136 | if (!error) { | 136 | if (!error) { |
137 | printk("done."); | 137 | printk("done."); |
138 | __usermodehelper_set_disable_depth(UMH_DISABLED); | ||
138 | oom_killer_disable(); | 139 | oom_killer_disable(); |
139 | } | 140 | } |
140 | printk("\n"); | 141 | printk("\n"); |