|
@@ -322,7 +322,7 @@ static void __call_usermodehelper(struct work_struct *work)
|
|
|
* land has been frozen during a system-wide hibernation or suspend operation).
|
|
|
* Should always be manipulated under umhelper_sem acquired for write.
|
|
|
*/
|
|
|
-static int usermodehelper_disabled = 1;
|
|
|
+static enum umh_disable_depth usermodehelper_disabled = UMH_DISABLED;
|
|
|
|
|
|
/* Number of helpers running */
|
|
|
static atomic_t running_helpers = ATOMIC_INIT(0);
|
|
@@ -347,13 +347,30 @@ static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_disabled_waitq);
|
|
|
|
|
|
int usermodehelper_read_trylock(void)
|
|
|
{
|
|
|
+ DEFINE_WAIT(wait);
|
|
|
int ret = 0;
|
|
|
|
|
|
down_read(&umhelper_sem);
|
|
|
- if (usermodehelper_disabled) {
|
|
|
+ for (;;) {
|
|
|
+ prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
|
|
|
+ TASK_INTERRUPTIBLE);
|
|
|
+ if (!usermodehelper_disabled)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (usermodehelper_disabled == UMH_DISABLED)
|
|
|
+ ret = -EAGAIN;
|
|
|
+
|
|
|
up_read(&umhelper_sem);
|
|
|
- ret = -EAGAIN;
|
|
|
+
|
|
|
+ if (ret)
|
|
|
+ break;
|
|
|
+
|
|
|
+ schedule();
|
|
|
+ try_to_freeze();
|
|
|
+
|
|
|
+ down_read(&umhelper_sem);
|
|
|
}
|
|
|
+ finish_wait(&usermodehelper_disabled_waitq, &wait);
|
|
|
return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
|
|
@@ -392,25 +409,35 @@ void usermodehelper_read_unlock(void)
|
|
|
EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
|
|
|
|
|
|
/**
|
|
|
- * usermodehelper_enable - allow new helpers to be started again
|
|
|
+ * __usermodehelper_set_disable_depth - Modify usermodehelper_disabled.
|
|
|
+ * depth: New value to assign to usermodehelper_disabled.
|
|
|
+ *
|
|
|
+ * Change the value of usermodehelper_disabled (under umhelper_sem locked for
|
|
|
+ * writing) and wakeup tasks waiting for it to change.
|
|
|
*/
|
|
|
-void usermodehelper_enable(void)
|
|
|
+void __usermodehelper_set_disable_depth(enum umh_disable_depth depth)
|
|
|
{
|
|
|
down_write(&umhelper_sem);
|
|
|
- usermodehelper_disabled = 0;
|
|
|
+ usermodehelper_disabled = depth;
|
|
|
wake_up(&usermodehelper_disabled_waitq);
|
|
|
up_write(&umhelper_sem);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * usermodehelper_disable - prevent new helpers from being started
|
|
|
+ * __usermodehelper_disable - Prevent new helpers from being started.
|
|
|
+ * @depth: New value to assign to usermodehelper_disabled.
|
|
|
+ *
|
|
|
+ * Set usermodehelper_disabled to @depth and wait for running helpers to exit.
|
|
|
*/
|
|
|
-int usermodehelper_disable(void)
|
|
|
+int __usermodehelper_disable(enum umh_disable_depth depth)
|
|
|
{
|
|
|
long retval;
|
|
|
|
|
|
+ if (!depth)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
down_write(&umhelper_sem);
|
|
|
- usermodehelper_disabled = 1;
|
|
|
+ usermodehelper_disabled = depth;
|
|
|
up_write(&umhelper_sem);
|
|
|
|
|
|
/*
|
|
@@ -425,7 +452,7 @@ int usermodehelper_disable(void)
|
|
|
if (retval)
|
|
|
return 0;
|
|
|
|
|
|
- usermodehelper_enable();
|
|
|
+ __usermodehelper_set_disable_depth(UMH_ENABLED);
|
|
|
return -EAGAIN;
|
|
|
}
|
|
|
|