diff options
Diffstat (limited to 'kernel/kmod.c')
-rw-r--r-- | kernel/kmod.c | 51 |
1 files changed, 29 insertions, 22 deletions
diff --git a/kernel/kmod.c b/kernel/kmod.c index bf0e231d9702..531ef62cf536 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
@@ -116,27 +116,16 @@ int __request_module(bool wait, const char *fmt, ...) | |||
116 | 116 | ||
117 | trace_module_request(module_name, wait, _RET_IP_); | 117 | trace_module_request(module_name, wait, _RET_IP_); |
118 | 118 | ||
119 | ret = call_usermodehelper(modprobe_path, argv, envp, | 119 | ret = call_usermodehelper_fns(modprobe_path, argv, envp, |
120 | wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC); | 120 | wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC, |
121 | NULL, NULL, NULL); | ||
122 | |||
121 | atomic_dec(&kmod_concurrent); | 123 | atomic_dec(&kmod_concurrent); |
122 | return ret; | 124 | return ret; |
123 | } | 125 | } |
124 | EXPORT_SYMBOL(__request_module); | 126 | EXPORT_SYMBOL(__request_module); |
125 | #endif /* CONFIG_MODULES */ | 127 | #endif /* CONFIG_MODULES */ |
126 | 128 | ||
127 | struct subprocess_info { | ||
128 | struct work_struct work; | ||
129 | struct completion *complete; | ||
130 | struct cred *cred; | ||
131 | char *path; | ||
132 | char **argv; | ||
133 | char **envp; | ||
134 | enum umh_wait wait; | ||
135 | int retval; | ||
136 | struct file *stdin; | ||
137 | void (*cleanup)(char **argv, char **envp); | ||
138 | }; | ||
139 | |||
140 | /* | 129 | /* |
141 | * This is the task which runs the usermode application | 130 | * This is the task which runs the usermode application |
142 | */ | 131 | */ |
@@ -184,9 +173,16 @@ static int ____call_usermodehelper(void *data) | |||
184 | */ | 173 | */ |
185 | set_user_nice(current, 0); | 174 | set_user_nice(current, 0); |
186 | 175 | ||
176 | if (sub_info->init) { | ||
177 | retval = sub_info->init(sub_info); | ||
178 | if (retval) | ||
179 | goto fail; | ||
180 | } | ||
181 | |||
187 | retval = kernel_execve(sub_info->path, sub_info->argv, sub_info->envp); | 182 | retval = kernel_execve(sub_info->path, sub_info->argv, sub_info->envp); |
188 | 183 | ||
189 | /* Exec failed? */ | 184 | /* Exec failed? */ |
185 | fail: | ||
190 | sub_info->retval = retval; | 186 | sub_info->retval = retval; |
191 | do_exit(0); | 187 | do_exit(0); |
192 | } | 188 | } |
@@ -194,7 +190,7 @@ static int ____call_usermodehelper(void *data) | |||
194 | void call_usermodehelper_freeinfo(struct subprocess_info *info) | 190 | void call_usermodehelper_freeinfo(struct subprocess_info *info) |
195 | { | 191 | { |
196 | if (info->cleanup) | 192 | if (info->cleanup) |
197 | (*info->cleanup)(info->argv, info->envp); | 193 | (*info->cleanup)(info); |
198 | if (info->cred) | 194 | if (info->cred) |
199 | put_cred(info->cred); | 195 | put_cred(info->cred); |
200 | kfree(info); | 196 | kfree(info); |
@@ -406,21 +402,31 @@ void call_usermodehelper_setkeys(struct subprocess_info *info, | |||
406 | EXPORT_SYMBOL(call_usermodehelper_setkeys); | 402 | EXPORT_SYMBOL(call_usermodehelper_setkeys); |
407 | 403 | ||
408 | /** | 404 | /** |
409 | * call_usermodehelper_setcleanup - set a cleanup function | 405 | * call_usermodehelper_setfns - set a cleanup/init function |
410 | * @info: a subprocess_info returned by call_usermodehelper_setup | 406 | * @info: a subprocess_info returned by call_usermodehelper_setup |
411 | * @cleanup: a cleanup function | 407 | * @cleanup: a cleanup function |
408 | * @init: an init function | ||
409 | * @data: arbitrary context sensitive data | ||
410 | * | ||
411 | * The init function is used to customize the helper process prior to | ||
412 | * exec. A non-zero return code causes the process to error out, exit, | ||
413 | * and return the failure to the calling process | ||
412 | * | 414 | * |
413 | * The cleanup function is just befor ethe subprocess_info is about to | 415 | * The cleanup function is just before ethe subprocess_info is about to |
414 | * be freed. This can be used for freeing the argv and envp. The | 416 | * be freed. This can be used for freeing the argv and envp. The |
415 | * Function must be runnable in either a process context or the | 417 | * Function must be runnable in either a process context or the |
416 | * context in which call_usermodehelper_exec is called. | 418 | * context in which call_usermodehelper_exec is called. |
417 | */ | 419 | */ |
418 | void call_usermodehelper_setcleanup(struct subprocess_info *info, | 420 | void call_usermodehelper_setfns(struct subprocess_info *info, |
419 | void (*cleanup)(char **argv, char **envp)) | 421 | int (*init)(struct subprocess_info *info), |
422 | void (*cleanup)(struct subprocess_info *info), | ||
423 | void *data) | ||
420 | { | 424 | { |
421 | info->cleanup = cleanup; | 425 | info->cleanup = cleanup; |
426 | info->init = init; | ||
427 | info->data = data; | ||
422 | } | 428 | } |
423 | EXPORT_SYMBOL(call_usermodehelper_setcleanup); | 429 | EXPORT_SYMBOL(call_usermodehelper_setfns); |
424 | 430 | ||
425 | /** | 431 | /** |
426 | * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin | 432 | * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin |
@@ -515,7 +521,8 @@ int call_usermodehelper_pipe(char *path, char **argv, char **envp, | |||
515 | struct subprocess_info *sub_info; | 521 | struct subprocess_info *sub_info; |
516 | int ret; | 522 | int ret; |
517 | 523 | ||
518 | sub_info = call_usermodehelper_setup(path, argv, envp, GFP_KERNEL); | 524 | sub_info = call_usermodehelper_setup(path, argv, envp, |
525 | GFP_KERNEL); | ||
519 | if (sub_info == NULL) | 526 | if (sub_info == NULL) |
520 | return -ENOMEM; | 527 | return -ENOMEM; |
521 | 528 | ||