svn commit: r193192 - in head/sys: boot/common kern

Craig Rodrigues rodrigc at FreeBSD.org
Mon Jun 1 01:02:31 UTC 2009


Author: rodrigc
Date: Mon Jun  1 01:02:30 2009
New Revision: 193192
URL: http://svn.freebsd.org/changeset/base/193192

Log:
  sys/boot/common.c
  =================
  Extend the loader to parse the root file system mount options in /etc/fstab,
  and set a new loader variable vfs.root.mountfrom.options with these options.
  The root mount options must be a comma-delimited string, as specified in
  /etc/fstab.
  Only set the vfs.root.mountfrom.options variable if it has not been
  set in the environment.
  
  sys/kern/vfs_mount.c
  ====================
  When mounting the root file system, pass the mount options
  specified in vfs.root.mountfrom.options, but filter out "rw" and "noro",
  since the initial mount of the root file system must be done as "ro".
  While we are here, try to add a few hints to the mountroot prompt
  to give users and idea what might of gone wrong during mounting
  of the root file system.
  
  Reviewed by:	jhb (an earlier patch)

Modified:
  head/sys/boot/common/boot.c
  head/sys/kern/vfs_mount.c

Modified: head/sys/boot/common/boot.c
==============================================================================
--- head/sys/boot/common/boot.c	Mon Jun  1 00:40:39 2009	(r193191)
+++ head/sys/boot/common/boot.c	Mon Jun  1 01:02:30 2009	(r193192)
@@ -287,7 +287,7 @@ getbootfile(int try)
 int
 getrootmount(char *rootdev)
 {
-    char	lbuf[128], *cp, *ep, *dev, *fstyp;
+    char	lbuf[128], *cp, *ep, *dev, *fstyp, *options;
     int		fd, error;
 
     if (getenv("vfs.root.mountfrom") != NULL)
@@ -331,11 +331,30 @@ getrootmount(char *rootdev)
 	*cp = 0;
 	fstyp = strdup(ep);
 
-	/* build the final result and save it */
+	/* skip whitespace up to mount options */
+	cp += 1;
+	while ((*cp != 0) && isspace(*cp))
+		cp++;
+	if (*cp == 0)           /* misformatted */
+		continue;
+	/* skip text to end of mount options and delimit */
+	ep = cp;
+	while ((*cp != 0) && !isspace(*cp))
+		cp++;
+	*cp = 0;
+	options = strdup(ep);
+	/* Build the <fstype>:<device> and save it in vfs.root.mountfrom */
 	sprintf(lbuf, "%s:%s", fstyp, dev);
 	free(dev);
 	free(fstyp);
 	setenv("vfs.root.mountfrom", lbuf, 0);
+
+	/* Don't override vfs.root.mountfrom.options if it is already set */
+	if (getenv("vfs.root.mountfrom.options") == NULL) {
+		/* save mount options */
+		setenv("vfs.root.mountfrom.options", options, 0);
+	}
+	free(options);
 	error = 0;
 	break;
     }

Modified: head/sys/kern/vfs_mount.c
==============================================================================
--- head/sys/kern/vfs_mount.c	Mon Jun  1 00:40:39 2009	(r193191)
+++ head/sys/kern/vfs_mount.c	Mon Jun  1 01:02:30 2009	(r193192)
@@ -77,7 +77,7 @@ static void	set_rootvnode(void);
 static int	vfs_domount(struct thread *td, const char *fstype,
 		    char *fspath, int fsflags, void *fsdata);
 static int	vfs_mountroot_ask(void);
-static int	vfs_mountroot_try(const char *mountfrom);
+static int	vfs_mountroot_try(const char *mountfrom, const char *options);
 static void	free_mntarg(struct mntarg *ma);
 
 static int	usermount = 0;
@@ -110,6 +110,10 @@ struct vnode	*rootvnode;
  *              of being mounted as root
  * path      := disk device name or other data used by the filesystem
  *              to locate its physical store
+ *
+ * The environment variable vfs.root.mountfrom options is a comma delimited
+ * set of string mount options.  These mount options must be parseable
+ * by nmount() in the kernel.
  */
 
 /*
@@ -1637,9 +1641,11 @@ vfs_opterror(struct vfsoptlist *opts, co
 void
 vfs_mountroot(void)
 {
-	char *cp;
+	char *cp, *options;
 	int error, i, asked = 0;
 
+	options = NULL;
+
 	root_mount_prepare();
 
 	mount_zone = uma_zcreate("Mountpoints", sizeof(struct mount),
@@ -1656,12 +1662,14 @@ vfs_mountroot(void)
 		asked = 1;
 	}
 
+	options = getenv("vfs.root.mountfrom.options");
+
 	/*
 	 * The root filesystem information is compiled in, and we are
 	 * booted with instructions to use it.
 	 */
 	if (ctrootdevname != NULL && (boothowto & RB_DFLTROOT)) {
-		if (!vfs_mountroot_try(ctrootdevname))
+		if (!vfs_mountroot_try(ctrootdevname, options))
 			goto mounted;
 		ctrootdevname = NULL;
 	}
@@ -1673,7 +1681,7 @@ vfs_mountroot(void)
 	 */
 	if (boothowto & RB_CDROM) {
 		for (i = 0; cdrom_rootdevnames[i] != NULL; i++) {
-			if (!vfs_mountroot_try(cdrom_rootdevnames[i]))
+			if (!vfs_mountroot_try(cdrom_rootdevnames[i], options))
 				goto mounted;
 		}
 	}
@@ -1685,7 +1693,7 @@ vfs_mountroot(void)
 	 */
 	cp = getenv("vfs.root.mountfrom");
 	if (cp != NULL) {
-		error = vfs_mountroot_try(cp);
+		error = vfs_mountroot_try(cp, options);
 		freeenv(cp);
 		if (!error)
 			goto mounted;
@@ -1694,16 +1702,16 @@ vfs_mountroot(void)
 	/*
 	 * Try values that may have been computed by code during boot
 	 */
-	if (!vfs_mountroot_try(rootdevnames[0]))
+	if (!vfs_mountroot_try(rootdevnames[0], options))
 		goto mounted;
-	if (!vfs_mountroot_try(rootdevnames[1]))
+	if (!vfs_mountroot_try(rootdevnames[1], options))
 		goto mounted;
 
 	/*
 	 * If we (still) have a compiled-in default, try it.
 	 */
 	if (ctrootdevname != NULL)
-		if (!vfs_mountroot_try(ctrootdevname))
+		if (!vfs_mountroot_try(ctrootdevname, options))
 			goto mounted;
 	/*
 	 * Everything so far has failed, prompt on the console if we haven't
@@ -1717,24 +1725,75 @@ vfs_mountroot(void)
 
 mounted:
 	root_mount_done();
+	freeenv(options);
+}
+
+static struct mntarg *
+parse_mountroot_options(struct mntarg *ma, const char *options)
+{
+	char *p;
+	char *name, *name_arg;
+	char *val, *val_arg;
+	char *opts;
+
+	if (options == NULL || options[0] == '\0')
+		return (ma);
+
+	p = opts = strdup(options, M_MOUNT);
+	if (opts == NULL) {
+		return (ma);
+	} 
+
+	while((name = strsep(&p, ",")) != NULL) {
+		if (name[0] == '\0')
+			break;
+
+		val = strchr(name, '=');
+		if (val != NULL) {
+			*val = '\0';
+			++val;
+		}
+		if( strcmp(name, "rw") == 0 ||
+		    strcmp(name, "noro") == 0) {
+			/*
+			 * The first time we mount the root file system,
+			 * we need to mount 'ro', so We need to ignore
+			 * 'rw' and 'noro' mount options.
+			 */
+			continue;
+		}
+		name_arg = strdup(name, M_MOUNT);
+		val_arg = NULL;
+		if (val != NULL) 
+			val_arg = strdup(val, M_MOUNT);
+
+		ma = mount_arg(ma, name_arg, val_arg,
+		    (val_arg != NULL ? -1 : 0));
+	}
+	free(opts, M_MOUNT);
+	return (ma);
 }
 
 /*
  * Mount (mountfrom) as the root filesystem.
  */
 static int
-vfs_mountroot_try(const char *mountfrom)
+vfs_mountroot_try(const char *mountfrom, const char *options)
 {
 	struct mount	*mp;
+	struct mntarg	*ma;
 	char		*vfsname, *path;
 	time_t		timebase;
 	int		error;
 	char		patt[32];
+	char		errmsg[255];
 
 	vfsname = NULL;
 	path    = NULL;
 	mp      = NULL;
+	ma	= NULL;
 	error   = EINVAL;
+	bzero(errmsg, sizeof(errmsg));
 
 	if (mountfrom == NULL)
 		return (error);		/* don't complain */
@@ -1751,12 +1810,14 @@ vfs_mountroot_try(const char *mountfrom)
 	if (path[0] == '\0')
 		strcpy(path, ROOTNAME);
 
-	error = kernel_vmount(
-	    MNT_RDONLY | MNT_ROOTFS,
-	    "fstype", vfsname,
-	    "fspath", "/",
-	    "from", path,
-	    NULL);
+	ma = mount_arg(ma, "fstype", vfsname, -1);
+	ma = mount_arg(ma, "fspath", "/", -1);
+	ma = mount_arg(ma, "from", path, -1);
+	ma = mount_arg(ma, "errmsg", errmsg, sizeof(errmsg));
+	ma = mount_arg(ma, "ro", NULL, 0);
+	ma = parse_mountroot_options(ma, options);
+	error = kernel_mount(ma, MNT_ROOTFS);
+
 	if (error == 0) {
 		/*
 		 * We mount devfs prior to mounting the / FS, so the first
@@ -1783,6 +1844,16 @@ vfs_mountroot_try(const char *mountfrom)
 
 		devfs_fixup(curthread);
 	}
+
+	if (error != 0 ) {
+		printf("ROOT MOUNT ERROR: %s\n", errmsg);
+		printf("If you have invalid mount options, reboot, and ");
+		printf("first try the following from\n");
+		printf("the loader prompt:\n\n");
+		printf("     set vfs.root.mountfrom.options=rw\n\n");
+		printf("and then remove invalid mount options from ");
+		printf("/etc/fstab.\n\n");
+	}
 out:
 	free(path, M_MOUNT);
 	free(vfsname, M_MOUNT);
@@ -1798,15 +1869,32 @@ static int
 vfs_mountroot_ask(void)
 {
 	char name[128];
+	char *mountfrom;
+	char *options;
 
 	for(;;) {
+		printf("Loader variables:\n");
+		printf("vfs.root.mountfrom=");
+		mountfrom = getenv("vfs.root.mountfrom");
+		if (mountfrom != NULL) {
+			printf("%s", mountfrom);
+		}
+		printf("\n");
+		printf("vfs.root.mountfrom.options=");
+		options = getenv("vfs.root.mountfrom.options");
+		if (options != NULL) {
+			printf("%s", options);
+		}
+		printf("\n");
+		freeenv(mountfrom);
+		freeenv(options);
 		printf("\nManual root filesystem specification:\n");
 		printf("  <fstype>:<device>  Mount <device> using filesystem <fstype>\n");
-#if defined(__amd64__) || defined(__i386__) || defined(__ia64__)
-		printf("                       eg. ufs:da0s1a\n");
-#else
-		printf("                       eg. ufs:/dev/da0a\n");
-#endif
+		printf("                       eg. ufs:/dev/da0s1a\n");
+		printf("                       eg. cd9660:/dev/acd0\n");
+		printf("                       This is equivalent to: ");
+		printf("mount -t cd9660 /dev/acd0 /\n"); 
+		printf("\n");
 		printf("  ?                  List valid disk boot devices\n");
 		printf("  <empty line>       Abort manual input\n");
 		printf("\nmountroot> ");
@@ -1818,7 +1906,7 @@ vfs_mountroot_ask(void)
 			g_dev_print();
 			continue;
 		}
-		if (!vfs_mountroot_try(name))
+		if (!vfs_mountroot_try(name, NULL))
 			return (0);
 	}
 }


More information about the svn-src-head mailing list