Index: sys/nfs/bootp_subr.c =================================================================== --- sys/nfs/bootp_subr.c (revision 251469) +++ sys/nfs/bootp_subr.c (working copy) @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include "opt_bootp.h" #include "opt_nfs.h" +#include "opt_rootdevname.h" #include #include @@ -55,6 +56,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -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, str 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,28 @@ bootpc_decode_reply(struct nfsv3_diskless *nd, str } } - 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, use + * ROOTDEVNAME if it contains "nfs:" and either the server didn't + * provide a name or the boot options say to force ROOTDEVNAME. + */ + 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 +1568,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 +1687,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 +1698,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 +1725,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; } Index: sys/kern/vfs_mountroot.c =================================================================== --- sys/kern/vfs_mountroot.c (revision 251469) +++ sys/kern/vfs_mountroot.c (working copy) @@ -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;