WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [patch 03/44] usermodehelper: split setup from execution

To: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [patch 03/44] usermodehelper: split setup from execution
From: Jeremy Fitzhardinge <jeremy@xxxxxxxxxxxxx>
Date: Mon, 16 Jul 2007 16:15:39 -0700
Cc: Randy Dunlap <randy.dunlap@xxxxxxxxxx>, Jeremy Fitzhardinge <jeremy@xxxxxxxx>, Xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxx>, Bj?rn Steinbrink <B.Steinbrink@xxxxxx>, Rusty Russell <rusty@xxxxxxxxxxxxxxx>, Andi Kleen <ak@xxxxxxx>, lkml <linux-kernel@xxxxxxxxxxxxxxx>, David Howells <dhowells@xxxxxxxxxx>, Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
Delivery-date: Mon, 16 Jul 2007 16:54:29 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <20070716231536.937393000@xxxxxxxxxxxxx>>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: quilt/0.46-1
Rather than having hundreds of variations of call_usermodehelper for
various pieces of usermode state which could be set up, split the
info allocation and initialization from the actual process execution.

This means the general pattern becomes:
 info = call_usermodehelper_setup(path, argv, envp); /* basic state */
 call_usermodehelper_<SET EXTRA STATE>(info, stuff...); /* extra state */
 call_usermodehelper_exec(info, wait);  /* run process and free info */

This patch introduces wrappers for all the existing calling styles for
call_usermodehelper_*, but folds their implementations into one.

Signed-off-by: Jeremy Fitzhardinge <jeremy@xxxxxxxxxxxxx>
Cc: Andi Kleen <ak@xxxxxxx>
Cc: Rusty Russell <rusty@xxxxxxxxxxxxxxx>
Cc: David Howells <dhowells@xxxxxxxxxx>
Cc: Bj?rn Steinbrink <B.Steinbrink@xxxxxx>
Cc: Randy Dunlap <randy.dunlap@xxxxxxxxxx>

---
 include/linux/kmod.h |   44 +++++++++-
 kernel/kmod.c        |  207 ++++++++++++++++++++++++++++++++++----------------
 2 files changed, 184 insertions(+), 67 deletions(-)

===================================================================
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -36,13 +36,51 @@ static inline int request_module(const c
 #define try_then_request_module(x, mod...) ((x) ?: (request_module(mod), (x)))
 
 struct key;
-extern int call_usermodehelper_keys(char *path, char *argv[], char *envp[],
-                                   struct key *session_keyring, int wait);
+struct file;
+struct subprocess_info;
+
+/* Allocate a subprocess_info structure */
+struct subprocess_info *call_usermodehelper_setup(char *path,
+                                                 char **argv, char **envp);
+
+/* Set various pieces of state into the subprocess_info structure */
+void call_usermodehelper_setkeys(struct subprocess_info *info,
+                                struct key *session_keyring);
+int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
+                                 struct file **filp);
+void call_usermodehelper_setcleanup(struct subprocess_info *info,
+                                   void (*cleanup)(char **argv, char **envp));
+
+/* Actually execute the sub-process */
+int call_usermodehelper_exec(struct subprocess_info *info, int wait);
+
+/* Free the subprocess_info. This is only needed if you're not going
+   to call call_usermodehelper_exec */
+void call_usermodehelper_freeinfo(struct subprocess_info *info);
 
 static inline int
 call_usermodehelper(char *path, char **argv, char **envp, int wait)
 {
-       return call_usermodehelper_keys(path, argv, envp, NULL, wait);
+       struct subprocess_info *info;
+
+       info = call_usermodehelper_setup(path, argv, envp);
+       if (info == NULL)
+               return -ENOMEM;
+       return call_usermodehelper_exec(info, wait);
+}
+
+static inline int
+call_usermodehelper_keys(char *path, char **argv, char **envp,
+                        struct key *session_keyring, int wait)
+{
+       struct subprocess_info *info;
+
+       info = call_usermodehelper_setup(path, argv, envp);
+       if (info == NULL)
+               return -ENOMEM;
+
+       call_usermodehelper_setkeys(info, session_keyring);
+       return call_usermodehelper_exec(info, wait);
 }
 
 extern void usermodehelper_init(void);
===================================================================
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -123,6 +123,7 @@ struct subprocess_info {
        int wait;
        int retval;
        struct file *stdin;
+       void (*cleanup)(char **argv, char **envp);
 };
 
 /*
@@ -176,6 +177,14 @@ static int ____call_usermodehelper(void 
        do_exit(0);
 }
 
+void call_usermodehelper_freeinfo(struct subprocess_info *info)
+{
+       if (info->cleanup)
+               (*info->cleanup)(info->argv, info->envp);
+       kfree(info);
+}
+EXPORT_SYMBOL(call_usermodehelper_freeinfo);
+
 /* Keventd can't block, but this (a child) can. */
 static int wait_for_helper(void *data)
 {
@@ -218,7 +227,7 @@ static int wait_for_helper(void *data)
        }
 
        if (sub_info->wait < 0)
-               kfree(sub_info);
+               call_usermodehelper_freeinfo(sub_info);
        else
                complete(sub_info->complete);
        return 0;
@@ -253,11 +262,94 @@ static void __call_usermodehelper(struct
 }
 
 /**
- * call_usermodehelper_keys - start a usermode application
- * @path: pathname for the application
- * @argv: null-terminated argument list
- * @envp: null-terminated environment list
- * @session_keyring: session keyring for process (NULL for an empty keyring)
+ * call_usermodehelper_setup - prepare to call a usermode helper
+ * @path - path to usermode executable
+ * @argv - arg vector for process
+ * @envp - environment for process
+ *
+ * Returns either NULL on allocation failure, or a subprocess_info
+ * structure.  This should be passed to call_usermodehelper_exec to
+ * exec the process and free the structure.
+ */
+struct subprocess_info *call_usermodehelper_setup(char *path,
+                                                 char **argv, char **envp)
+{
+       struct subprocess_info *sub_info;
+       sub_info = kzalloc(sizeof(struct subprocess_info),  GFP_ATOMIC);
+       if (!sub_info)
+               goto out;
+
+       INIT_WORK(&sub_info->work, __call_usermodehelper);
+       sub_info->path = path;
+       sub_info->argv = argv;
+       sub_info->envp = envp;
+
+  out:
+       return sub_info;
+}
+EXPORT_SYMBOL(call_usermodehelper_setup);
+
+/**
+ * call_usermodehelper_setkeys - set the session keys for usermode helper
+ * @info: a subprocess_info returned by call_usermodehelper_setup
+ * @session_keyring: the session keyring for the process
+ */
+void call_usermodehelper_setkeys(struct subprocess_info *info,
+                                struct key *session_keyring)
+{
+       info->ring = session_keyring;
+}
+EXPORT_SYMBOL(call_usermodehelper_setkeys);
+
+/**
+ * call_usermodehelper_setcleanup - set a cleanup function
+ * @info: a subprocess_info returned by call_usermodehelper_setup
+ * @cleanup: a cleanup function
+ *
+ * The cleanup function is just befor ethe subprocess_info is about to
+ * be freed.  This can be used for freeing the argv and envp.  The
+ * Function must be runnable in either a process context or the
+ * context in which call_usermodehelper_exec is called.
+ */
+void call_usermodehelper_setcleanup(struct subprocess_info *info,
+                                   void (*cleanup)(char **argv, char **envp))
+{
+       info->cleanup = cleanup;
+}
+EXPORT_SYMBOL(call_usermodehelper_setcleanup);
+
+/**
+ * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin
+ * @sub_info: a subprocess_info returned by call_usermodehelper_setup
+ * @filp: set to the write-end of a pipe
+ *
+ * This constructs a pipe, and sets the read end to be the stdin of the
+ * subprocess, and returns the write-end in *@filp.
+ */
+int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
+                                 struct file **filp)
+{
+       struct file *f;
+
+       f = create_write_pipe();
+       if (IS_ERR(f))
+               return PTR_ERR(f);
+       *filp = f;
+
+       f = create_read_pipe(f);
+       if (IS_ERR(f)) {
+               free_write_pipe(*filp);
+               return PTR_ERR(f);
+       }
+       sub_info->stdin = f;
+
+       return 0;
+}
+EXPORT_SYMBOL(call_usermodehelper_stdinpipe);
+
+/**
+ * call_usermodehelper_exec - start a usermode application
+ * @sub_info: information about the subprocessa
  * @wait: wait for the application to finish and return status.
  *        when -1 don't wait at all, but you get no useful error back when
  *        the program couldn't be exec'ed. This makes it safe to call
@@ -266,33 +358,24 @@ static void __call_usermodehelper(struct
  * 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 a negative error code
- * if program was not execed successfully, or 0.
- */
-int call_usermodehelper_keys(char *path, char **argv, char **envp,
-                            struct key *session_keyring, int wait)
+ */
+int call_usermodehelper_exec(struct subprocess_info *sub_info,
+                            int wait)
 {
        DECLARE_COMPLETION_ONSTACK(done);
-       struct subprocess_info *sub_info;
        int retval;
 
-       if (!khelper_wq)
-               return -EBUSY;
-
-       if (path[0] == '\0')
-               return 0;
-
-       sub_info = kzalloc(sizeof(struct subprocess_info),  GFP_ATOMIC);
-       if (!sub_info)
-               return -ENOMEM;
-
-       INIT_WORK(&sub_info->work, __call_usermodehelper);
+       if (sub_info->path[0] == '\0') {
+               retval = 0;
+               goto out;
+       }
+
+       if (!khelper_wq) {
+               retval = -EBUSY;
+               goto out;
+       }
+
        sub_info->complete = &done;
-       sub_info->path = path;
-       sub_info->argv = argv;
-       sub_info->envp = envp;
-       sub_info->ring = session_keyring;
        sub_info->wait = wait;
 
        queue_work(khelper_wq, &sub_info->work);
@@ -300,47 +383,43 @@ int call_usermodehelper_keys(char *path,
                return 0;
        wait_for_completion(&done);
        retval = sub_info->retval;
-       kfree(sub_info);
+
+  out:
+       call_usermodehelper_freeinfo(sub_info);
        return retval;
 }
-EXPORT_SYMBOL(call_usermodehelper_keys);
-
+EXPORT_SYMBOL(call_usermodehelper_exec);
+
+/**
+ * call_usermodehelper_pipe - call a usermode helper process with a pipe stdin
+ * @path: path to usermode executable
+ * @argv: arg vector for process
+ * @envp: environment for process
+ * @filp: set to the write-end of a pipe
+ *
+ * This is a simple wrapper which executes a usermode-helper function
+ * with a pipe as stdin.  It is implemented entirely in terms of
+ * lower-level call_usermodehelper_* functions.
+ */
 int call_usermodehelper_pipe(char *path, char **argv, char **envp,
                             struct file **filp)
 {
-       DECLARE_COMPLETION(done);
-       struct subprocess_info sub_info = {
-               .work           = __WORK_INITIALIZER(sub_info.work,
-                                                    __call_usermodehelper),
-               .complete       = &done,
-               .path           = path,
-               .argv           = argv,
-               .envp           = envp,
-               .retval         = 0,
-       };
-       struct file *f;
-
-       if (!khelper_wq)
-               return -EBUSY;
-
-       if (path[0] == '\0')
-               return 0;
-
-       f = create_write_pipe();
-       if (IS_ERR(f))
-               return PTR_ERR(f);
-       *filp = f;
-
-       f = create_read_pipe(f);
-       if (IS_ERR(f)) {
-               free_write_pipe(*filp);
-               return PTR_ERR(f);
-       }
-       sub_info.stdin = f;
-
-       queue_work(khelper_wq, &sub_info.work);
-       wait_for_completion(&done);
-       return sub_info.retval;
+       struct subprocess_info *sub_info;
+       int ret;
+
+       sub_info = call_usermodehelper_setup(path, argv, envp);
+       if (sub_info == NULL)
+               return -ENOMEM;
+
+       ret = call_usermodehelper_stdinpipe(sub_info, filp);
+       if (ret < 0)
+               goto out;
+
+       return call_usermodehelper_exec(sub_info, 1);
+
+  out:
+       call_usermodehelper_freeinfo(sub_info);
+       return ret;
 }
 EXPORT_SYMBOL(call_usermodehelper_pipe);
 

-- 


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel