diff options
author | Lucas De Marchi <lucas.demarchi@profusion.mobi> | 2013-04-30 18:28:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-30 20:04:05 -0400 |
commit | 938e4b22e2a7d0f6f3962e601339347b2d8e09f5 (patch) | |
tree | 1d66004074a1306c20ce7e40eefc2839736e2ea0 | |
parent | 17afab1de42236ee2f6235f4383cc6f3f13f8a10 (diff) |
usermodehelper: export call_usermodehelper_exec() and call_usermodehelper_setup()
call_usermodehelper_setup() + call_usermodehelper_exec() need to be
called instead of call_usermodehelper_fns() when the cleanup function
needs to be called even when an ENOMEM error occurs. In this case using
call_usermodehelper_fns() the user can't distinguish if the cleanup
function was called or not.
[akpm@linux-foundation.org: export call_usermodehelper_setup() to modules]
Signed-off-by: Lucas De Marchi <lucas.demarchi@profusion.mobi>
Reviewed-by: Oleg Nesterov <oleg@redhat.com>
Cc: David Howells <dhowells@redhat.com>
Cc: James Morris <james.l.morris@oracle.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Tejun Heo <tj@kernel.org>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
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 | 8 | ||||
-rw-r--r-- | kernel/kmod.c | 57 |
2 files changed, 32 insertions, 33 deletions
diff --git a/include/linux/kmod.h b/include/linux/kmod.h index 5398d5807075..7eebcf5d75f1 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h | |||
@@ -71,6 +71,14 @@ call_usermodehelper_fns(char *path, char **argv, char **envp, int wait, | |||
71 | int (*init)(struct subprocess_info *info, struct cred *new), | 71 | int (*init)(struct subprocess_info *info, struct cred *new), |
72 | void (*cleanup)(struct subprocess_info *), void *data); | 72 | void (*cleanup)(struct subprocess_info *), void *data); |
73 | 73 | ||
74 | extern struct subprocess_info * | ||
75 | call_usermodehelper_setup(char *path, char **argv, char **envp, gfp_t gfp_mask, | ||
76 | int (*init)(struct subprocess_info *info, struct cred *new), | ||
77 | void (*cleanup)(struct subprocess_info *), void *data); | ||
78 | |||
79 | extern int | ||
80 | call_usermodehelper_exec(struct subprocess_info *info, int wait); | ||
81 | |||
74 | static inline int | 82 | static inline int |
75 | call_usermodehelper(char *path, char **argv, char **envp, int wait) | 83 | call_usermodehelper(char *path, char **argv, char **envp, int wait) |
76 | { | 84 | { |
diff --git a/kernel/kmod.c b/kernel/kmod.c index 56dd34976d7b..e11ea14ac011 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
@@ -502,14 +502,28 @@ static void helper_unlock(void) | |||
502 | * @argv: arg vector for process | 502 | * @argv: arg vector for process |
503 | * @envp: environment for process | 503 | * @envp: environment for process |
504 | * @gfp_mask: gfp mask for memory allocation | 504 | * @gfp_mask: gfp mask for memory allocation |
505 | * @cleanup: a cleanup function | ||
506 | * @init: an init function | ||
507 | * @data: arbitrary context sensitive data | ||
505 | * | 508 | * |
506 | * Returns either %NULL on allocation failure, or a subprocess_info | 509 | * Returns either %NULL on allocation failure, or a subprocess_info |
507 | * structure. This should be passed to call_usermodehelper_exec to | 510 | * structure. This should be passed to call_usermodehelper_exec to |
508 | * exec the process and free the structure. | 511 | * exec the process and free the structure. |
512 | * | ||
513 | * The init function is used to customize the helper process prior to | ||
514 | * exec. A non-zero return code causes the process to error out, exit, | ||
515 | * and return the failure to the calling process | ||
516 | * | ||
517 | * The cleanup function is just before ethe subprocess_info is about to | ||
518 | * be freed. This can be used for freeing the argv and envp. The | ||
519 | * Function must be runnable in either a process context or the | ||
520 | * context in which call_usermodehelper_exec is called. | ||
509 | */ | 521 | */ |
510 | static | ||
511 | struct subprocess_info *call_usermodehelper_setup(char *path, char **argv, | 522 | struct subprocess_info *call_usermodehelper_setup(char *path, char **argv, |
512 | char **envp, gfp_t gfp_mask) | 523 | char **envp, gfp_t gfp_mask, |
524 | int (*init)(struct subprocess_info *info, struct cred *new), | ||
525 | void (*cleanup)(struct subprocess_info *info), | ||
526 | void *data) | ||
513 | { | 527 | { |
514 | struct subprocess_info *sub_info; | 528 | struct subprocess_info *sub_info; |
515 | sub_info = kzalloc(sizeof(struct subprocess_info), gfp_mask); | 529 | sub_info = kzalloc(sizeof(struct subprocess_info), gfp_mask); |
@@ -520,36 +534,14 @@ struct subprocess_info *call_usermodehelper_setup(char *path, char **argv, | |||
520 | sub_info->path = path; | 534 | sub_info->path = path; |
521 | sub_info->argv = argv; | 535 | sub_info->argv = argv; |
522 | sub_info->envp = envp; | 536 | sub_info->envp = envp; |
537 | |||
538 | sub_info->cleanup = cleanup; | ||
539 | sub_info->init = init; | ||
540 | sub_info->data = data; | ||
523 | out: | 541 | out: |
524 | return sub_info; | 542 | return sub_info; |
525 | } | 543 | } |
526 | 544 | EXPORT_SYMBOL(call_usermodehelper_setup); | |
527 | /** | ||
528 | * call_usermodehelper_setfns - set a cleanup/init function | ||
529 | * @info: a subprocess_info returned by call_usermodehelper_setup | ||
530 | * @cleanup: a cleanup function | ||
531 | * @init: an init function | ||
532 | * @data: arbitrary context sensitive data | ||
533 | * | ||
534 | * The init function is used to customize the helper process prior to | ||
535 | * exec. A non-zero return code causes the process to error out, exit, | ||
536 | * and return the failure to the calling process | ||
537 | * | ||
538 | * The cleanup function is just before ethe subprocess_info is about to | ||
539 | * be freed. This can be used for freeing the argv and envp. The | ||
540 | * Function must be runnable in either a process context or the | ||
541 | * context in which call_usermodehelper_exec is called. | ||
542 | */ | ||
543 | static | ||
544 | void call_usermodehelper_setfns(struct subprocess_info *info, | ||
545 | int (*init)(struct subprocess_info *info, struct cred *new), | ||
546 | void (*cleanup)(struct subprocess_info *info), | ||
547 | void *data) | ||
548 | { | ||
549 | info->cleanup = cleanup; | ||
550 | info->init = init; | ||
551 | info->data = data; | ||
552 | } | ||
553 | 545 | ||
554 | /** | 546 | /** |
555 | * call_usermodehelper_exec - start a usermode application | 547 | * call_usermodehelper_exec - start a usermode application |
@@ -563,7 +555,6 @@ void call_usermodehelper_setfns(struct subprocess_info *info, | |||
563 | * asynchronously if wait is not set, and runs as a child of keventd. | 555 | * asynchronously if wait is not set, and runs as a child of keventd. |
564 | * (ie. it runs with full root capabilities). | 556 | * (ie. it runs with full root capabilities). |
565 | */ | 557 | */ |
566 | static | ||
567 | int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait) | 558 | int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait) |
568 | { | 559 | { |
569 | DECLARE_COMPLETION_ONSTACK(done); | 560 | DECLARE_COMPLETION_ONSTACK(done); |
@@ -615,6 +606,7 @@ unlock: | |||
615 | helper_unlock(); | 606 | helper_unlock(); |
616 | return retval; | 607 | return retval; |
617 | } | 608 | } |
609 | EXPORT_SYMBOL(call_usermodehelper_exec); | ||
618 | 610 | ||
619 | /* | 611 | /* |
620 | * call_usermodehelper_fns() will not run the caller-provided cleanup function | 612 | * call_usermodehelper_fns() will not run the caller-provided cleanup function |
@@ -630,13 +622,12 @@ int call_usermodehelper_fns( | |||
630 | struct subprocess_info *info; | 622 | struct subprocess_info *info; |
631 | gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; | 623 | gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; |
632 | 624 | ||
633 | info = call_usermodehelper_setup(path, argv, envp, gfp_mask); | 625 | info = call_usermodehelper_setup(path, argv, envp, gfp_mask, |
626 | init, cleanup, data); | ||
634 | 627 | ||
635 | if (info == NULL) | 628 | if (info == NULL) |
636 | return -ENOMEM; | 629 | return -ENOMEM; |
637 | 630 | ||
638 | call_usermodehelper_setfns(info, init, cleanup, data); | ||
639 | |||
640 | return call_usermodehelper_exec(info, wait); | 631 | return call_usermodehelper_exec(info, wait); |
641 | } | 632 | } |
642 | EXPORT_SYMBOL(call_usermodehelper_fns); | 633 | EXPORT_SYMBOL(call_usermodehelper_fns); |