2.1.95 freezes were my fault; kmod patch

Adam J. Richter (adam@yggdrasil.com)
Sat, 11 Apr 1998 13:20:15 -0700


I must apologize now because the 2.1.95 freezes that I had
reported earlier were my fault. It appears that I in one of the last
few kernel versions, kmod_init() was moved up in init/main.c in an
effort to allow kmod to run on the initial ramdisk, just as I had
done. I had somehow goofed in integrating this changes and ended up
with two calls to kmod_init() in init/main.c. Removing my extra call
seems to have solved all of the problems, and I am now happily running
my original configuration, complete with kmod.

Now, let me offer some restitution for the time that I have
taken in the way of a kernel patch. Under 2.1.95, kmod + initial
ramdisk does not quite work properly. kmod's root directory never
changes to the real root directory after the initial ramdisk exits or
chroots. As a result, the space used by the initial ramdisk is never
released, and demand loading of modules will only work if modprobe and
the modules to be loaded happen to have been on the initial ramdisk.
The initial ramdisk need not use any demand loading of modules for
this problem to occur. It just has to be enabled. So, it is possible
that other people are unknowingly experiencing this problem, since the
symptoms are fairly subtle (demand loads of modules fail silently, as if
the modules did not exist).

I have attached a patch below that causes kmod to chroot to
whereever the initial ramdisk chroot or to the new root directory if
it exits. I have been using this since at least 2.1.91, and it works
quite well for me (at least after I deleted my duplicate call to
kmod_init!).

By the way, it is important to allow the initial ramdisk to
switch to the new root by doing "exec chroot /mnt /sbin/init" rather
than exiting to enable initial ramdisks that can select from more than
one possibility for finding the actual root partition (e.g., bringing
up a screen that says "boot from CDROM or boot from network?").
Please do not remove that functionality.

Anyhow, I hope you'll integrate this fix into the main kernel
distribution.

Adam J. Richter __ ______________ 4880 Stevens Creek Blvd, Suite 205
adam@yggdrasil.com \ / San Jose, California 95129-1034
+1 408 261-6630 | g g d r a s i l United States of America
fax +1 408 261-6631 "Free Software For The Rest Of Us."
-------------------------------CUT HERE-----------------------------------
--- /tmp/linux-2.1.95/init/main.c Wed Apr 8 18:10:01 1998
+++ linux/init/main.c Sat Apr 11 12:49:48 1998
@@ -306,6 +306,11 @@

int rows, cols;

+#ifdef CONFIG_BLK_DEV_INITRD
+pid_t initrd_pid;
+#endif
+
+
#ifdef CONFIG_BLK_DEV_RAM
extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
@@ -1189,17 +1194,24 @@
if (mount_initrd && ROOT_DEV != real_root_dev
&& MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) {
int error;
- int i, pid;
+ int i;

- pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
- if (pid>0)
- while (pid != wait(&i));
+ initrd_pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
+ if (initrd_pid>0)
+ while (initrd_pid != wait(&i));
+ initrd_pid = -1;
if (MAJOR(real_root_dev) != RAMDISK_MAJOR
|| MINOR(real_root_dev) != 0) {
error = change_root(real_root_dev,"/initrd");
if (error)
printk(KERN_ERR "Change root to /initrd: "
"error %d\n",error);
+#ifdef CONFIG_KMOD
+ {
+ extern int kmod_chroot(void);
+ kmod_chroot();
+ }
+#endif
}
}
#endif
--- /tmp/linux-2.1.95/fs/open.c Tue Mar 10 13:28:05 1998
+++ linux/fs/open.c Sat Apr 11 11:30:11 1998
@@ -20,6 +20,7 @@
#include <linux/file.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/config.h>

#include <asm/uaccess.h>
#include <asm/bitops.h>
@@ -423,6 +424,16 @@
dput_and_out:
dput(dentry);
out:
+#if defined(CONFIG_KMOD) && defined(CONFIG_INITRD)
+ {
+ extern pid_t initrd_pid;
+
+ if (current->pid == initrd_pid) {
+ extern void kmod_chroot();
+ kmod_chroot();
+ }
+ }
+#endif /* CONFIG_KMOD && CONFIG_INITRD */
unlock_kernel();
return error;
}
--- /tmp/linux-2.1.95/kernel/kmod.c Tue Apr 7 08:05:05 1998
+++ linux/kernel/kmod.c Sat Apr 11 11:30:46 1998
@@ -26,7 +26,7 @@
static struct wait_queue * kmod_queue = NULL;
static struct timer_list kmod_unload_timer;

-/*
+/* Chroot to the same root directory as the specified process. This is
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.
@@ -40,6 +40,31 @@
}

/*
+ used so that when the ramdisk finishes*/
+
+static int kmod_root_changed = 0;
+const pid_t pid_to_follow = 1; /* the init process */
+
+static void
+follow_root(void) {
+ struct task_struct *task;
+
+ read_lock(&tasklist_lock);
+ task = find_task_by_pid(pid_to_follow);
+
+ if (current->fs->root != task->fs->root) {
+ struct dentry *old_root = current->fs->root;
+ struct dentry *old_pwd = current->fs->root;
+
+ current->fs->root = dget(task->fs->root);
+ current->fs->pwd = dget(task->fs->root);
+ dput(old_root);
+ dput(old_pwd);
+ }
+ read_unlock(&tasklist_lock);
+}
+
+/*
kmod_thread is the thread that does most of the work. kmod_unload and
request_module tell it to wake up and do work.
*/
@@ -62,7 +87,11 @@

while (1) {
interruptible_sleep_on(&kmod_queue);
-
+ if (kmod_root_changed) {
+ follow_root();
+ kmod_root_changed = 0;
+ wake_up(&kmod_queue);
+ }
/*
If request_module woke us up, we should try to
load module_name. If not, kmod_unload woke us up,
@@ -146,4 +175,11 @@
*/
interruptible_sleep_on(&kmod_queue);
return 0;
+}
+
+void
+kmod_chroot (void) {
+ kmod_root_changed = 1;
+ wake_up(&kmod_queue);
+ interruptible_sleep_on(&kmod_queue);
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu