vfs_mountroot.c revision 213365
1213365Smarcel/*-
2213365Smarcel * Copyright (c) 1999-2004 Poul-Henning Kamp
3213365Smarcel * Copyright (c) 1999 Michael Smith
4213365Smarcel * Copyright (c) 1989, 1993
5213365Smarcel *      The Regents of the University of California.  All rights reserved.
6213365Smarcel * (c) UNIX System Laboratories, Inc.
7213365Smarcel * All or some portions of this file are derived from material licensed
8213365Smarcel * to the University of California by American Telephone and Telegraph
9213365Smarcel * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10213365Smarcel * the permission of UNIX System Laboratories, Inc.
11213365Smarcel *
12213365Smarcel * Redistribution and use in source and binary forms, with or without
13213365Smarcel * modification, are permitted provided that the following conditions
14213365Smarcel * are met:
15213365Smarcel * 1. Redistributions of source code must retain the above copyright
16213365Smarcel *    notice, this list of conditions and the following disclaimer.
17213365Smarcel * 2. Redistributions in binary form must reproduce the above copyright
18213365Smarcel *    notice, this list of conditions and the following disclaimer in the
19213365Smarcel *    documentation and/or other materials provided with the distribution.
20213365Smarcel * 4. Neither the name of the University nor the names of its contributors
21213365Smarcel *    may be used to endorse or promote products derived from this software
22213365Smarcel *    without specific prior written permission.
23213365Smarcel *
24213365Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25213365Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26213365Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27213365Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28213365Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29213365Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30213365Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31213365Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32213365Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33213365Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34213365Smarcel * SUCH DAMAGE.
35213365Smarcel */
36213365Smarcel
37213365Smarcel#include <sys/cdefs.h>
38213365Smarcel__FBSDID("$FreeBSD: head/sys/kern/vfs_mountroot.c 213365 2010-10-02 19:44:13Z marcel $");
39213365Smarcel
40213365Smarcel#include <sys/param.h>
41213365Smarcel#include <sys/conf.h>
42213365Smarcel#include <sys/fcntl.h>
43213365Smarcel#include <sys/jail.h>
44213365Smarcel#include <sys/kernel.h>
45213365Smarcel#include <sys/libkern.h>
46213365Smarcel#include <sys/malloc.h>
47213365Smarcel#include <sys/mount.h>
48213365Smarcel#include <sys/mutex.h>
49213365Smarcel#include <sys/namei.h>
50213365Smarcel#include <sys/priv.h>
51213365Smarcel#include <sys/proc.h>
52213365Smarcel#include <sys/filedesc.h>
53213365Smarcel#include <sys/reboot.h>
54213365Smarcel#include <sys/syscallsubr.h>
55213365Smarcel#include <sys/sysproto.h>
56213365Smarcel#include <sys/sx.h>
57213365Smarcel#include <sys/sysctl.h>
58213365Smarcel#include <sys/sysent.h>
59213365Smarcel#include <sys/systm.h>
60213365Smarcel#include <sys/vnode.h>
61213365Smarcel#include <vm/uma.h>
62213365Smarcel
63213365Smarcel#include <geom/geom.h>
64213365Smarcel
65213365Smarcel#include <machine/stdarg.h>
66213365Smarcel
67213365Smarcel#include "opt_rootdevname.h"
68213365Smarcel
69213365Smarcel#define	ROOTNAME		"root_device"
70213365Smarcel
71213365Smarcelstatic int	vfs_mountroot_ask(void);
72213365Smarcelstatic int	vfs_mountroot_try(const char *mountfrom, const char *options);
73213365Smarcel
74213365Smarcel/*
75213365Smarcel * The vnode of the system's root (/ in the filesystem, without chroot
76213365Smarcel * active.)
77213365Smarcel */
78213365Smarcelstruct vnode	*rootvnode;
79213365Smarcel
80213365Smarcel/*
81213365Smarcel * The root filesystem is detailed in the kernel environment variable
82213365Smarcel * vfs.root.mountfrom, which is expected to be in the general format
83213365Smarcel *
84213365Smarcel * <vfsname>:[<path>][	<vfsname>:[<path>] ...]
85213365Smarcel * vfsname   := the name of a VFS known to the kernel and capable
86213365Smarcel *              of being mounted as root
87213365Smarcel * path      := disk device name or other data used by the filesystem
88213365Smarcel *              to locate its physical store
89213365Smarcel *
90213365Smarcel * If the environment variable vfs.root.mountfrom is a space separated list,
91213365Smarcel * each list element is tried in turn and the root filesystem will be mounted
92213365Smarcel * from the first one that suceeds.
93213365Smarcel *
94213365Smarcel * The environment variable vfs.root.mountfrom.options is a comma delimited
95213365Smarcel * set of string mount options.  These mount options must be parseable
96213365Smarcel * by nmount() in the kernel.
97213365Smarcel */
98213365Smarcel
99213365Smarcel/*
100213365Smarcel * The root specifiers we will try if RB_CDROM is specified.
101213365Smarcel */
102213365Smarcelstatic char *cdrom_rootdevnames[] = {
103213365Smarcel	"cd9660:cd0",
104213365Smarcel	"cd9660:acd0",
105213365Smarcel	NULL
106213365Smarcel};
107213365Smarcel
108213365Smarcel/* legacy find-root code */
109213365Smarcelchar		*rootdevnames[2] = {NULL, NULL};
110213365Smarcel#ifndef ROOTDEVNAME
111213365Smarcel#  define ROOTDEVNAME NULL
112213365Smarcel#endif
113213365Smarcelstatic const char	*ctrootdevname = ROOTDEVNAME;
114213365Smarcel
115213365Smarcelstruct root_hold_token {
116213365Smarcel	const char			*who;
117213365Smarcel	LIST_ENTRY(root_hold_token)	list;
118213365Smarcel};
119213365Smarcel
120213365Smarcelstatic LIST_HEAD(, root_hold_token)	root_holds =
121213365Smarcel    LIST_HEAD_INITIALIZER(root_holds);
122213365Smarcel
123213365Smarcelstatic int root_mount_complete;
124213365Smarcel
125213365Smarcelstruct root_hold_token *
126213365Smarcelroot_mount_hold(const char *identifier)
127213365Smarcel{
128213365Smarcel	struct root_hold_token *h;
129213365Smarcel
130213365Smarcel	if (root_mounted())
131213365Smarcel		return (NULL);
132213365Smarcel
133213365Smarcel	h = malloc(sizeof *h, M_DEVBUF, M_ZERO | M_WAITOK);
134213365Smarcel	h->who = identifier;
135213365Smarcel	mtx_lock(&mountlist_mtx);
136213365Smarcel	LIST_INSERT_HEAD(&root_holds, h, list);
137213365Smarcel	mtx_unlock(&mountlist_mtx);
138213365Smarcel	return (h);
139213365Smarcel}
140213365Smarcel
141213365Smarcelvoid
142213365Smarcelroot_mount_rel(struct root_hold_token *h)
143213365Smarcel{
144213365Smarcel
145213365Smarcel	if (h == NULL)
146213365Smarcel		return;
147213365Smarcel	mtx_lock(&mountlist_mtx);
148213365Smarcel	LIST_REMOVE(h, list);
149213365Smarcel	wakeup(&root_holds);
150213365Smarcel	mtx_unlock(&mountlist_mtx);
151213365Smarcel	free(h, M_DEVBUF);
152213365Smarcel}
153213365Smarcel
154213365Smarcelstatic void
155213365Smarcelroot_mount_prepare(void)
156213365Smarcel{
157213365Smarcel	struct root_hold_token *h;
158213365Smarcel	struct timeval lastfail;
159213365Smarcel	int curfail = 0;
160213365Smarcel
161213365Smarcel	for (;;) {
162213365Smarcel		DROP_GIANT();
163213365Smarcel		g_waitidle();
164213365Smarcel		PICKUP_GIANT();
165213365Smarcel		mtx_lock(&mountlist_mtx);
166213365Smarcel		if (LIST_EMPTY(&root_holds)) {
167213365Smarcel			mtx_unlock(&mountlist_mtx);
168213365Smarcel			break;
169213365Smarcel		}
170213365Smarcel		if (ppsratecheck(&lastfail, &curfail, 1)) {
171213365Smarcel			printf("Root mount waiting for:");
172213365Smarcel			LIST_FOREACH(h, &root_holds, list)
173213365Smarcel				printf(" %s", h->who);
174213365Smarcel			printf("\n");
175213365Smarcel		}
176213365Smarcel		msleep(&root_holds, &mountlist_mtx, PZERO | PDROP, "roothold",
177213365Smarcel		    hz);
178213365Smarcel	}
179213365Smarcel}
180213365Smarcel
181213365Smarcelstatic void
182213365Smarcelroot_mount_done(void)
183213365Smarcel{
184213365Smarcel
185213365Smarcel	/* Keep prison0's root in sync with the global rootvnode. */
186213365Smarcel	mtx_lock(&prison0.pr_mtx);
187213365Smarcel	prison0.pr_root = rootvnode;
188213365Smarcel	vref(prison0.pr_root);
189213365Smarcel	mtx_unlock(&prison0.pr_mtx);
190213365Smarcel	/*
191213365Smarcel	 * Use a mutex to prevent the wakeup being missed and waiting for
192213365Smarcel	 * an extra 1 second sleep.
193213365Smarcel	 */
194213365Smarcel	mtx_lock(&mountlist_mtx);
195213365Smarcel	root_mount_complete = 1;
196213365Smarcel	wakeup(&root_mount_complete);
197213365Smarcel	mtx_unlock(&mountlist_mtx);
198213365Smarcel}
199213365Smarcel
200213365Smarcelint
201213365Smarcelroot_mounted(void)
202213365Smarcel{
203213365Smarcel
204213365Smarcel	/* No mutex is acquired here because int stores are atomic. */
205213365Smarcel	return (root_mount_complete);
206213365Smarcel}
207213365Smarcel
208213365Smarcelvoid
209213365Smarcelroot_mount_wait(void)
210213365Smarcel{
211213365Smarcel
212213365Smarcel	/*
213213365Smarcel	 * Panic on an obvious deadlock - the function can't be called from
214213365Smarcel	 * a thread which is doing the whole SYSINIT stuff.
215213365Smarcel	 */
216213365Smarcel	KASSERT(curthread->td_proc->p_pid != 0,
217213365Smarcel	    ("root_mount_wait: cannot be called from the swapper thread"));
218213365Smarcel	mtx_lock(&mountlist_mtx);
219213365Smarcel	while (!root_mount_complete) {
220213365Smarcel		msleep(&root_mount_complete, &mountlist_mtx, PZERO, "rootwait",
221213365Smarcel		    hz);
222213365Smarcel	}
223213365Smarcel	mtx_unlock(&mountlist_mtx);
224213365Smarcel}
225213365Smarcel
226213365Smarcelstatic void
227213365Smarcelset_rootvnode(void)
228213365Smarcel{
229213365Smarcel	struct proc *p;
230213365Smarcel
231213365Smarcel	if (VFS_ROOT(TAILQ_FIRST(&mountlist), LK_EXCLUSIVE, &rootvnode))
232213365Smarcel		panic("Cannot find root vnode");
233213365Smarcel
234213365Smarcel	VOP_UNLOCK(rootvnode, 0);
235213365Smarcel
236213365Smarcel	p = curthread->td_proc;
237213365Smarcel	FILEDESC_XLOCK(p->p_fd);
238213365Smarcel
239213365Smarcel	if (p->p_fd->fd_cdir != NULL)
240213365Smarcel		vrele(p->p_fd->fd_cdir);
241213365Smarcel	p->p_fd->fd_cdir = rootvnode;
242213365Smarcel	VREF(rootvnode);
243213365Smarcel
244213365Smarcel	if (p->p_fd->fd_rdir != NULL)
245213365Smarcel		vrele(p->p_fd->fd_rdir);
246213365Smarcel	p->p_fd->fd_rdir = rootvnode;
247213365Smarcel	VREF(rootvnode);
248213365Smarcel
249213365Smarcel	FILEDESC_XUNLOCK(p->p_fd);
250213365Smarcel
251213365Smarcel	EVENTHANDLER_INVOKE(mountroot);
252213365Smarcel}
253213365Smarcel
254213365Smarcelstatic void
255213365Smarceldevfs_first(void)
256213365Smarcel{
257213365Smarcel	struct thread *td = curthread;
258213365Smarcel	struct vfsoptlist *opts;
259213365Smarcel	struct vfsconf *vfsp;
260213365Smarcel	struct mount *mp = NULL;
261213365Smarcel	int error;
262213365Smarcel
263213365Smarcel	vfsp = vfs_byname("devfs");
264213365Smarcel	KASSERT(vfsp != NULL, ("Could not find devfs by name"));
265213365Smarcel	if (vfsp == NULL)
266213365Smarcel		return;
267213365Smarcel
268213365Smarcel	mp = vfs_mount_alloc(NULLVP, vfsp, "/dev", td->td_ucred);
269213365Smarcel
270213365Smarcel	error = VFS_MOUNT(mp);
271213365Smarcel	KASSERT(error == 0, ("VFS_MOUNT(devfs) failed %d", error));
272213365Smarcel	if (error)
273213365Smarcel		return;
274213365Smarcel
275213365Smarcel	opts = malloc(sizeof(struct vfsoptlist), M_MOUNT, M_WAITOK);
276213365Smarcel	TAILQ_INIT(opts);
277213365Smarcel	mp->mnt_opt = opts;
278213365Smarcel
279213365Smarcel	mtx_lock(&mountlist_mtx);
280213365Smarcel	TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list);
281213365Smarcel	mtx_unlock(&mountlist_mtx);
282213365Smarcel
283213365Smarcel	set_rootvnode();
284213365Smarcel
285213365Smarcel	error = kern_symlink(td, "/", "dev", UIO_SYSSPACE);
286213365Smarcel	if (error)
287213365Smarcel		printf("kern_symlink /dev -> / returns %d\n", error);
288213365Smarcel}
289213365Smarcel
290213365Smarcelstatic void
291213365Smarceldevfs_fixup(struct thread *td)
292213365Smarcel{
293213365Smarcel	struct nameidata nd;
294213365Smarcel	struct vnode *vp, *dvp;
295213365Smarcel	struct mount *mp;
296213365Smarcel	int error;
297213365Smarcel
298213365Smarcel	/* Remove our devfs mount from the mountlist and purge the cache */
299213365Smarcel	mtx_lock(&mountlist_mtx);
300213365Smarcel	mp = TAILQ_FIRST(&mountlist);
301213365Smarcel	TAILQ_REMOVE(&mountlist, mp, mnt_list);
302213365Smarcel	mtx_unlock(&mountlist_mtx);
303213365Smarcel	cache_purgevfs(mp);
304213365Smarcel
305213365Smarcel	VFS_ROOT(mp, LK_EXCLUSIVE, &dvp);
306213365Smarcel	VI_LOCK(dvp);
307213365Smarcel	dvp->v_iflag &= ~VI_MOUNT;
308213365Smarcel	VI_UNLOCK(dvp);
309213365Smarcel	dvp->v_mountedhere = NULL;
310213365Smarcel
311213365Smarcel	/* Set up the real rootvnode, and purge the cache */
312213365Smarcel	TAILQ_FIRST(&mountlist)->mnt_vnodecovered = NULL;
313213365Smarcel	set_rootvnode();
314213365Smarcel	cache_purgevfs(rootvnode->v_mount);
315213365Smarcel
316213365Smarcel	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, "/dev", td);
317213365Smarcel	error = namei(&nd);
318213365Smarcel	if (error) {
319213365Smarcel		printf("Lookup of /dev for devfs, error: %d\n", error);
320213365Smarcel		vput(dvp);
321213365Smarcel		vfs_unbusy(mp);
322213365Smarcel		return;
323213365Smarcel	}
324213365Smarcel	NDFREE(&nd, NDF_ONLY_PNBUF);
325213365Smarcel	vp = nd.ni_vp;
326213365Smarcel	if (vp->v_type != VDIR) {
327213365Smarcel		printf("/dev is not a directory\n");
328213365Smarcel		vput(dvp);
329213365Smarcel		vput(vp);
330213365Smarcel		vfs_unbusy(mp);
331213365Smarcel		return;
332213365Smarcel	}
333213365Smarcel	error = vinvalbuf(vp, V_SAVE, 0, 0);
334213365Smarcel	if (error) {
335213365Smarcel		printf("vinvalbuf() of /dev failed, error: %d\n", error);
336213365Smarcel		vput(dvp);
337213365Smarcel		vput(vp);
338213365Smarcel		vfs_unbusy(mp);
339213365Smarcel		return;
340213365Smarcel	}
341213365Smarcel	cache_purge(vp);
342213365Smarcel	mp->mnt_vnodecovered = vp;
343213365Smarcel	vp->v_mountedhere = mp;
344213365Smarcel	mtx_lock(&mountlist_mtx);
345213365Smarcel	TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
346213365Smarcel	mtx_unlock(&mountlist_mtx);
347213365Smarcel	VOP_UNLOCK(vp, 0);
348213365Smarcel	vput(dvp);
349213365Smarcel	vfs_unbusy(mp);
350213365Smarcel
351213365Smarcel	/* Unlink the no longer needed /dev/dev -> / symlink */
352213365Smarcel	error = kern_unlink(td, "/dev/dev", UIO_SYSSPACE);
353213365Smarcel	if (error)
354213365Smarcel		printf("kern_unlink of /dev/dev failed, error: %d\n", error);
355213365Smarcel}
356213365Smarcel
357213365Smarcelvoid
358213365Smarcelvfs_mountroot(void)
359213365Smarcel{
360213365Smarcel	char *cp, *cpt, *options, *tmpdev;
361213365Smarcel	int error, i, asked = 0;
362213365Smarcel
363213365Smarcel	options = NULL;
364213365Smarcel
365213365Smarcel	root_mount_prepare();
366213365Smarcel
367213365Smarcel	devfs_first();
368213365Smarcel
369213365Smarcel	/*
370213365Smarcel	 * We are booted with instructions to prompt for the root filesystem.
371213365Smarcel	 */
372213365Smarcel	if (boothowto & RB_ASKNAME) {
373213365Smarcel		if (!vfs_mountroot_ask())
374213365Smarcel			goto mounted;
375213365Smarcel		asked = 1;
376213365Smarcel	}
377213365Smarcel
378213365Smarcel	options = getenv("vfs.root.mountfrom.options");
379213365Smarcel
380213365Smarcel	/*
381213365Smarcel	 * The root filesystem information is compiled in, and we are
382213365Smarcel	 * booted with instructions to use it.
383213365Smarcel	 */
384213365Smarcel	if (ctrootdevname != NULL && (boothowto & RB_DFLTROOT)) {
385213365Smarcel		if (!vfs_mountroot_try(ctrootdevname, options))
386213365Smarcel			goto mounted;
387213365Smarcel		ctrootdevname = NULL;
388213365Smarcel	}
389213365Smarcel
390213365Smarcel	/*
391213365Smarcel	 * We've been given the generic "use CDROM as root" flag.  This is
392213365Smarcel	 * necessary because one media may be used in many different
393213365Smarcel	 * devices, so we need to search for them.
394213365Smarcel	 */
395213365Smarcel	if (boothowto & RB_CDROM) {
396213365Smarcel		for (i = 0; cdrom_rootdevnames[i] != NULL; i++) {
397213365Smarcel			if (!vfs_mountroot_try(cdrom_rootdevnames[i], options))
398213365Smarcel				goto mounted;
399213365Smarcel		}
400213365Smarcel	}
401213365Smarcel
402213365Smarcel	/*
403213365Smarcel	 * Try to use the value read by the loader from /etc/fstab, or
404213365Smarcel	 * supplied via some other means.  This is the preferred
405213365Smarcel	 * mechanism.
406213365Smarcel	 */
407213365Smarcel	cp = getenv("vfs.root.mountfrom");
408213365Smarcel	if (cp != NULL) {
409213365Smarcel		cpt = cp;
410213365Smarcel		while ((tmpdev = strsep(&cpt, " \t")) != NULL) {
411213365Smarcel			error = vfs_mountroot_try(tmpdev, options);
412213365Smarcel			if (error == 0) {
413213365Smarcel				freeenv(cp);
414213365Smarcel				goto mounted;
415213365Smarcel			}
416213365Smarcel		}
417213365Smarcel		freeenv(cp);
418213365Smarcel	}
419213365Smarcel
420213365Smarcel	/*
421213365Smarcel	 * Try values that may have been computed by code during boot
422213365Smarcel	 */
423213365Smarcel	if (!vfs_mountroot_try(rootdevnames[0], options))
424213365Smarcel		goto mounted;
425213365Smarcel	if (!vfs_mountroot_try(rootdevnames[1], options))
426213365Smarcel		goto mounted;
427213365Smarcel
428213365Smarcel	/*
429213365Smarcel	 * If we (still) have a compiled-in default, try it.
430213365Smarcel	 */
431213365Smarcel	if (ctrootdevname != NULL)
432213365Smarcel		if (!vfs_mountroot_try(ctrootdevname, options))
433213365Smarcel			goto mounted;
434213365Smarcel	/*
435213365Smarcel	 * Everything so far has failed, prompt on the console if we haven't
436213365Smarcel	 * already tried that.
437213365Smarcel	 */
438213365Smarcel	if (!asked)
439213365Smarcel		if (!vfs_mountroot_ask())
440213365Smarcel			goto mounted;
441213365Smarcel
442213365Smarcel	panic("Root mount failed, startup aborted.");
443213365Smarcel
444213365Smarcelmounted:
445213365Smarcel	root_mount_done();
446213365Smarcel	freeenv(options);
447213365Smarcel}
448213365Smarcel
449213365Smarcelstatic struct mntarg *
450213365Smarcelparse_mountroot_options(struct mntarg *ma, const char *options)
451213365Smarcel{
452213365Smarcel	char *p;
453213365Smarcel	char *name, *name_arg;
454213365Smarcel	char *val, *val_arg;
455213365Smarcel	char *opts;
456213365Smarcel
457213365Smarcel	if (options == NULL || options[0] == '\0')
458213365Smarcel		return (ma);
459213365Smarcel
460213365Smarcel	p = opts = strdup(options, M_MOUNT);
461213365Smarcel	if (opts == NULL) {
462213365Smarcel		return (ma);
463213365Smarcel	}
464213365Smarcel
465213365Smarcel	while((name = strsep(&p, ",")) != NULL) {
466213365Smarcel		if (name[0] == '\0')
467213365Smarcel			break;
468213365Smarcel
469213365Smarcel		val = strchr(name, '=');
470213365Smarcel		if (val != NULL) {
471213365Smarcel			*val = '\0';
472213365Smarcel			++val;
473213365Smarcel		}
474213365Smarcel		if( strcmp(name, "rw") == 0 ||
475213365Smarcel		    strcmp(name, "noro") == 0) {
476213365Smarcel			/*
477213365Smarcel			 * The first time we mount the root file system,
478213365Smarcel			 * we need to mount 'ro', so We need to ignore
479213365Smarcel			 * 'rw' and 'noro' mount options.
480213365Smarcel			 */
481213365Smarcel			continue;
482213365Smarcel		}
483213365Smarcel		name_arg = strdup(name, M_MOUNT);
484213365Smarcel		val_arg = NULL;
485213365Smarcel		if (val != NULL)
486213365Smarcel			val_arg = strdup(val, M_MOUNT);
487213365Smarcel
488213365Smarcel		ma = mount_arg(ma, name_arg, val_arg,
489213365Smarcel		    (val_arg != NULL ? -1 : 0));
490213365Smarcel	}
491213365Smarcel	free(opts, M_MOUNT);
492213365Smarcel	return (ma);
493213365Smarcel}
494213365Smarcel
495213365Smarcel/*
496213365Smarcel * Mount (mountfrom) as the root filesystem.
497213365Smarcel */
498213365Smarcelstatic int
499213365Smarcelvfs_mountroot_try(const char *mountfrom, const char *options)
500213365Smarcel{
501213365Smarcel	struct mount	*mp;
502213365Smarcel	struct mntarg	*ma;
503213365Smarcel	char		*vfsname, *path;
504213365Smarcel	time_t		timebase;
505213365Smarcel	int		error;
506213365Smarcel	char		patt[32];
507213365Smarcel	char		errmsg[255];
508213365Smarcel
509213365Smarcel	vfsname = NULL;
510213365Smarcel	path    = NULL;
511213365Smarcel	mp      = NULL;
512213365Smarcel	ma	= NULL;
513213365Smarcel	error   = EINVAL;
514213365Smarcel	bzero(errmsg, sizeof(errmsg));
515213365Smarcel
516213365Smarcel	if (mountfrom == NULL)
517213365Smarcel		return (error);		/* don't complain */
518213365Smarcel	printf("Trying to mount root from %s\n", mountfrom);
519213365Smarcel
520213365Smarcel	/* parse vfs name and path */
521213365Smarcel	vfsname = malloc(MFSNAMELEN, M_MOUNT, M_WAITOK);
522213365Smarcel	path = malloc(MNAMELEN, M_MOUNT, M_WAITOK);
523213365Smarcel	vfsname[0] = path[0] = 0;
524213365Smarcel	sprintf(patt, "%%%d[a-z0-9]:%%%ds", MFSNAMELEN, MNAMELEN);
525213365Smarcel	if (sscanf(mountfrom, patt, vfsname, path) < 1)
526213365Smarcel		goto out;
527213365Smarcel
528213365Smarcel	if (path[0] == '\0')
529213365Smarcel		strcpy(path, ROOTNAME);
530213365Smarcel
531213365Smarcel	ma = mount_arg(ma, "fstype", vfsname, -1);
532213365Smarcel	ma = mount_arg(ma, "fspath", "/", -1);
533213365Smarcel	ma = mount_arg(ma, "from", path, -1);
534213365Smarcel	ma = mount_arg(ma, "errmsg", errmsg, sizeof(errmsg));
535213365Smarcel	ma = mount_arg(ma, "ro", NULL, 0);
536213365Smarcel	ma = parse_mountroot_options(ma, options);
537213365Smarcel	error = kernel_mount(ma, MNT_ROOTFS);
538213365Smarcel
539213365Smarcel	if (error == 0) {
540213365Smarcel		/*
541213365Smarcel		 * We mount devfs prior to mounting the / FS, so the first
542213365Smarcel		 * entry will typically be devfs.
543213365Smarcel		 */
544213365Smarcel		mp = TAILQ_FIRST(&mountlist);
545213365Smarcel		KASSERT(mp != NULL, ("%s: mountlist is empty", __func__));
546213365Smarcel
547213365Smarcel		/*
548213365Smarcel		 * Iterate over all currently mounted file systems and use
549213365Smarcel		 * the time stamp found to check and/or initialize the RTC.
550213365Smarcel		 * Typically devfs has no time stamp and the only other FS
551213365Smarcel		 * is the actual / FS.
552213365Smarcel		 * Call inittodr() only once and pass it the largest of the
553213365Smarcel		 * timestamps we encounter.
554213365Smarcel		 */
555213365Smarcel		timebase = 0;
556213365Smarcel		do {
557213365Smarcel			if (mp->mnt_time > timebase)
558213365Smarcel				timebase = mp->mnt_time;
559213365Smarcel			mp = TAILQ_NEXT(mp, mnt_list);
560213365Smarcel		} while (mp != NULL);
561213365Smarcel		inittodr(timebase);
562213365Smarcel
563213365Smarcel		devfs_fixup(curthread);
564213365Smarcel	}
565213365Smarcel
566213365Smarcel	if (error != 0 ) {
567213365Smarcel		printf("ROOT MOUNT ERROR: %s\n", errmsg);
568213365Smarcel		printf("If you have invalid mount options, reboot, and ");
569213365Smarcel		printf("first try the following from\n");
570213365Smarcel		printf("the loader prompt:\n\n");
571213365Smarcel		printf("     set vfs.root.mountfrom.options=rw\n\n");
572213365Smarcel		printf("and then remove invalid mount options from ");
573213365Smarcel		printf("/etc/fstab.\n\n");
574213365Smarcel	}
575213365Smarcelout:
576213365Smarcel	free(path, M_MOUNT);
577213365Smarcel	free(vfsname, M_MOUNT);
578213365Smarcel	return (error);
579213365Smarcel}
580213365Smarcel
581213365Smarcelstatic int
582213365Smarcelvfs_mountroot_ask(void)
583213365Smarcel{
584213365Smarcel	char name[128];
585213365Smarcel	char *mountfrom;
586213365Smarcel	char *options;
587213365Smarcel
588213365Smarcel	for(;;) {
589213365Smarcel		printf("Loader variables:\n");
590213365Smarcel		printf("vfs.root.mountfrom=");
591213365Smarcel		mountfrom = getenv("vfs.root.mountfrom");
592213365Smarcel		if (mountfrom != NULL) {
593213365Smarcel			printf("%s", mountfrom);
594213365Smarcel		}
595213365Smarcel		printf("\n");
596213365Smarcel		printf("vfs.root.mountfrom.options=");
597213365Smarcel		options = getenv("vfs.root.mountfrom.options");
598213365Smarcel		if (options != NULL) {
599213365Smarcel			printf("%s", options);
600213365Smarcel		}
601213365Smarcel		printf("\n");
602213365Smarcel		freeenv(mountfrom);
603213365Smarcel		freeenv(options);
604213365Smarcel		printf("\nManual root filesystem specification:\n");
605213365Smarcel		printf("  <fstype>:<device>  Mount <device> using filesystem <fstype>\n");
606213365Smarcel		printf("                       eg. zfs:tank\n");
607213365Smarcel		printf("                       eg. ufs:/dev/da0s1a\n");
608213365Smarcel		printf("                       eg. cd9660:/dev/acd0\n");
609213365Smarcel		printf("                       This is equivalent to: ");
610213365Smarcel		printf("mount -t cd9660 /dev/acd0 /\n");
611213365Smarcel		printf("\n");
612213365Smarcel		printf("  ?                  List valid disk boot devices\n");
613213365Smarcel		printf("  <empty line>       Abort manual input\n");
614213365Smarcel		printf("\nmountroot> ");
615213365Smarcel		gets(name, sizeof(name), 1);
616213365Smarcel		if (name[0] == '\0')
617213365Smarcel			return (1);
618213365Smarcel		if (name[0] == '?') {
619213365Smarcel			printf("\nList of GEOM managed disk devices:\n  ");
620213365Smarcel			g_dev_print();
621213365Smarcel			continue;
622213365Smarcel		}
623213365Smarcel		if (!vfs_mountroot_try(name, NULL))
624213365Smarcel			return (0);
625213365Smarcel	}
626213365Smarcel}
627