Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | /*
kmod, the new module loader (replaces kerneld)
Kirk Petersen
*/
#define __KERNEL_SYSCALLS__
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/unistd.h>
/*
kmod_unload_delay and modprobe_path are set via /proc/sys.
*/
int kmod_unload_delay = 60;
char modprobe_path[256] = "/sbin/modprobe";
static char module_name[64] = "";
static char * argv[] = { modprobe_path, "-s", "-k", module_name, NULL };
static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL };
/*
kmod_queue synchronizes the kmod thread and the rest of the system
kmod_unload_timer is what we use to unload modules
after kmod_unload_delay seconds
*/
static struct wait_queue * kmod_queue = NULL;
static struct timer_list kmod_unload_timer;
/*
It is not easy to implement a full fork in kernel-space on some
systems (Alpha), and it is not necessary for us here. This is
a new thread that does the exec.
*/
static int kmod_exec_modprobe(void * data)
{
sigemptyset(¤t->blocked);
execve(modprobe_path, argv, envp);
printk(KERN_ERR "kmod: failed to load module %s\n", module_name);
return 0;
}
/*
kmod_thread is the thread that does most of the work. kmod_unload and
request_module tell it to wake up and do work.
*/
static int kmod_thread(void * data)
{
int pid;
/*
Initialize basic thread information
*/
current->session = 1;
current->pgrp = 1;
sprintf(current->comm, "kmod");
sigfillset(¤t->blocked);
/*
This is the main kmod_thread loop. It first sleeps, then
handles requests from request_module or kmod_unload.
*/
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)
*/
if (module_name[0] == '\0') {
delete_module(NULL);
} else {
pid = kernel_thread(kmod_exec_modprobe, NULL, SIGCHLD);
if (pid > 0) {
waitpid(pid, NULL, 0);
module_name[0] = '\0';
wake_up(&kmod_queue);
} else {
printk(KERN_ERR "kmod: fork failed, errno %d\n", -pid);
}
}
}
return 0; /* Never reached. */
}
/*
kmod_unload is the function that the kernel calls when
the kmod_unload_timer expires
*/
void kmod_unload(unsigned long x)
{
/*
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?))
once it is awake, reset the timer
*/
wake_up(&kmod_queue);
kmod_unload_timer.expires = jiffies + (kmod_unload_delay * HZ);
add_timer(&kmod_unload_timer);
}
int kmod_init(void)
{
printk("Starting kmod\n");
/*
* CLONE_FS means that our "cwd" will follow that of init.
* CLONE_FILES just saves some space (we don't need any
* new file descriptors). Ditto for CLONE_SIGHAND.
*/
kernel_thread(kmod_thread, NULL, CLONE_FILES | CLONE_FS | CLONE_SIGHAND);
kmod_unload_timer.next = NULL;
kmod_unload_timer.prev = NULL;
kmod_unload_timer.expires = jiffies + (5 * 60 * HZ);
kmod_unload_timer.data = 0L;
kmod_unload_timer.function = kmod_unload;
add_timer(&kmod_unload_timer);
return 0;
}
/*
request_module, the function that everyone calls when they need a
module to be loaded
*/
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) */
/*
kmod_thread is sleeping, so start by copying the name of
the module into module_name. Once that is done, wake up
kmod_thread.
*/
strncpy(module_name, name, sizeof(module_name));
module_name[sizeof(module_name)-1] = '\0';
wake_up(&kmod_queue);
/*
Now that we have told kmod_thread what to do, we want to
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);
return 0;
}
|