diff options
| author | Oleg Nesterov <oleg@redhat.com> | 2012-03-23 15:02:47 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-23 16:58:41 -0700 | 
| commit | d0bd587a80960d7ba7e0c8396e154028c9045c54 (patch) | |
| tree | 3765f8eccdc5f982ba173a7a05d8981d573b9486 | |
| parent | b3449922502f5a161ee2b5022a33aec8472fbf18 (diff) | |
| download | olio-linux-3.10-d0bd587a80960d7ba7e0c8396e154028c9045c54.tar.xz olio-linux-3.10-d0bd587a80960d7ba7e0c8396e154028c9045c54.zip  | |
usermodehelper: implement UMH_KILLABLE
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".
Note: UMH_NO_WAIT == -1 but it obviously should not be used with
UMH_KILLABLE.  We delay the neccessary cleanup to simplify the back
porting.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Tejun Heo <tj@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | include/linux/kmod.h | 2 | ||||
| -rw-r--r-- | kernel/kmod.c | 27 | 
2 files changed, 27 insertions, 2 deletions
diff --git a/include/linux/kmod.h b/include/linux/kmod.h index 722f477c4ef..1b5985855ff 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h @@ -54,6 +54,8 @@ enum umh_wait {  	UMH_WAIT_PROC = 1,	/* wait for the process to complete */  }; +#define UMH_KILLABLE	4	/* wait for EXEC/PROC killable */ +  struct subprocess_info {  	struct work_struct work;  	struct completion *complete; diff --git a/kernel/kmod.c b/kernel/kmod.c index 8ea25944ce3..f92f917c450 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -201,7 +201,15 @@ EXPORT_SYMBOL(call_usermodehelper_freeinfo);  static void umh_complete(struct subprocess_info *sub_info)  { -	complete(sub_info->complete); +	struct completion *comp = xchg(&sub_info->complete, NULL); +	/* +	 * See call_usermodehelper_exec(). If xchg() returns NULL +	 * we own sub_info, the UMH_KILLABLE caller has gone away. +	 */ +	if (comp) +		complete(comp); +	else +		call_usermodehelper_freeinfo(sub_info);  }  /* Keventd can't block, but this (a child) can. */ @@ -252,6 +260,9 @@ static void __call_usermodehelper(struct work_struct *work)  	enum umh_wait wait = sub_info->wait;  	pid_t pid; +	if (wait != UMH_NO_WAIT) +		wait &= ~UMH_KILLABLE; +  	/* CLONE_VFORK: wait until the usermode helper has execve'd  	 * successfully We need the data structures to stay around  	 * until that is done.  */ @@ -461,9 +472,21 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info,  	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; + +		/* umh_complete() will see NULL and free sub_info */ +		if (xchg(&sub_info->complete, NULL)) +			goto unlock; +		/* fallthrough, umh_complete() was already called */ +	} +  	wait_for_completion(&done); +wait_done:  	retval = sub_info->retval; -  out:  	call_usermodehelper_freeinfo(sub_info);  unlock:  |