lkml.org 
[lkml]   [1998]   [Mar]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: kmod fix
Well, the code is _much_ bigger than the original kmod, but I've modified
kmod to allow multiple requests. It splits up the signalling into the
original kmod_queue and an array of module slots. Each of these slots
contains the wait queue for waking up request_module, the name of the
module, and a information byte telling the status of the module. This
allows the lp module to load properly again. Although it's somewhat
bloated, I think it bypasses the races in the current kmod code.

In addition, I've added a switch that shuts kmod off by default. It is
activated by putting a non-null string in systcl kernel/modprobe_path.
This is necessary because kmod starts after initrd is run. Inserting
modules that run request_module will cause a freeze (scsi fits into that
category - a la Redhat installs). So the rc scripts must put a modprobe
path into kernel/modprobe_path (this could be easily changed)

Another thing is that request_module will now return -1 if a module load
failed - I couldn't find the proper return code, but I think the return
code should change if a failure occurs.

Patch is against 2.1.90pre2 but should work against 2.1.90pre3 and 1, (I'm
compiling pre3 now)
Anyway, what do you think? Is the extra code worth it?

Greg Zornetzer - gaz+@andrew.cmu.edu
"Light shines brightest in the darkest night"
http://www.contrib.andrew.cmu.edu/~gaz

--- linux/kernel/kmod.c.old Thu Mar 12 23:18:22 1998
+++ linux/kernel/kmod.c Sun Mar 15 00:20:38 1998
@@ -1,6 +1,9 @@
/*
kmod, the new module loader (replaces kerneld)
Kirk Petersen
+ Modifications to support multiple modules loading
+ by Greg Zornetzer (gaz@andrew.cmu.edu)
+
*/

#define __KERNEL_SYSCALLS__
@@ -9,17 +12,51 @@
#include <linux/types.h>
#include <linux/unistd.h>

+
+/*
+ Define the number of modules that we can concurrently load.
+ It's easier to statically define this amount than to make
+ it scale dynamically
+*/
+
+#define NUMMODS 10
+
+/*
+ A module slot can be in several states - unused, or in various
+ states of processing
+*/
+#define MODRQ_NONE 0
+#define MODRQ_REQUESTED 1
+#define MODRQ_SERVICING 2
+#define MODRQ_REMOVE 4
+#define MODRQ_FAILURE 8
+
static inline _syscall1(int,delete_module,const char *,name_user)

/*
kmod_unload_delay and modprobe_path are set via /proc/sys.
+ Make modprobe path null by default - this signals that
+ request_module (and therefore kmod) will be unable to service
+ requests until explicitly activated using sysctl
*/
int kmod_unload_delay = 60;
-char modprobe_path[256] = "/sbin/modprobe";
-char module_name[64] = "";
+char modprobe_path[256] = "";
char * argv[] = { "modprobe", "-k", NULL, NULL, };
char * envp[] = { "HOME=/", "TERM=linux", NULL, };

+
+/*
+ A modslot defines the state of a module being loaded and holds the
+ wait_queue to reactivate request_module
+*/
+typedef struct {
+ struct wait_queue *mreq_queue;
+ unsigned char info;
+ char module_name[64];
+} modslot;
+
+modslot modlist[NUMMODS];
+
/*
kmod_queue synchronizes the kmod thread and the rest of the system
kmod_unload_timer is what we use to unload modules
@@ -28,6 +65,33 @@
struct wait_queue * kmod_queue = NULL;
struct timer_list kmod_unload_timer;

+void install_module(int listnum) {
+
+ int pid;
+ pid = fork();
+
+ if (pid > 0) {
+ waitpid(pid, NULL, 0);
+ wake_up(&(modlist[listnum].mreq_queue));
+
+ } else if (pid == 0) {
+ /*
+ Call modprobe with module_name. If execve returns,
+ print out an error.
+ */
+ argv[2] = modlist[listnum].module_name;
+ execve(modprobe_path, argv, envp);
+
+ printk("kmod: failed to load module %s\n", modlist[listnum].module_name);
+ modlist[listnum].info = MODRQ_FAILURE;
+ _exit(0);
+ } else {
+ printk("error, fork failed in kmod - couldn't load %s\n",modlist[listnum].module_name);
+ modlist[listnum].info = MODRQ_FAILURE;
+ wake_up(&(modlist[listnum].mreq_queue));
+ }
+}
+
/*
kmod_thread is the thread that does most of the work. kmod_unload and
request_module tell it to wake up and do work.
@@ -35,6 +99,7 @@
int kmod_thread(void * data)
{
int pid;
+ int i;

/*
Initialize basic thread information
@@ -45,6 +110,13 @@
sigfillset(&current->blocked);

/*
+ Initialize the modlist array
+ */
+ for(i = 0; i < NUMMODS; i++) {
+ modlist[i].info = MODRQ_NONE;
+ modlist[i].mreq_queue = NULL;
+ }
+ /*
This is the main kmod_thread loop. It first sleeps, then
handles requests from request_module or kmod_unload.
*/
@@ -52,37 +124,38 @@
while (1) {
interruptible_sleep_on(&kmod_queue);

- /*
- If request_module woke us up, we should try to
- load module_name. If not, kmod_unload woke us up,
- do call delete_module.
- (if somehow both want us to do something, ignore the
- delete_module request)
+ /*
+ We've been awakened - check all of the module
+ slots for new requests
*/
- if (module_name[0] == '\0') {
- delete_module(NULL);
- } else {
- pid = fork();
- if (pid > 0) {
- waitpid(pid, NULL, 0);
- module_name[0] = '\0';
- wake_up(&kmod_queue);
- } else
- if (pid == 0) {
-
- /*
- Call modprobe with module_name. If execve returns,
- print out an error.
- */
- argv[2] = module_name;
- execve(modprobe_path, argv, envp);

- printk("kmod: failed to load module %s\n", module_name);
- _exit(0);
- } else {
- printk("error, fork failed in kmod\n");
+ for(i = 0; i < NUMMODS; i++) {
+ switch (modlist[i].info) {
+ case MODRQ_REQUESTED :
+ modlist[i].info = MODRQ_SERVICING;
+ /*
+ Gotta fork off a new process to make
+ sure that kmod can handle
+ subsequent requests
+ */
+ pid = fork();
+ if (pid == 0) {
+ install_module(i);
+ _exit(0);
+ }
+ else if (pid < 0) {
+ printk("KMod: Couldn't fork - Cannot load %s\n",modlist[i].module_name);
+ modlist[i].info = MODRQ_FAILURE;
+ wake_up(&(modlist[i].mreq_queue));
+ }
+ break;
+ case MODRQ_REMOVE :
+ modlist[i].info = MODRQ_NONE;
+ delete_module(NULL);
+ break;
}
}
+
}

return 0; /* Never reached. */
@@ -94,13 +167,23 @@
*/
void kmod_unload(unsigned long x)
{
+ int i=0;
/*
+ Find a free slot, and set it to the remove status
+ KMod will pick this up and call delete_module
wake up the kmod thread, which does the work
(we can't call delete_module, as it locks the kernel and
- we are in the bottom half of the kernel (right?))
+ we are in the bottom half of the kernel (right?))
once it is awake, reset the timer
*/
- wake_up(&kmod_queue);
+ while((i < NUMMODS) && (modlist[i].info != MODRQ_NONE))
+ i++;
+ if(i != NUMMODS) {
+ modlist[i].info = MODRQ_REMOVE;
+ wake_up(&kmod_queue);
+ }
+ else
+ printk("Couldn't get slot for module cleanup\n");
kmod_unload_timer.expires = jiffies + (kmod_unload_delay * HZ);
add_timer(&kmod_unload_timer);
}
@@ -127,16 +210,30 @@
*/
int request_module(const char * name)
{
- /* first, copy the name of the module into module_name */
- /* then wake_up() the kmod daemon */
- /* wait for the kmod daemon to finish (it will wake us up) */
+/*
+ request_module will (if kmod is running) get free modslot
+ and wake up kmod.
+*/

- /*
- kmod_thread is sleeping, so start by copying the name of
- the module into module_name. Once that is done, wake up
- kmod_thread.
- */
- strcpy(module_name, name);
+ int i = 0;
+
+
+/*
+ modprobe_path hasn't been initialized, the kmod is inactive.
+ So we fail
+*/
+ if (modprobe_path[0]=='\0')
+ return(-1);
+
+ while((i < NUMMODS) && (modlist[i].info != MODRQ_NONE))
+ i++;
+ if(i == NUMMODS) {
+ printk("KMod - module load failure - no free mod slots\n");
+ return(-1);
+ }
+
+ modlist[i].info = MODRQ_REQUESTED;
+ strcpy(modlist[i].module_name, name);
wake_up(&kmod_queue);

/*
@@ -144,6 +241,22 @@
go to sleep and let it do its work. It will wake us up,
at which point we will be done (the module will be loaded).
*/
- interruptible_sleep_on(&kmod_queue);
+
+ interruptible_sleep_on(&(modlist[i].mreq_queue));
+
+ /*
+ If the module load returns a failure for any reason,
+ we should fail also
+ */
+ if(modlist[i].info == MODRQ_FAILURE) {
+ modlist[i].info = MODRQ_NONE;
+ return(-1);
+ }
+ modlist[i].info = MODRQ_NONE;
return 0;
}
+
+
+
+
+
\
 
 \ /
  Last update: 2005-03-22 13:41    [W:2.082 / U:0.012 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site