aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/kmod.h21
-rw-r--r--kernel/kmod.c47
-rw-r--r--kernel/power/process.c3
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
111extern struct ctl_table usermodehelper_table[]; 111extern struct ctl_table usermodehelper_table[];
112 112
113enum umh_disable_depth {
114 UMH_ENABLED = 0,
115 UMH_FREEZING,
116 UMH_DISABLED,
117};
118
113extern void usermodehelper_init(void); 119extern void usermodehelper_init(void);
114 120
115extern int usermodehelper_disable(void); 121extern int __usermodehelper_disable(enum umh_disable_depth depth);
116extern void usermodehelper_enable(void); 122extern void __usermodehelper_set_disable_depth(enum umh_disable_depth depth);
123
124static inline int usermodehelper_disable(void)
125{
126 return __usermodehelper_disable(UMH_DISABLED);
127}
128
129static inline void usermodehelper_enable(void)
130{
131 __usermodehelper_set_disable_depth(UMH_ENABLED);
132}
133
117extern int usermodehelper_read_trylock(void); 134extern int usermodehelper_read_trylock(void);
118extern long usermodehelper_read_lock_wait(long timeout); 135extern long usermodehelper_read_lock_wait(long timeout);
119extern void usermodehelper_read_unlock(void); 136extern 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 */
325static int usermodehelper_disabled = 1; 325static enum umh_disable_depth usermodehelper_disabled = UMH_DISABLED;
326 326
327/* Number of helpers running */ 327/* Number of helpers running */
328static atomic_t running_helpers = ATOMIC_INIT(0); 328static atomic_t running_helpers = ATOMIC_INIT(0);
@@ -347,13 +347,30 @@ static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_disabled_waitq);
347 347
348int usermodehelper_read_trylock(void) 348int 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}
359EXPORT_SYMBOL_GPL(usermodehelper_read_trylock); 376EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
@@ -392,25 +409,35 @@ void usermodehelper_read_unlock(void)
392EXPORT_SYMBOL_GPL(usermodehelper_read_unlock); 409EXPORT_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 */
397void usermodehelper_enable(void) 418void __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 */
408int usermodehelper_disable(void) 432int __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");