Made nfs-root work with 2.1.78 !

DAVID BALAZIC (david.balazic@uni-mb.si)
Wed, 07 Jan 1998 11:16:13 +0100 (MET)


I succeded in making an nfs-root "diskless" linux system with kernel 2.1.78

The old setup I used was kernel 2.0.33 with nfs-root option
It was loaded with loadlin and the following command line options :
nfsroot=199.4.5.6:/root-fs/my-clients-root-fs
nfsaddrs=199.4.5.10:199.4.5.6:199.4.5.1:255.255.255.0:blondie::

199.4.5.6 - nfs-server IP
199.4.5.10 - client IP
199.4.5.1 - gateway IP
255.255.255.0 - netmask ( IPs are not my real IPs !! )

The mounted root-fs is minimal and the first commands in
/etc/rc.S ( fisrt script to execute ) are mounts
that mount /bin /usr /home .. also over nfs

This setup works OK

Let's look at 2.1.78 now :

I compiled the kernel with options :

IP autoconfig - YES
RARP - NO
BOOTP - NO

root-fs on NFS - YES

This wont work , because of two bugs in the kernel :

First :
IP auto config will fail ( write a message on boot :
"IP-Config: Auto-configuration of network failed."
and continue ),
because in file net/ipv4/ipconfig.c
function __initfunc(int ip_auto_config(void)) ( line 1016 )
statement
---
if (ic_myaddr == INADDR_NONE ||
#ifdef CONFIG_ROOT_NFS
root_server_addr == INADDR_NONE ||
#endif
(ic_first_dev && ic_first_dev->next)) {
#ifdef CONFIG_IP_PNP_DYNAMIC
if (ic_dynamic() < 0) {
printk(KERN_ERR "IP-Config: Auto-configuration of
network failed.\n");
ic_close_devs();
return -1;
}
---
will FAIL , because root_server_addr is always INADDR_NONE at this point.
It would be set in the function __initfunc(int ic_defaults(void))
( same file ), but it is called only after the prevoius if () , so
it is never reached. The solution is to move the lines :

if (ic_defaults() < 0)
return -1;

before the mentioned if(...) statement

Second :
After that the kernel will cause an oops , in file
fs/super.c function , line 1060 :
-----
if ((fs_type = get_fs_type("nfs"))) {
if ((vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/")))
{
/* wrong , mnt_sb is not set in add_vfsmnt() !! */
sb = vfsmnt->mnt_sb;
/* sb is NULL , so the following line cause a NULL dereference error ! */
sb->s_dev = get_unnamed_dev();
sb->s_flags = root_mountflags & ~MS_RDONLY;
if (nfs_root_mount(sb) >= 0) {
----

as a cure i copied the code from the 2.0.33 kernel , so we get :
--------
if ((fs_type = get_fs_type("nfs"))) {
if ((vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/")))
{
// DEL this line sb = vfsmnt->mnt_sb ;
add this line sb = &super_blocks[0];
add this line while (sb->s_dev) sb++;
add this line vfsmnt->mnt_sb = sb;
sb->s_dev = get_unnamed_dev();
sb->s_flags = root_mountflags & ~MS_RDONLY;
--------

This fixes the kernel problems , but I had to do some fixing in the startup
script too :

the new kernel requires rpc.portmap running , otherwise the
nfs mounts in the startup script wont succeed , so
I added the line /bootbin/rpc.portmap before the mount commands.

I also added "-o nolock" to the mounts to avoid further complications.

So , here are the kernel patches again :
( dont forget to comment out SMP=1 in the Makefile ! :)

diff -u -r linux/fs/super.c linux-2.1.78/fs/super.c
--- linux/fs/super.c Mon Dec 22 02:31:17 1997
+++ linux-2.1.78/fs/super.c Wed Jan 7 09:36:07 1998
@@ -1064,7 +1064,11 @@
ROOT_DEV = 0;
if ((fs_type = get_fs_type("nfs"))) {
if ((vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/"))) {
- sb = vfsmnt->mnt_sb;
+// sb = vfsmnt->mnt_sb ;
+ sb = &super_blocks[0];
+ while (sb->s_dev) sb++;
+
+ vfsmnt->mnt_sb = sb;
sb->s_dev = get_unnamed_dev();
sb->s_flags = root_mountflags & ~MS_RDONLY;
if (nfs_root_mount(sb) >= 0) {
diff -u -r linux/net/ipv4/ipconfig.c linux-2.1.78/net/ipv4/ipconfig.c
--- linux/net/ipv4/ipconfig.c Sun Nov 30 23:00:39 1997
+++ linux-2.1.78/net/ipv4/ipconfig.c Wed Jan 7 11:12:16 1998
@@ -1022,6 +1022,12 @@
return -1;

/*
+ * Use defaults whereever applicable.
+ */
+ if (ic_defaults() < 0)
+ return -1;
+
+ /*
* If the config information is insufficient (e.g., our IP address or
* IP address of the boot server is missing or we have multiple network
* interfaces and no default was set), use BOOTP or RARP to get the
@@ -1047,11 +1053,6 @@
ic_dev = ic_first_dev->dev; /* Device selected manually or only one device -> use it */
}

- /*
- * Use defaults whereever applicable.
- */
- if (ic_defaults() < 0)
- return -1;

/*
* Close all network devices except the device we've
-----cut-here-------------

Party on !

--
David Balazic , student
E-mail: David.Balazic@uni-mb.si       |             sLOVEnija
http://www.uni-mb.si/~uel003r2a
Computer: Amiga 1200 + Quantum LPS-340AT
--