svn commit: r253847 - in head/sys: kern nfs

Ian Lepore ian at FreeBSD.org
Wed Jul 31 19:14:01 UTC 2013


Author: ian
Date: Wed Jul 31 19:14:00 2013
New Revision: 253847
URL: http://svnweb.freebsd.org/changeset/base/253847

Log:
  Changes to allow using BOOTP_NFSROOT and mounting an nfs root filesystem
  other than the one specified by the BOOTP server.  This configures NFS
  using the BOOTP protocol while also respecting other root-path options such
  as setting vfs.root.mountfrom in the environment or using the RB_DFLTROOT
  boot option.  It allows you to override the root path provided by the
  server, or to supply a root path when the server provides IP configuration
  but no root path info.
  
  This maintains the historical BOOTP_NFSROOT behavior of panicking on a
  failure to mount the root path provided by the server, unless you've
  provided an alternative via the ROOTDEVNAME kernel option or by setting
  vfs.root.mountfrom.  The behavior of panicking when given no other options
  is preserved because it amounts to a bit of a retry loop that could
  eventually recover from a transient network or server problem.
  
  The user can now override the root path from loader(8) even if the
  kernel is compiled with BOOTP_NFSROOT.  If vfs.root.mountfrom is set in
  the environment it is used unconditionally -- it always overrides the
  BOOTP info.  If it begins with [old]nfs: then the BOOTP code uses it
  instead of the server-provided info.  If it specifies some other
  filesystem then the bootp code will not panic like it used to and the code
  in vfs_mountroot.c will invoke the right filesystem to do the mount.
  
  If the kernel is compiled with the ROOTDEVNAME option, then that name is
  used by the BOOTP code if either
        * The server doesn't provide a pathname.
        * The boothowto flags include RB_DFLTROOT.
  The latter allows the user to compile in alternate path in ROOTDEVNAME
  such as ufs:/dev/da0s1a and boot from that path by setting
  boot_dftlroot=1 in loader(8) or using the '-r' option in boot(8).
  
  The one thing not provided here is automatic failover from a
  server-provided path to a compiled-in one without the user manually
  requesting that.  The code just isn't currently structured in a way that
  makes that possible with a lot of rewrite.  I think the ability to set
  vfs.root.mountfrom and to use ROOTDEVNAME automatically when the server
  doesn't provide a name covers the most common needs.
  
  A set of patches submitted by Lars Eggert provided the part I couldn't
  figure out by myself when I tried to do this last year; many thanks.
  
  Reviewed by:	rodrigc

Modified:
  head/sys/kern/vfs_mountroot.c
  head/sys/nfs/bootp_subr.c

Modified: head/sys/kern/vfs_mountroot.c
==============================================================================
--- head/sys/kern/vfs_mountroot.c	Wed Jul 31 18:18:02 2013	(r253846)
+++ head/sys/kern/vfs_mountroot.c	Wed Jul 31 19:14:00 2013	(r253847)
@@ -714,8 +714,8 @@ parse_mount(char **conf)
 		goto out;
 	}
 
-	if (strcmp(fs, "zfs") != 0 && dev[0] != '\0' &&
-	    !parse_mount_dev_present(dev)) {
+	if (strcmp(fs, "zfs") != 0 && strstr(fs, "nfs") == NULL && 
+	    dev[0] != '\0' && !parse_mount_dev_present(dev)) {
 		printf("mountroot: waiting for device %s ...\n", dev);
 		delay = hz / 10;
 		timeout = root_mount_timeout * hz;

Modified: head/sys/nfs/bootp_subr.c
==============================================================================
--- head/sys/nfs/bootp_subr.c	Wed Jul 31 18:18:02 2013	(r253846)
+++ head/sys/nfs/bootp_subr.c	Wed Jul 31 19:14:00 2013	(r253847)
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
 
 #include "opt_bootp.h"
 #include "opt_nfs.h"
+#include "opt_rootdevname.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -55,6 +56,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/mount.h>
 #include <sys/mbuf.h>
 #include <sys/proc.h>
+#include <sys/reboot.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 #include <sys/sysctl.h>
@@ -167,6 +169,7 @@ struct bootpc_tagcontext {
 struct bootpc_globalcontext {
 	STAILQ_HEAD(, bootpc_ifcontext) interfaces;
 	u_int32_t xid;
+	int any_root_overrides;
 	int gotrootpath;
 	int gotgw;
 	int ifnum;
@@ -865,13 +868,14 @@ bootpc_call(struct bootpc_globalcontext 
 							BOOTP_SETTLE_DELAY;
 				} else
 					printf(" (ignored)");
-				if (ifctx->gotrootpath) {
+				if (ifctx->gotrootpath || 
+				    gctx->any_root_overrides) {
 					gotrootpath = 1;
 					rtimo = time_second +
 						BOOTP_SETTLE_DELAY;
-					printf(" (got root path)");
-				} else
-					printf(" (no root path)");
+					if (ifctx->gotrootpath)
+						printf(" (got root path)");
+				}
 				printf("\n");
 			}
 		} /* while secs */
@@ -1371,7 +1375,7 @@ static void
 bootpc_decode_reply(struct nfsv3_diskless *nd, struct bootpc_ifcontext *ifctx,
     struct bootpc_globalcontext *gctx)
 {
-	char *p;
+	char *p, *s;
 	unsigned int ip;
 
 	ifctx->gotgw = 0;
@@ -1438,8 +1442,30 @@ bootpc_decode_reply(struct nfsv3_diskles
 		}
 	}
 
-	p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
+	/*
+	 * Choose a root filesystem.  If a value is forced in the environment
+	 * and it contains "nfs:", use it unconditionally.  Otherwise, if the
+	 * kernel is compiled with the ROOTDEVNAME option, then use it if:
+	 *  - The server doesn't provide a pathname.
+	 *  - The boothowto flags include RB_DFLTROOT (user said to override
+	 *    the server value).
+	 */
+	p = NULL;
+	if ((s = getenv("vfs.root.mountfrom")) != NULL) {
+		if ((p = strstr(s, "nfs:")) != NULL)
+			p = strdup(p + 4, M_TEMP);
+		freeenv(s);
+	}
+	if (p == NULL) {
+		p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
 		       TAG_ROOT);
+	}
+#ifdef ROOTDEVNAME
+	if ((p == NULL || (boothowto & RB_DFLTROOT) != 0) && 
+	    (p = strstr(ROOTDEVNAME, "nfs:")) != NULL) {
+		p += 4;
+	}
+#endif
 	if (p != NULL) {
 		if (gctx->setrootfs != NULL) {
 			printf("rootfs %s (ignored) ", p);
@@ -1544,6 +1570,17 @@ bootpc_init(void)
 	gctx->starttime = time_second;
 
 	/*
+	 * If ROOTDEVNAME is defined or vfs.root.mountfrom is set then we have
+	 * root-path overrides that can potentially let us boot even if we don't
+	 * get a root path from the server, so we can treat that as a non-error.
+	 */
+#ifdef ROOTDEVNAME
+	gctx->any_root_overrides = 1;
+#else
+	gctx->any_root_overrides = testenv("vfs.root.mountfrom");
+#endif
+
+	/*
 	 * Find a network interface.
 	 */
 	CURVNET_SET(TD_TO_VNET(td));
@@ -1652,19 +1689,10 @@ retry:
 		bootpc_compose_query(ifctx, td);
 
 	error = bootpc_call(gctx, td);
-
 	if (error != 0) {
-#ifdef BOOTP_NFSROOT
-		panic("BOOTP call failed");
-#else
 		printf("BOOTP call failed\n");
-#endif
 	}
 
-	rootdevnames[0] = "nfs:";
-#ifdef NFSCLIENT
-	rootdevnames[1] = "oldnfs:";
-#endif
 	mountopts(&nd->root_args, NULL);
 
 	STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
@@ -1672,7 +1700,7 @@ retry:
 			bootpc_decode_reply(nd, ifctx, gctx);
 
 #ifdef BOOTP_NFSROOT
-	if (gctx->gotrootpath == 0)
+	if (gctx->gotrootpath == 0 && gctx->any_root_overrides == 0)
 		panic("bootpc: No root path offered");
 #endif
 
@@ -1699,9 +1727,16 @@ retry:
 		error = md_mount(&nd->root_saddr, nd->root_hostnam,
 				 nd->root_fh, &nd->root_fhsize,
 				 &nd->root_args, td);
-		if (error != 0)
-			panic("nfs_boot: mountd root, error=%d", error);
-
+		if (error != 0) {
+			if (gctx->any_root_overrides == 0)
+				panic("nfs_boot: mount root, error=%d", error);
+			else
+				goto out;
+		}
+		rootdevnames[0] = "nfs:";
+#ifdef NFSCLIENT
+		rootdevnames[1] = "oldnfs:";
+#endif
 		nfs_diskless_valid = 3;
 	}
 


More information about the svn-src-all mailing list