[PATCH 3/5] usermodehelper: implement UMH_KILLABLE

From: Oleg Nesterov
Date: Tue Feb 07 2012 - 11:40:32 EST


Implement UMH_KILLABLE, should be used along with UMH_WAIT_EXEC/PROC.
The caller must ensure that subprocess_info->path/etc can not go away
until call_usermodehelper_freeinfo().

call_usermodehelper_exec(UMH_KILLABLE) does wait_for_completion_killable.
If it fails, it uses xchg(&sub_info->complete, NULL) to serialize with
umh_complete() which does the same xhcg() to access sub_info->complete.

If call_usermodehelper_exec wins, it can safely return. umh_complete()
should get NULL and call call_usermodehelper_freeinfo().

Otherwise we know that umh_complete() was already called, in this case
call_usermodehelper_exec() falls back to wait_for_completion() which
should succeed "very soon".
---
include/linux/kmod.h | 1 +
kernel/kmod.c | 23 ++++++++++++++++++++---
2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index 26187f2..9efeae6 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -51,6 +51,7 @@ struct file;
#define UMH_NO_WAIT 0 /* don't wait at all */
#define UMH_WAIT_EXEC 1 /* wait for the exec, but not the process */
#define UMH_WAIT_PROC 2 /* wait for the process to complete */
+#define UMH_KILLABLE 4 /* wait for EXEC/PROC killable */

struct subprocess_info {
struct work_struct work;
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 2443213..7452b4e 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -201,7 +201,12 @@ EXPORT_SYMBOL(call_usermodehelper_freeinfo);

static void umh_complete(struct subprocess_info *sub_info)
{
- complete(sub_info->complete);
+ struct completion *done = xchg(&sub_info->complete, NULL);
+
+ if (done)
+ complete(done);
+ else /* see call_usermodehelper_exec(), we own sub_info */
+ call_usermodehelper_freeinfo(sub_info);
}

/* Keventd can't block, but this (a child) can. */
@@ -455,14 +460,26 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
}

sub_info->complete = &done;
- sub_info->wait = wait;
+ sub_info->wait = (wait & ~UMH_KILLABLE);

queue_work(khelper_wq, &sub_info->work);
if (wait == UMH_NO_WAIT) /* task has freed sub_info */
goto unlock;
+
+ if (wait & UMH_KILLABLE) {
+ retval = wait_for_completion_killable(&done);
+ if (!retval)
+ goto wait_done;
+
+ /* see umh_complete()->call_usermodehelper_freeinfo() */
+ if (xchg(&sub_info->complete, NULL))
+ goto unlock;
+ /* wait for umh_complete()->complete() in progress... */
+ }
+
wait_for_completion(&done);
+wait_done:
retval = sub_info->retval;
-
out:
call_usermodehelper_freeinfo(sub_info);
unlock:
--
1.5.5.1


--FL5UXtIhxfXey3p5
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="0004-kmod-introduce-call_modprobe-helper.patch"