diff options
Diffstat (limited to 'kernel/kmod.c')
-rw-r--r-- | kernel/kmod.c | 117 |
1 files changed, 87 insertions, 30 deletions
diff --git a/kernel/kmod.c b/kernel/kmod.c index 957a7aab8ebc..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); |
@@ -334,32 +334,110 @@ static atomic_t running_helpers = ATOMIC_INIT(0); | |||
334 | static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq); | 334 | static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq); |
335 | 335 | ||
336 | /* | 336 | /* |
337 | * Used by usermodehelper_read_lock_wait() to wait for usermodehelper_disabled | ||
338 | * to become 'false'. | ||
339 | */ | ||
340 | static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_disabled_waitq); | ||
341 | |||
342 | /* | ||
337 | * Time to wait for running_helpers to become zero before the setting of | 343 | * Time to wait for running_helpers to become zero before the setting of |
338 | * usermodehelper_disabled in usermodehelper_disable() fails | 344 | * usermodehelper_disabled in usermodehelper_disable() fails |
339 | */ | 345 | */ |
340 | #define RUNNING_HELPERS_TIMEOUT (5 * HZ) | 346 | #define RUNNING_HELPERS_TIMEOUT (5 * HZ) |
341 | 347 | ||
342 | void read_lock_usermodehelper(void) | 348 | int usermodehelper_read_trylock(void) |
343 | { | 349 | { |
350 | DEFINE_WAIT(wait); | ||
351 | int ret = 0; | ||
352 | |||
344 | down_read(&umhelper_sem); | 353 | down_read(&umhelper_sem); |
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 | |||
363 | up_read(&umhelper_sem); | ||
364 | |||
365 | if (ret) | ||
366 | break; | ||
367 | |||
368 | schedule(); | ||
369 | try_to_freeze(); | ||
370 | |||
371 | down_read(&umhelper_sem); | ||
372 | } | ||
373 | finish_wait(&usermodehelper_disabled_waitq, &wait); | ||
374 | return ret; | ||
375 | } | ||
376 | EXPORT_SYMBOL_GPL(usermodehelper_read_trylock); | ||
377 | |||
378 | long usermodehelper_read_lock_wait(long timeout) | ||
379 | { | ||
380 | DEFINE_WAIT(wait); | ||
381 | |||
382 | if (timeout < 0) | ||
383 | return -EINVAL; | ||
384 | |||
385 | down_read(&umhelper_sem); | ||
386 | for (;;) { | ||
387 | prepare_to_wait(&usermodehelper_disabled_waitq, &wait, | ||
388 | TASK_UNINTERRUPTIBLE); | ||
389 | if (!usermodehelper_disabled) | ||
390 | break; | ||
391 | |||
392 | up_read(&umhelper_sem); | ||
393 | |||
394 | timeout = schedule_timeout(timeout); | ||
395 | if (!timeout) | ||
396 | break; | ||
397 | |||
398 | down_read(&umhelper_sem); | ||
399 | } | ||
400 | finish_wait(&usermodehelper_disabled_waitq, &wait); | ||
401 | return timeout; | ||
345 | } | 402 | } |
346 | EXPORT_SYMBOL_GPL(read_lock_usermodehelper); | 403 | EXPORT_SYMBOL_GPL(usermodehelper_read_lock_wait); |
347 | 404 | ||
348 | void read_unlock_usermodehelper(void) | 405 | void usermodehelper_read_unlock(void) |
349 | { | 406 | { |
350 | up_read(&umhelper_sem); | 407 | up_read(&umhelper_sem); |
351 | } | 408 | } |
352 | EXPORT_SYMBOL_GPL(read_unlock_usermodehelper); | 409 | EXPORT_SYMBOL_GPL(usermodehelper_read_unlock); |
353 | 410 | ||
354 | /** | 411 | /** |
355 | * usermodehelper_disable - prevent new helpers from being started | 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. | ||
356 | */ | 417 | */ |
357 | int usermodehelper_disable(void) | 418 | void __usermodehelper_set_disable_depth(enum umh_disable_depth depth) |
419 | { | ||
420 | down_write(&umhelper_sem); | ||
421 | usermodehelper_disabled = depth; | ||
422 | wake_up(&usermodehelper_disabled_waitq); | ||
423 | up_write(&umhelper_sem); | ||
424 | } | ||
425 | |||
426 | /** | ||
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. | ||
431 | */ | ||
432 | int __usermodehelper_disable(enum umh_disable_depth depth) | ||
358 | { | 433 | { |
359 | long retval; | 434 | long retval; |
360 | 435 | ||
436 | if (!depth) | ||
437 | return -EINVAL; | ||
438 | |||
361 | down_write(&umhelper_sem); | 439 | down_write(&umhelper_sem); |
362 | usermodehelper_disabled = 1; | 440 | usermodehelper_disabled = depth; |
363 | up_write(&umhelper_sem); | 441 | up_write(&umhelper_sem); |
364 | 442 | ||
365 | /* | 443 | /* |
@@ -374,31 +452,10 @@ int usermodehelper_disable(void) | |||
374 | if (retval) | 452 | if (retval) |
375 | return 0; | 453 | return 0; |
376 | 454 | ||
377 | down_write(&umhelper_sem); | 455 | __usermodehelper_set_disable_depth(UMH_ENABLED); |
378 | usermodehelper_disabled = 0; | ||
379 | up_write(&umhelper_sem); | ||
380 | return -EAGAIN; | 456 | return -EAGAIN; |
381 | } | 457 | } |
382 | 458 | ||
383 | /** | ||
384 | * usermodehelper_enable - allow new helpers to be started again | ||
385 | */ | ||
386 | void usermodehelper_enable(void) | ||
387 | { | ||
388 | down_write(&umhelper_sem); | ||
389 | usermodehelper_disabled = 0; | ||
390 | up_write(&umhelper_sem); | ||
391 | } | ||
392 | |||
393 | /** | ||
394 | * usermodehelper_is_disabled - check if new helpers are allowed to be started | ||
395 | */ | ||
396 | bool usermodehelper_is_disabled(void) | ||
397 | { | ||
398 | return usermodehelper_disabled; | ||
399 | } | ||
400 | EXPORT_SYMBOL_GPL(usermodehelper_is_disabled); | ||
401 | |||
402 | static void helper_lock(void) | 459 | static void helper_lock(void) |
403 | { | 460 | { |
404 | atomic_inc(&running_helpers); | 461 | atomic_inc(&running_helpers); |