kerneld replacement

Kirk Petersen (kirk@eidolon.speakeasy.org)
Thu, 8 Jan 1998 23:46:47 -0800


Hi,
Here is an experimental patch of mine. It is the start of
a replacement for kerneld. Instead of communicating with a userland
daemon, it execve()s modprobe directly.
It is far from complete. I'm sure there are race conditions
or deadlocks somewhere in there :) I've only tested it on my system.
I'll release much cleaner patches in the future but I thought it would
be fun to see what everyone thinks.
As far as the other features of kerneld, I think they can all
be fixed with changes to modprobe. For example, persistent driver state
can be done by having modprobe save /proc/sys/driver_name to a file when
removing a module and the reverse when loading. Of course, any driver
that wants its state saved would have to export it to /proc/sys/*,
but that is generally a desirable thing :)
Any thoughts? Any reason to keep kerneld? Is it bad to execve()
modprobe from kernel land?

-- 
Bye,
Kirk Petersen
http://www.muppetlabs.com/~kirk/

--- cut here ---

diff -u --recursive --new-file linux-old/arch/i386/config.in linux/arch/i386/config.in --- linux-old/arch/i386/config.in Mon Jan 5 22:33:32 1998 +++ linux/arch/i386/config.in Thu Jan 8 18:57:02 1998 @@ -25,6 +25,7 @@ if [ "$CONFIG_MODULES" = "y" ]; then bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD + bool 'Kernel module loader (very experimental)' CONFIG_KMOD fi endmenu diff -u --recursive --new-file linux-old/include/linux/kerneld.h linux/include/linux/kerneld.h --- linux-old/include/linux/kerneld.h Mon Jan 5 22:29:44 1998 +++ linux/include/linux/kerneld.h Thu Jan 8 22:50:21 1998 @@ -56,12 +56,16 @@ * Wait for the exit status from insmod/modprobe. * If it fails, it fails... at least we tried... */ +#ifdef CONFIG_KMOD +extern request_module(const char * name); +#else static inline int request_module(const char *name) { return kerneld_send(KERNELD_REQUEST_MODULE, 0 | KERNELD_WAIT, strlen(name), name, NULL); } +#endif /* * Request the removal of a module, maybe don't wait for it. diff -u --recursive --new-file linux-old/init/main.c linux/init/main.c --- linux-old/init/main.c Mon Jan 5 22:33:50 1998 +++ linux/init/main.c Thu Jan 8 19:00:11 1998 @@ -1155,6 +1155,14 @@ } #endif +#ifdef CONFIG_KMOD + { + extern int kmod_init(void *); + kernel_thread(kmod_init, NULL, 0); + } +#endif + + setup(1); if (open("/dev/console", O_RDWR, 0) < 0) diff -u --recursive --new-file linux-old/kernel/Makefile linux/kernel/Makefile --- linux-old/kernel/Makefile Mon Jan 5 22:33:50 1998 +++ linux/kernel/Makefile Thu Jan 8 18:58:01 1998 @@ -17,6 +17,10 @@ OX_OBJS += signal.o +ifeq ($(CONFIG_KMOD),y) +O_OBJS += kmod.o +endif + ifeq ($(CONFIG_MODULES),y) OX_OBJS += ksyms.o endif diff -u --recursive --new-file linux-old/kernel/kmod.c linux/kernel/kmod.c --- linux-old/kernel/kmod.c Wed Dec 31 16:00:00 1969 +++ linux/kernel/kmod.c Thu Jan 8 22:53:35 1998 @@ -0,0 +1,99 @@ +/* + kmod loading (first cut) + kirk petersen + + there are undoubtedly race conditions and/or deadlocks in here +*/ + +#define __KERNEL_SYSCALLS__ + +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/unistd.h> + +char modprobe_path[64] = "/sbin/modprobe"; +char module_name[64] = ""; +char * argv[] = { "modprobe", "-k", NULL, NULL, }; +char * envp[] = { "HOME=/", "TERM=linux", NULL, }; + +struct wait_queue * kmod_queue = NULL; + +int kmod_init(void * data) +{ + int x; + + /* + Initialize basic thread information + (i'm not sure what this does, entirely) + */ + current->session = 1; + current->pgrp = 1; + sprintf(current->comm, "kmod"); + sigfillset(&current->blocked); + + /* + For now, this thread waits until someone calls + request_module. Then it executes modprobe with the + arguments request_module was given. + */ + + printk ("Starting kmod (kerneld replacement)\n"); + + (void)open("/dev/console", O_RDWR, 0); + (void)dup(0); + (void)dup(0); + + while (1) { + /* wait to be signaled by a call to request_module */ + printk("kmod: sleeping\n"); + interruptible_sleep_on(&kmod_queue); + + x = fork(); + if (x) { + /* wait for the child to load the module */ + waitpid(x, NULL, 0); + + /* reset name and wake up the requesting task */ + module_name[0] = '\0'; + wake_up(&kmod_queue); + } else { + + /* if no module_name, return an error */ + if (module_name[0] == '\0') { + printk("kmod: no module_name given\n"); + return -1; + } + + /* the child execve()s modprobe */ + argv[2] = module_name; + execve(modprobe_path, argv, envp); + + /* only executed if execve() fails */ + printk("kmod: failed to load module %s\n", module_name); + _exit(0); + } + } + + return 0; /* Never reached. */ +} + +int request_module(const char * name) +{ + /* + first, copy the name of the module into module_name + */ + printk("requesting module: %s\n", name); + strcpy(module_name, name); + + /* + then wake_up() the kmod daemon + */ + wake_up(&kmod_queue); + + /* + wait for the kmod daemon to finish (it will wake us up) + */ + interruptible_sleep_on(&kmod_queue); + + return 0; +} diff -u --recursive --new-file linux-old/kernel/ksyms.c linux/kernel/ksyms.c --- linux-old/kernel/ksyms.c Mon Jan 5 22:33:07 1998 +++ linux/kernel/ksyms.c Thu Jan 8 22:52:10 1998 @@ -90,6 +90,10 @@ #endif +#ifdef CONFIG_KMOD +EXPORT_SYMBOL(request_module); +#endif + #ifdef CONFIG_MODULES EXPORT_SYMBOL(get_module_symbol); #endif