]> git.hungrycats.org Git - linux/commitdiff
[PATCH] call_usermodehelper retval fix
authorAndrew Morton <akpm@osdl.org>
Tue, 30 Dec 2003 09:00:38 +0000 (01:00 -0800)
committerLinus Torvalds <torvalds@home.osdl.org>
Tue, 30 Dec 2003 09:00:38 +0000 (01:00 -0800)
The reworked firmware loader in the DVB patches needs the fix to the
call_usermodehelper() return value.

From: Rusty Russell <rusty@rustcorp.com.au>

MODULE_ALIAS_BLOCK() and MODULE_ALIAS_CHAR() define aliases of form
"XXX-<major>-<minor>", so we should probe for modules using this form.
Unfortunately in 2.4, block aliases were "XXX-<major>" and char aliases
were of both forms.

Ideally, all modules would now be using MODULE_ALIAS() macros to define
their aliases, and the old configuration files wouldn't matter as much.
Unfortunately, this hasn't happened, so we make request_module() return the
exit status of modprobe, and then do fallback when probing for char and
block devices.

(Kudos to Chris Wright, I stole his kernel_thread flags).

drivers/block/genhd.c
fs/char_dev.c
include/linux/kmod.h
kernel/kmod.c

index d50419e1e7d1b624f44c833bf45d692eb2f15f1b..06a7d4ea0d1bd1e20e479a8aa81048766bbe9127 100644 (file)
@@ -296,7 +296,9 @@ extern int blk_dev_init(void);
 
 static struct kobject *base_probe(dev_t dev, int *part, void *data)
 {
-       request_module("block-major-%d", MAJOR(dev));
+       if (request_module("block-major-%d-%d", MAJOR(dev), MINOR(dev)) > 0)
+               /* Make old-style 2.4 aliases work */
+               request_module("block-major-%d", MAJOR(dev));
        return NULL;
 }
 
index 5f4ab3ac1296478af824be83b6cf9d67188ae575..50ab4cf8e8e162c543d465d8eabcab29c33e7072 100644 (file)
@@ -434,7 +434,9 @@ void cdev_init(struct cdev *cdev, struct file_operations *fops)
 
 static struct kobject *base_probe(dev_t dev, int *part, void *data)
 {
-       request_module("char-major-%d-%d", MAJOR(dev), MINOR(dev));
+       if (request_module("char-major-%d-%d", MAJOR(dev), MINOR(dev)) > 0)
+               /* Make old-style 2.4 aliases work */
+               request_module("char-major-%d", MAJOR(dev));
        return NULL;
 }
 
index 8412faeea0f7e2730ed75e269fa44481d38a2e7d..7c5af18df9d11b504472382b902beb07026f639e 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/compiler.h>
 
 #ifdef CONFIG_KMOD
+/* modprobe exit status on success, -ve on error.  Return value
+ * usually useless though. */
 extern int request_module(const char * name, ...) __attribute__ ((format (printf, 1, 2)));
 #else
 static inline int request_module(const char * name, ...) { return -ENOSYS; }
index 2c74533c0b963c563230b4e92522f1a8999dbda0..ed2c9a76f66b69f042c37398d9024faad7c89a9b 100644 (file)
@@ -182,16 +182,21 @@ static int wait_for_helper(void *data)
 {
        struct subprocess_info *sub_info = data;
        pid_t pid;
+       struct k_sigaction sa;
+
+       /* Install a handler: if SIGCLD isn't handled sys_wait4 won't
+        * populate the status, but will return -ECHILD. */
+       sa.sa.sa_handler = SIG_IGN;
+       sa.sa.sa_flags = 0;
+       siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
+       do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
+       allow_signal(SIGCHLD);
 
-       sub_info->retval = 0;
        pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD);
        if (pid < 0)
                sub_info->retval = pid;
        else
-               /* We don't have a SIGCHLD signal handler, so this
-                * always returns -ECHILD, but the important thing is
-                * that it blocks. */
-               sys_wait4(pid, NULL, 0, NULL);
+               sys_wait4(pid, &sub_info->retval, 0, NULL);
 
        complete(sub_info->complete);
        return 0;
@@ -210,7 +215,7 @@ static void __call_usermodehelper(void *data)
         * until that is done.  */
        if (sub_info->wait)
                pid = kernel_thread(wait_for_helper, sub_info,
-                                   CLONE_KERNEL | SIGCHLD);
+                                   CLONE_FS | CLONE_FILES | SIGCHLD);
        else
                pid = kernel_thread(____call_usermodehelper, sub_info,
                                    CLONE_VFORK | SIGCHLD);