In the blasphemous occasions that the Kernel must call a user-mode program half of the times it is more robust to not wait forever but limit the wait for a specified timeout. So add a new call_usermodehelper_timeout() that implements that. (Users of this new API will be added once this API is in mainline) call_usermodehelper_fns() is added an extra timeout parameter which is then implemented in call_usermodehelper_exec. The few users of call_usermodehelper_fns() are also changed in this patch. Also an gfp_t parameter is added, for finer allocation control The code in call_usermodehelper_exec is simplified by the use of the all-mighty wait_for_completion_timeout_state() which is able to wait in all the different modes. See: completion: Add wait_for_completion_timeout_state() Should some wait-forever callers today, be converted to this new schema? CC: Trond Myklebust <Trond.Myklebust@xxxxxxxxxx> Signed-off-by: Boaz Harrosh <bharrosh@xxxxxxxxxxx> --- fs/exec.c | 4 ++-- include/linux/kmod.h | 19 ++++++++++++++----- kernel/kmod.c | 24 ++++++++++++------------ kernel/sys.c | 2 +- security/keys/request_key.c | 2 +- 5 files changed, 30 insertions(+), 21 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 23559c2..8789ba8 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -2185,8 +2185,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) } retval = call_usermodehelper_fns(helper_argv[0], helper_argv, - NULL, UMH_WAIT_EXEC, umh_pipe_setup, - NULL, &cprm); + NULL, UMH_WAIT_EXEC, 0, 0, + umh_pipe_setup, NULL, &cprm); argv_free(helper_argv); if (retval) { printk(KERN_INFO "Core dump to %s pipe failed\n", diff --git a/include/linux/kmod.h b/include/linux/kmod.h index ae3f9623..4d9f202 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h @@ -60,21 +60,30 @@ struct subprocess_info { char **argv; char **envp; int wait; + unsigned long timeout; int retval; int (*init)(struct subprocess_info *info, struct cred *new); void (*cleanup)(struct subprocess_info *info); void *data; }; -extern int -call_usermodehelper_fns(char *path, char **argv, char **envp, int wait, - int (*init)(struct subprocess_info *info, struct cred *new), - void (*cleanup)(struct subprocess_info *), void *data); +extern int call_usermodehelper_fns(char *path, char **argv, char **envp, + int wait, unsigned long timeout, gfp_t gfp, + int (*init)(struct subprocess_info *info, struct cred *new), + void (*cleanup)(struct subprocess_info *), void *data); static inline int call_usermodehelper(char *path, char **argv, char **envp, int wait) { - return call_usermodehelper_fns(path, argv, envp, wait, + return call_usermodehelper_fns(path, argv, envp, wait, 0, 0, + NULL, NULL, NULL); +} + +static inline int +call_usermodehelper_timeout(char *path, char **argv, char **envp, + int wait, unsigned long timeout, gfp_t gfp) +{ + return call_usermodehelper_fns(path, argv, envp, wait, timeout, gfp, NULL, NULL, NULL); } diff --git a/kernel/kmod.c b/kernel/kmod.c index b404f99..588cb6f 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -90,7 +90,7 @@ static int call_modprobe(char *module_name, int wait) argv[4] = NULL; return call_usermodehelper_fns(modprobe_path, argv, envp, - wait | UMH_KILLABLE, NULL, free_modprobe_argv, NULL); + wait | UMH_KILLABLE, 0, 0, NULL, free_modprobe_argv, NULL); free_argv: kfree(argv); out: @@ -522,6 +522,7 @@ void call_usermodehelper_setfns(struct subprocess_info *info, int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait) { DECLARE_COMPLETION_ONSTACK(done); + int wait_state; int retval = 0; helper_lock(); @@ -540,19 +541,15 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait) 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; - + wait_state = (wait & UMH_KILLABLE) ? TASK_KILLABLE : 0; + retval = wait_for_completion_timeout_state(&done, sub_info->timeout, + wait_state); + if (unlikely(retval)) { /* 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); @@ -561,13 +558,15 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait) return retval; } -int call_usermodehelper_fns( - char *path, char **argv, char **envp, int wait, +int call_usermodehelper_fns(char *path, char **argv, char **envp, + int wait, unsigned long timeout, gfp_t gfp_mask, int (*init)(struct subprocess_info *info, struct cred *new), void (*cleanup)(struct subprocess_info *), void *data) { struct subprocess_info *info; - gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; + + if (!gfp_mask) + gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; info = call_usermodehelper_setup(path, argv, envp, gfp_mask); @@ -575,6 +574,7 @@ int call_usermodehelper_fns( return -ENOMEM; call_usermodehelper_setfns(info, init, cleanup, data); + info->timeout = timeout; return call_usermodehelper_exec(info, wait); } diff --git a/kernel/sys.c b/kernel/sys.c index 37b1971..16d14d1 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -2020,7 +2020,7 @@ int orderly_poweroff(bool force) goto out; } - ret = call_usermodehelper_fns(argv[0], argv, envp, UMH_NO_WAIT, + ret = call_usermodehelper_fns(argv[0], argv, envp, UMH_NO_WAIT, 0, 0, NULL, argv_cleanup, NULL); out: if (likely(!ret)) diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 000e750..aa94dbb 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -93,7 +93,7 @@ static void umh_keys_cleanup(struct subprocess_info *info) static int call_usermodehelper_keys(char *path, char **argv, char **envp, struct key *session_keyring, int wait) { - return call_usermodehelper_fns(path, argv, envp, wait, + return call_usermodehelper_fns(path, argv, envp, wait, 0, 0, umh_keys_init, umh_keys_cleanup, key_get(session_keyring)); } -- 1.7.6.5 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html