aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kmod.c')
-rw-r--r--kernel/kmod.c47
1 files changed, 37 insertions, 10 deletions
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