Index: 2.4.x-xfs/include/linux/kmod.h =================================================================== --- 2.4.x-xfs.orig/include/linux/kmod.h 2004-11-22 13:47:17.000000000 +1100 +++ 2.4.x-xfs/include/linux/kmod.h 2006-08-15 17:13:48.751783409 +1000 @@ -30,6 +30,7 @@ extern int exec_usermodehelper(char *program_path, char *argv[], char *envp[]); extern int call_usermodehelper(char *path, char *argv[], char *envp[]); +extern int __call_usermodehelper(char *path, char *argv[], char *envp[], int wait); #ifdef CONFIG_HOTPLUG extern char hotplug_path []; Index: 2.4.x-xfs/kernel/kmod.c =================================================================== --- 2.4.x-xfs.orig/kernel/kmod.c 2006-08-15 16:50:47.494091873 +1000 +++ 2.4.x-xfs/kernel/kmod.c 2006-08-15 17:13:48.751783409 +1000 @@ -14,6 +14,9 @@ Unblock all signals when we exec a usermode process. Shuu Yamaguchi December 2000 + + Add wait flag to call_usermodehelper. Based on a patch from Rusty Russell. + Marcel Holtmann Jan 2003 */ #define __KERNEL_SYSCALLS__ @@ -175,7 +178,7 @@ * If module auto-loading support is disabled then this function * becomes a no-operation. */ -int request_module(const char * module_name) +int request_module(const char *module_name) { pid_t pid; int waitpid_result; @@ -273,7 +276,8 @@ char *path; char **argv; char **envp; - pid_t retval; + int wait; + int retval; }; /* @@ -289,26 +293,58 @@ retval = exec_usermodehelper(sub_info->path, sub_info->argv, sub_info->envp); /* Exec failed? */ - sub_info->retval = (pid_t)retval; + sub_info->retval = retval; do_exit(0); } -/* - * This is run by keventd. +/* + * Keventd can't block, but this (a child) can. */ -static void __call_usermodehelper(void *data) +static int wait_for_helper(void *data) { struct subprocess_info *sub_info = data; pid_t pid; - /* - * CLONE_VFORK: wait until the usermode helper has execve'd successfully - * We need the data structures to stay around until that is done. - */ - pid = kernel_thread(____call_usermodehelper, sub_info, CLONE_VFORK | SIGCHLD); + pid = kernel_thread(____call_usermodehelper, sub_info, + CLONE_VFORK | SIGCHLD); if (pid < 0) sub_info->retval = pid; + else + sys_wait4(pid, (unsigned int *)&sub_info->retval, 0, NULL); + complete(sub_info->complete); + return 0; +} + +/* + * This is run by keventd. + */ +static void __call_usermodehelper_data(void *data) +{ + struct subprocess_info *sub_info = data; + pid_t pid; + + /* CLONE_VFORK: wait until the usermode helper has execve'd + * successfully We need the data structures to stay around + * until that is done. */ + if (sub_info->wait) + pid = kernel_thread(wait_for_helper, sub_info, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); + else + pid = kernel_thread(____call_usermodehelper, sub_info, + CLONE_VFORK | SIGCHLD); + + if (pid < 0) { + sub_info->retval = pid; + complete(sub_info->complete); + } else if (!sub_info->wait) + complete(sub_info->complete); +} + + +int call_usermodehelper(char *path, char *argv[], char *envp[]) +{ + return __call_usermodehelper(path, argv, envp, 0); } /** @@ -316,15 +352,17 @@ * @path: pathname for the application * @argv: null-terminated argument list * @envp: null-terminated environment list + * @wait: wait for the application to finish and return status. * - * Runs a user-space application. The application is started asynchronously. It - * runs as a child of keventd. It runs with full root capabilities. keventd silently - * reaps the child when it exits. + * Runs a user-space application. The application is started + * asynchronously if wait is not set, and runs as a child of keventd. + * (ie. it runs with full root capabilities). * - * Must be called from process context. Returns zero on success, else a negative - * error code. + * Must be called from process context. Returns a negative error code + * if program was not execed successfully, or (exitcode << 8 + signal) + * of the application (0 if wait is not set). */ -int call_usermodehelper(char *path, char **argv, char **envp) +int __call_usermodehelper(char *path, char *argv[], char *envp[], int wait) { DECLARE_COMPLETION(work); struct subprocess_info sub_info = { @@ -332,10 +370,11 @@ path: path, argv: argv, envp: envp, + wait: wait, retval: 0, }; struct tq_struct tqs = { - routine: __call_usermodehelper, + routine: __call_usermodehelper_data, data: &sub_info, }; @@ -344,7 +383,7 @@ if (current_is_keventd()) { /* We can't wait on keventd! */ - __call_usermodehelper(&sub_info); + __call_usermodehelper_data(&sub_info); } else { schedule_task(&tqs); wait_for_completion(&work); @@ -371,8 +410,8 @@ EXPORT_SYMBOL(exec_usermodehelper); EXPORT_SYMBOL(call_usermodehelper); +EXPORT_SYMBOL(__call_usermodehelper); #ifdef CONFIG_KMOD EXPORT_SYMBOL(request_module); #endif -