[RFC PATCH 8/9] nfsroot: move to netroot framework

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Parse and convert commandline options in the cmdline hook, and
fill in the missing pieces in the netroot hook. This also allows
root=dhcp to work as expected.

Signed-off-by: David Dillow <dave@xxxxxxxxxxxxxx>
---
 modules.d/95nfs/60-nfsroot.rules |    1 -
 modules.d/95nfs/install          |   10 +---
 modules.d/95nfs/nfs-netroot.sh   |   52 +++++++++++++++++++
 modules.d/95nfs/nfsroot          |  105 +++++++++++--------------------------
 modules.d/95nfs/parse-nfsroot.sh |   48 +++++++++++++++++
 modules.d/99base/dracut-lib      |   16 ++++++
 6 files changed, 149 insertions(+), 83 deletions(-)
 delete mode 100644 modules.d/95nfs/60-nfsroot.rules
 create mode 100755 modules.d/95nfs/nfs-netroot.sh
 create mode 100755 modules.d/95nfs/parse-nfsroot.sh

diff --git a/modules.d/95nfs/60-nfsroot.rules b/modules.d/95nfs/60-nfsroot.rules
deleted file mode 100644
index 99a2acf..0000000
--- a/modules.d/95nfs/60-nfsroot.rules
+++ /dev/null
@@ -1 +0,0 @@
-ACTION=="online", SUBSYSTEM=="net", RUN+="/sbin/nfsroot $env{INTERFACE}"
diff --git a/modules.d/95nfs/install b/modules.d/95nfs/install
index 80b59a1..8d7366f 100755
--- a/modules.d/95nfs/install
+++ b/modules.d/95nfs/install
@@ -1,23 +1,17 @@
 #!/bin/sh
 dracut_install rpcbind rpc.statd mount.nfs mount.nfs4 umount 
 dracut_install /etc/netconfig /etc/passwd /etc/services
-
-# XXX debug stuff
-dracut_install rpcinfo ping strace dmesg nc free df
-
 dracut_install rpc.idmapd /etc/idmapd.conf
 
 instmods nfs
-inst_rules "$moddir/60-nfsroot.rules"
+inst_hook cmdline 90 "$moddir/parse-nfsroot.sh"
+inst_hook netroot 90 "$moddir/nfs-netroot.sh"
 inst_hook pre-pivot 70 "$moddir/nfsroot-cleanup.sh"
 inst "$moddir/nfsroot" "/sbin/nfsroot"
 mkdir -p "$initdir/var/lib/nfs/rpc_pipefs"
 mkdir -p "$initdir/var/lib/rpcbind"
 mkdir -p "$initdir/var/lib/nfs/statd/sm"
 
-# XXX debug
-mkdir -p "$initdir/mnt"
-
 # Rather than copy the passwd file in, just set a user for rpcbind
 # We'll save the state and restart the daemon from the root anyway
 #echo "rpc:x:32:32:Rpcbind:/var/lib/rpcbind:/bin/false" >> "$initdir/etc/passwd"
diff --git a/modules.d/95nfs/nfs-netroot.sh b/modules.d/95nfs/nfs-netroot.sh
new file mode 100755
index 0000000..ac72163
--- /dev/null
+++ b/modules.d/95nfs/nfs-netroot.sh
@@ -0,0 +1,52 @@
+#!/bin/sh # for highlighting
+
+# If we're auto-detecting our root type from DHCP, see if this looks like
+# an NFS root option. As the variety of root-path formats is large, validate
+# that the number of colons match what we expect, and our glob didn't
+# inadvertently match a different handler's.
+#
+if [ "$root" = "dhcp" -o "$root" = "nfs" -o "$root" = "nfs4" ]; then
+    nfsver=nfs
+    if [ "$root" = "nfs4" ]; then
+	nfsver=nfs4
+    fi
+    case "$new_root_path" in
+    nfs:*|nfs4:*) root="$new_root_path" ;;
+    *:/*:*)
+	if check_occurances "$new_root_path" ':' 2; then
+	    root="$nfsver:$new_root_path"
+	fi ;;
+    *:/*)
+	if check_occurances "$new_root_path" ':' 1; then
+	    root="$nfsver:$new_root_path:"
+	fi ;;
+    /*:*)
+	if check_occurances "$new_root_path" ':' 1; then
+	    root="$nfsver::$new_root_path"
+	fi ;;
+    /*)
+	if check_occurances "$new_root_path" ':' 0; then
+	    root="$nfsver::$new_root_path:"
+	fi ;;
+    esac
+fi
+
+if [ -z "${root%%nfs:*}" -o -z "${root%%nfs4:*}" ]; then
+    # Fill in missing information from DHCP
+    nfsver=${root%%:*}; root=${root#*:}
+    nfsserver=${root%%:*}; root=${root#*:}
+    nfspath=${root%%:*}
+    nfsflags=${root#*:}
+
+    # XXX where does dhclient stash the next-server option? Do we care?
+    if [ -z "$nfsserver" -o "$nfsserver" = "$nfspath" ]; then
+	nfsserver=$new_dhcp_server_identifier
+    fi
+    if [ "$nfspath" = "$nfsflags" ]; then
+	unset nfsflags
+    fi
+
+    # XXX validate we have all the required info?
+    root="$nfsver:$nfsserver:$nfspath:$nfsflags"
+    handler=/sbin/nfsroot
+fi
diff --git a/modules.d/95nfs/nfsroot b/modules.d/95nfs/nfsroot
index b8858bc..18e1300 100755
--- a/modules.d/95nfs/nfsroot
+++ b/modules.d/95nfs/nfsroot
@@ -6,77 +6,38 @@ PATH=$PATH:/sbin:/usr/sbin
 
 # XXX needs error handling like ifup/dhclient-script
 
-# XXX need to lock our attempts if we're doing the mount here
-
 getarg rdnetdebug && {
     exec > /tmp/nfsroot.$1.$$.out
     exec 2>> /tmp/nfsroot.$1.$$.out
     set -x
 }
 
-[ "$NFS_LOCKED" ] || {
-	NFS_LOCKED=true
-	export NFS_LOCKED
-	exec flock -xo /tmp/nfs.lock -c "$0 $*"
-	exit 1
-}
-
-[ -e /tmp/nfsdone ] && exit 0
-
-nfs_done() {
-    >/tmp/nfsdone
-    exit 0
-}
-
-root=$(getarg root)
-case $root in
-    nfs|/dev/nfs)	type=nfs  ;;
-    nfs4|/dev/nfs4)	type=nfs4 ;;
-    auto|'')		type=auto  ;;
-esac
-
-rootfstype=$(getarg rootfstype)
-case $rootfstype in
-    nfs|nfs4|auto)	type=$rootfstype  ;;
-esac
-
-# If we're not doing NFS at all, don't keep banging our head
-[ -n "$type" ] || nfs_done
-
-[ -e /tmp/net.$1.dhcpopts ] && . /tmp/net.$1.dhcpopts
+# root is in the form root=nfs[4]:server:path:[options]
+netif="$1"
+root="$2"
 
-nfsroot=$(getarg nfsroot)
-[ -n "$nfsroot" ] || nfsroot="$new_root_path"
-[ -n "$nfsroot" ] || nfs_done
-
-# check for IP address at front, if there is none, use
-# new_dhcp_server_identifier
-#
-# XXX kernel nfsroot uses , to separate NFS options at end
-#
-nfsserver=${nfsroot%%:*}; nfsroot=${nfsroot#*:}
-nfspath=${nfsroot%%:*}
-flags=${nfsroot#*:}
-[ "$nfsserver" = "$nfspath" ] && nfsserver=$new_dhcp_server_identifier
-[ "$nfspath" = "$flags" ] && unset flags
-
-[ -n "$nfsserver" ] || no_nfs
+nfsver=${root%%:*}; root=${root#*:}
+nfsserver=${root%%:*}; root=${root#*:}
+nfspath=${root%%:*}
+flags=${root#*:}
 
 # look through the flags and see if any are overridden by the command line
+# Append a , so we know we terminate
+flags=${flags},
 while [ -n "$flags" ]; do
-    f=${flags%%,*}; flags=${flags#*,}
-    [ "$f" = "nfs" -o "$f" = "nfs4" ] && {
-	[ "$type" = "auto" ] && type=$f
-	continue
-    }
-    [ "$f" = "ro" -o "$f" = "rw" ] && {
+    f=${flags%%,*}
+    flags=${flags#*,}
+    if [ -z "$f" ]; then
+	break
+    fi
+    if [ "$f" = "ro" -o "$f" = "rw" ]; then
 	nfsrw=$f
 	continue
-    }
-    [ "$f" = "lock" -o "$f" = "nolock" ] && {
+    fi
+    if [ "$f" = "lock" -o "$f" = "nolock" ]; then
 	nfslock=$f
 	continue
-    }
+    fi
     nfsflags=${nfsflags+$nfsflags,}$f
 done
 
@@ -84,11 +45,10 @@ getarg ro && nfsrw=ro
 getarg rw && nfsrw=rw
 nfsflags=${nfsflags+$nfsflags,}${nfsrw}
 
-# load our modules explicitly, so we can fail fast in the future
-modprobe nfs || nfs_done
+# Load the modules so the filesystem type is there
+modprobe nfs || exit 1
 
 # XXX don't forget to move /var/lib/nfs/rpc_pipefs to new /
-# XXX need host name set before now?
 
 # Start rpcbind and rpc.statd as mount won't let us use locks on a NFSv4
 # filesystem without talking to them, even though they are unneeded
@@ -102,24 +62,21 @@ modprobe nfs || nfs_done
 
 # XXX really, want to retry in a loop I think, but not here...
 
-[ "$type" = "nfs4" -o "$type" = "auto" ] && {
+if [ "$nfsver" = "nfs4" ]; then
     # XXX really needed? Do we need non-root users before we start it in
     # XXX the real root image?
-    [ -n "$(pidof rpc.idmapd)" ] || rpc.idmapd
+    if [ -z "$(pidof rpc.idmapd)" ]; then
+	rpc.idmapd
+    fi
 
     # NFSv4 does locks internally
-    mount -t nfs4 -o${nfsflags}${nfslock+,$nfslock} \
-			$nfsserver:$nfspath /sysroot && nfs_done
-
-    # If we're specified to be NFSv4, then stop when we fail
-    # Don't mark us done, as this may be transient
-    [ "$type" = "nfs4" ] && exit 0
-}
+    exec mount -t nfs4 -o${nfsflags}${nfslock+,$nfslock} \
+			$nfsserver:$nfspath $NEWROOT
+fi
 
-# we're NFSv{2,3} or auto and NFSv4 failed. We don't support using locks
-# on NFSv{2,3} because that requires a helper to transfer the rpcbind state
-# rpcbind to the new root
+# NFSv{2,3} doesn't support using locks as it requires a helper to transfer
+# the rpcbind state to the new root
+#
 [ -z "$nfslock" -o "$nfslock" = "lock" ] &&
     echo "Locks unsupported on NFSv{2,3}, using nolock" 1>&2
-mount -t nfs -onolock,$nfsflags $nfsserver:$nfspath /sysroot && nfs_done
-exit 0
+exec mount -t nfs -onolock,$nfsflags $nfsserver:$nfspath $NEWROOT
diff --git a/modules.d/95nfs/parse-nfsroot.sh b/modules.d/95nfs/parse-nfsroot.sh
new file mode 100755
index 0000000..5201e4b
--- /dev/null
+++ b/modules.d/95nfs/parse-nfsroot.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+# We're 90-nfs.sh to catch root=/dev/nfs
+#
+# Preferred format:
+#	root=nfs[4]:[server:]path[:options]
+#
+# If server is unspecified it will be pulled from one of the following
+# sources, in order:
+#	static ip= option on kernel command line
+#	DHCP next-server option
+#	DHCP server-id option
+#
+# Legacy formats:
+#	root=nfs[4]
+#	root=/dev/nfs[4] nfsroot=[server:]path[,options]
+#
+# Plain "root=nfs" interprets DHCP root-path option as [ip:]path[:options]
+#
+# NFSv4 is only used if explicitly listed; default is NFSv3
+#
+
+case "$root" in
+    nfs|dhcp|'')
+	if getarg nfsroot= > /dev/null; then
+	    root=nfs:$(getarg nfsroot=)
+	fi
+	;;
+    nfs4)
+	if getarg nfsroot= > /dev/null; then
+	    root=nfs4:$(getarg nfsroot=)
+	fi
+	;;
+    /dev/nfs|/dev/nfs4)
+	if getarg nfsroot= > /dev/null; then
+	    root=${root#/dev/}:$(getarg nfsroot=)
+	else
+	    root=${root#/dev/}
+	fi
+	;;
+esac
+
+case "$root" in
+    nfs|nfs4|nfs:*|nfs4:*)
+    	rootok=1
+    	netroot=nfs
+    ;;
+esac
diff --git a/modules.d/99base/dracut-lib b/modules.d/99base/dracut-lib
index 7078827..e3f4794 100644
--- a/modules.d/99base/dracut-lib
+++ b/modules.d/99base/dracut-lib
@@ -20,3 +20,19 @@ source_all() {
     [ "$1" ] && [  -d "/$1" ] || return
     for f in "/$1"/*.sh; do [ -f "$f" ] && . "$f"; done
 }
+
+check_occurances() {
+    # Count the number of times the character $ch occurs in $str
+    # Return 0 if the count matches the expected number, 1 otherwise
+    local str="$1"
+    local ch="$2"
+    local expected="$3"
+    local count=0
+
+    while [ "${str#*$ch}" != "${str}" ]; do
+	str="${str#*$ch}"
+	count=$(( $count + 1 ))
+    done
+
+    [ $count -eq $expected ]
+}
-- 
1.6.0.6

--
To unsubscribe from this list: send the line "unsubscribe initramfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux