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 /kernel | |
| 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>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/kmod.c | 57 |
1 files changed, 24 insertions, 33 deletions
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); |
