Skip to contentSkip to conversation

nfsroot

RFC PATCH In review Seewer Philippe 1 participant 1 message Jun 12, 2009

lore
Share & tools
lore
#0 lore raw

RFC PATCH 3/5 nfsroot

---

modules.d/95nfs/install          |   11 ++-
modules.d/95nfs/nfs-netroot.sh   |   67 ---------------
modules.d/95nfs/nfsroot          |  173 ++++++++++++++++++++++++++------------
modules.d/95nfs/parse-nfsroot.sh |  160 +++++++++++++++++++++++++++--------
4 files changed, 248 insertions(+), 163 deletions(-)
modules.d/95nfs/install +0 -0
index 12cc27d..afb0e41 100755
@@ -1,7 +1,12 @@

#!/bin/sh
-dracut_install rpcbind rpc.statd mount.nfs mount.nfs4 umount -dracut_install /etc/netconfig /etc/passwd /etc/services +
+which portmap >/dev/null 2>&1 && dracut_install portmap
+which rpcbind >/dev/null 2>&1 && dracut_install rpcbind
+
+dracut_install rpc.statd mount.nfs mount.nfs4 umount +dracut_install /etc/passwd /etc/services dracut_install /etc/nsswitch.conf /etc/rpc /etc/protocols +[ -f /etc/netconfig ] && dracut_install /etc/netconfig dracut_install rpc.idmapd /etc/idmapd.conf
if ldd $(which rpc.idmapd) |grep -q lib64; then

    LIBDIR="/lib64"

@@ -11,11 +16,9 @@ fi

dracut_install $(ls {/usr,}$LIBDIR/libnfsidmap*.so* 2>/dev/null ) dracut_install $(ls {/usr,}$LIBDIR/libnss*.so 2>/dev/null) -dracut_install grep

instmods nfs sunrpc ipv6
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"

modules.d/95nfs/nfs-netroot.sh deleted +0 -67

67 lines not on this page · raw message

modules.d/95nfs/nfsroot +0 -0
index cd3bc7c..e051004 100755
@@ -4,94 +4,157 @@
 

PATH=$PATH:/sbin:/usr/sbin

-# XXX needs error handling like ifup/dhclient-script -

getarg rdnetdebug && {
    exec > /tmp/nfsroot.$1.$$.out
    exec 2>> /tmp/nfsroot.$1.$$.out
    set -x
}

-# root is in the form root=nfs[4]:server:path:[options] +# Copy from parse-nfsroot.sh
+root_to_var() {

+    local v=${1}:
+    set --
+    while [ -n "$v" ]; do

+ set -- "$@" "${v%%:*}"
+ v=${v#*:}
+ done
+
+ unset nfs server path options
+

+    # Ugly: Can't -z test $path after the case, since it might be allowed
+    # to be empty for root=nfs
+    nfs=$1
+    case $# in
+    0|1);;
+    2)	path=${2:-error};;
+    3)
+    # This is ultra ugly. But we can't decide in which position path
+    # sits without checking if the string starts with '/'
+    case $2 in
+	/*) path=$2; options=$3;;
+	*) server=$2; path=${3:-error};;
+    esac
+    ;;
+    *)	server=$2; path=${3:-error}; options=$4;
+    esac
+    +    # Does it really start with '/'?
+    [ -n "${path%%/*}" ] && path="error";
+    +    #Fix kernel legacy style separating path and options with ','
+    if [ "$path" != "${path#*,}" ] ; then

+ options=${path#*,}
+ path=${path%%,*}
+ fi
+}
+
+# Huh? Empty $1?
+[ -z "$1" ] && exit 1
+
+# Huh? Empty $2?
+[ -z "$2" ] && exit 1
+
+# Huh? Empty $3?
+[ -z "$3" ] && exit 1
+
+# root is in the form root=nfs[4]:[server:]path[:options], either from +# cmdline or dhcp root-path
netif="$1"
root="$2"
+NEWROOT="$3"
+
+# If it's not nfs we don't continue
+case "${root%%:*}" in
+ nfs|nfs4);;
+ *) return;;
+esac
+
+# Ugly: root=nfs[4] requires dhcp root-path
+if [ "$root" = "nfs" ] || [ "$root" = "nfs4" ] ; then

+    # No need to check if the file exists. ip cmdline parser takes care of this
+    . /tmp/dhclient.$netif.dhcpopts
+    [ -z "$new_root_path" ] && die "Required dhcp option root-path not available"
+    root=$root:$new_root_path

+fi +
+root_to_var $root
+
+#Empty path defaults to "/tftpboot/%s"
+[ -z "$path" ] && path="/tftpboot/%s"
+
+if [ -z "$server" ] ; then
+ # No need to check if the file exists. ip cmdline parser takes care of this
+ . /tmp/dhclient.$netif.dhcpopts
+
+ # XXX new_dhcp_next_server is unconfirmed this is an assumption
+ for var in $new_dhcp_server_identifier $new_dhcp_next_server $new_root_path '' ; do
+ [ -n "$var" ] && server=$var && break;
+ done
+
+ # XXX This blindly assumes that if new_root_path has to used that + # XXX it really can be used as server
+ server=${server%%:*}
+fi

-nfsver=${root%%:*}; root=${root#*:} -nfsserver=${root%%:*}; root=${root#*:} -nfspath=${root%%:*}
-flags=${root#*:}
-
-[ -z "$nfspath" ] && nfspath=/tftpboot/%s
+[ -z "$server" ] && die "Required parameter 'server' is missing"

# Kernel replaces first %s with host name, and falls back to the ip address

# if it isn't set. Only the first %s is substituted.
-#
-if [ "${nfspath#*%s}" != "$nfspath" ]; then
+if [ "${path#*%s}" != "$path" ]; then
    ip=$(ip -o -f inet addr show $netif)
    ip=${ip%%/*}
    ip=${ip##* }
    read node < /proc/sys/kernel/hostname
    [ "$node" = "(none)" ] && node=$ip
-    nfspath=${nfspath%%%s*}$node${nfspath#*%s}
+    path=${path%%%s*}$node${path#*%s}
fi

-# 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#*,}
-    if [ -z "$f" ]; then

- break
- fi
- if [ "$f" = "ro" -o "$f" = "rw" ]; then
- nfsrw=$f
- continue
- fi
- if [ "$f" = "lock" -o "$f" = "nolock" ]; then
- nfslock=$f
- continue
- fi
- nfsflags=${nfsflags+$nfsflags,}$f
+# Look through the options and remove rw/locking options +OLDIFS=$IFS
+IFS=,
+for f in $options ; do

+    [ "$f" = "ro" -o "$f" = "rw" ] && nfsrw=$f && continue
+    [ "$f" = "lock" -o "$f" = "nolock" ] && nfslock=$f && continue
+    flags=${flags:+$flags,}$f

done
+IFS=$OLDIFS
+options=$flags

+# Override rw/ro if set on cmdline
getarg ro && nfsrw=ro
getarg rw && nfsrw=rw
-nfsflags=${nfsflags+$nfsflags,}${nfsrw}

-# Load the modules so the filesystem type is there

-incol2 /proc/filesystems nfs  || modprobe nfs || exit 1
-incol2 /proc/filesystems nfs4 || modprobe nfs || exit 1

+# Default to ro if unset
+[ -z "$nfsrw" ] && nfsrw=ro

-# XXX don't forget to move /var/lib/nfs/rpc_pipefs to new / +options=${options:+$options,}$nfsrw

-# 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 -# XXX occasionally saw 'rpcbind: fork failed: No such device' -- why? -[ -n "$(pidof rpcbind)" ] || rpcbind
-[ -n "$(pidof rpc.statd)" ] || rpc.statd

-# XXX should I do rpc.idmapd here, or wait and start in the new root -# XXX waiting assumes root can read everything it needs right up until -# XXX we start it...
+# Start rpcbind or portmap
+# FIXME occasionally saw 'rpcbind: fork failed: No such device' -- why? +[ -x /sbin/portmap ] && [ -z "$(pidof portmap)" ] && portmap +[ -x /sbin/rpcbind ] && [ -z "$(pidof rpcbind)" ] && rpcbind

-# XXX really, want to retry in a loop I think, but not here... +# XXX Should we loop here?
+if [ "$nfs" = "nfs4" ]; then

+    # Start rpc.statd as mount won't let us use locks on a NFSv4
+    # filesystem without talking to it. NFSv4 does locks internally,
+    # rpc.lockd isn't needed
+    [ -z "$(pidof rpc.statd)" ] && rpc.statd

-if [ "$nfsver" = "nfs4" ]; then
# XXX really needed? Do we need non-root users before we start it in # XXX the real root image?
- if [ -z "$(pidof rpc.idmapd)" ]; then
- rpc.idmapd
- fi
-
- # NFSv4 does locks internally
- exec mount -t nfs4 -o${nfsflags}${nfslock+,$nfslock} \
- $nfsserver:$nfspath $NEWROOT
+ [ -z "$(pidof rpc.idmapd)" ] && rpc.idmapd
+ + mount -t nfs4 -o$options${nfslock+,$nfslock} \
+ $server:$path $NEWROOT
fi

# 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
-exec mount -t nfs -onolock,$nfsflags $nfsserver:$nfspath $NEWROOT
+[ "$nfslock" = "lock" ] && \
+    echo "Warning: Locks unsupported on NFSv{2,3}, using nolock"
+
+# XXX Should we loop here?
+mount -t nfs -o$options${options:+,}nolock $server:$path $NEWROOT
modules.d/95nfs/parse-nfsroot.sh +1 -1
index 294ca28..26d1fd2 100755
@@ -1,55 +1,141 @@
-# We're 90-nfs.sh to catch root=/dev/nfs
+#!/bin/sh

#
# Preferred format:
# root=nfs[4]:[server:]path[:options]
-# netroot=nfs[4]:[server:]path[:options]
+# [root=*] netroot=nfs[4]:[server:]path[:options]
+#
+# Legacy formats:
+# [net]root=[[/dev/]nfs[4]] nfsroot=[server:]path[,options]
+# [net]root=[[/dev/]nfs[4]] nfsroot=[server:]path[:options]
+#
+# If the 'nfsroot' parameter is not given on the command line or is empty, +# the dhcp root-path is used as [server:]path[:options] or the default +# "/tftpboot/%s" will be used.
#
# 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
+# DHCP root-path option
#
-# Legacy formats:
-# root=nfs[4]
-# root=/dev/nfs[4] nfsroot=[server:]path[,options]
+# NFSv4 is only used if explicitly requested; default is NFSv2 or NFSv3 +# depending on kernel configuration
#
-# Plain "root=nfs" interprets DHCP root-path option as [ip:]path[:options] -#
-# NFSv4 is only used if explicitly listed; default is NFSv3
+# root= takes precedence over netroot= if root=nfs[...]
#

-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
- ;;
+# Sadly there's no easy way to split ':' separated lines into variables +netroot_to_var() {

+    local v=${1}:
+    set --
+    while [ -n "$v" ]; do

+ set -- "$@" "${v%%:*}"
+ v=${v#*:}
+ done
+
+ unset nfs server path options
+

+    nfs=$1
+    # Ugly: Can't -z test #path after the case, since it might be allowed
+    # to be empty for root=nfs
+    case $# in
+    0|1);;
+    2)	path=${2:-error};;
+    3)
+    # This is ultra ugly. But we can't decide in which position path
+    # sits without checking if the string starts with '/'
+    case $2 in
+	/*) path=$2; options=$3;;
+	*) server=$2; path=${3:-error};;
+    esac
+    ;;
+    *)	server=$2; path=${3:-error}; options=$4;
+    esac
+    +    # Does it really start with '/'?
+    [ -n "${path%%/*}" ] && path="error";
+    +    #Fix kernel legacy style separating path and options with ','
+    if [ "$path" != "${path#*,}" ] ; then

+ options=${path#*,}
+ path=${path%%,*}
+ fi
+}
+
+#Don't continue if root is ok
+[ -n "$rootok" ] && return
+
+# This script is sourced, so root should be set. But let's be paranoid +[ -z "$root" ] && root=$(getarg root=)
+[ -z "$netroot" ] && netroot=$(getarg netroot=)
+[ -z "$nfsroot" ] && nfsroot=$(getarg nfsroot=)
+
+# Root takes precedence over netroot
+case "${root%%:*}" in
+ nfs|nfs4|/dev/nfs|/dev/nfs4)
+ if [ -n "$netroot" ] ; then
+ echo "Warning: root takes precedence over netroot. Ignoring netroot"
+

+    fi
+    netroot=$root
+    ;;

esac

-if [ -z "$netroot" -a -n "$root" -a -z "${root%%nfs*}" ]; then
- netroot="$root"
- unset root
+# If it's not empty or nfs we don't continue
+case "${netroot%%:*}" in
+ ''|nfs|nfs4|/dev/nfs|/dev/nfs4);;
+ *) return;;
+esac
+
+if [ -n "$nfsroot" ] ; then
+ [ -z "$netroot" ] && netroot=$root
+

+    # @deprecated
+    echo "Warning: Argument nfsroot is deprecated and might be removed in a future"
+    echo "release. See http://apps.sourceforge.net/trac/dracut/wiki/commandline for"
+    echo "more information."

+
+ case "$netroot" in
+ ''|nfs|nfs4|/dev/nfs|/dev/nfs4) netroot=${netroot:-nfs}:$nfsroot;;
+ *) die "Argument nfsroot only accepted for empty root= or root=[/dev/]nfs[4]"
+ esac
fi

-case "$netroot" in
- nfs|nfs4|nfs:*|nfs4:*)
- rootok=1
- if [ -n "$root" -a "$netroot" != "$root" ]; then
- echo "WARNING: root= and netroot= do not match, ignoring root="
- fi
- unset root
- ;;
+# If it's not nfs we don't continue
+case "${netroot%%:*}" in
+ nfs|nfs4|/dev/nfs|/dev/nfs4);;
+ *) return;;
+esac
+
+# Check required arguments
+netroot_to_var $netroot
+[ "$path" = "error" ] && die "Argument nfsroot must contain a valid path!"
+
+# Set fstype, might help somewhere
+fstype=${nfs#/dev/}
+
+# NFS actually supported? Some more uglyness here: nfs3 or nfs4 might not
+# be in the module...
+if incol2 /proc/filesystems $fstype ; then
+ modprobe nfs
+ incol2 /proc/filesystems $fstype || die "nfsroot type $fstype requested but kernel/initrd does not support nfs"
+fi
+
+#Rewrite root so we don't have to parse this uglyness later on again +netroot="${netroot%%:*}:$server:$path:$options"
+
+#Delegate ip= checking to the ip script if we need dhcp/server-ip
+if [ -z "$server" ] ; then
+ NEEDDHCP="1"
+ DHCPORSERVER="1"
+fi;
+
+# Done, all good!
+rootok=1
+
+# Shut up init error check or make sure that block parser wont get +# confused by having /dev/nfs[4]
+case "$root" in + ''|/dev/nfs|/dev/nfs4) root="$fstype";;
esac
--
To unsubscribe from this list: send the line "unsubscribe initramfs" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html