summaryrefslogtreecommitdiffstats
path: root/sys/nfs
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2013-07-31 19:14:00 +0000
committerian <ian@FreeBSD.org>2013-07-31 19:14:00 +0000
commit24c5871f5aaf01f006fc71eb30589d12f6f2ecb2 (patch)
treefc3006350cbf8829022d6200458811d13c821525 /sys/nfs
parent19e0ec879c3e5b92cf8fd6410016cc57d87f8bc3 (diff)
downloadFreeBSD-src-24c5871f5aaf01f006fc71eb30589d12f6f2ecb2.zip
FreeBSD-src-24c5871f5aaf01f006fc71eb30589d12f6f2ecb2.tar.gz
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
Diffstat (limited to 'sys/nfs')
-rw-r--r--sys/nfs/bootp_subr.c73
1 files changed, 54 insertions, 19 deletions
diff --git a/sys/nfs/bootp_subr.c b/sys/nfs/bootp_subr.c
index 2c57a91..7b84f94 100644
--- a/sys/nfs/bootp_subr.c
+++ b/sys/nfs/bootp_subr.c
@@ -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 *gctx, struct thread *td)
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_diskless *nd, struct bootpc_ifcontext *ifctx,
}
}
- 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;
}
OpenPOWER on IntegriCloud