xref: /freebsd/sys/kern/vfs_mountroot.c (revision 24e01f5998ce6b26b55d632eff0ca33ad60c72f1)
1*24e01f59SMarcel Moolenaar /*-
2*24e01f59SMarcel Moolenaar  * Copyright (c) 1999-2004 Poul-Henning Kamp
3*24e01f59SMarcel Moolenaar  * Copyright (c) 1999 Michael Smith
4*24e01f59SMarcel Moolenaar  * Copyright (c) 1989, 1993
5*24e01f59SMarcel Moolenaar  *      The Regents of the University of California.  All rights reserved.
6*24e01f59SMarcel Moolenaar  * (c) UNIX System Laboratories, Inc.
7*24e01f59SMarcel Moolenaar  * All or some portions of this file are derived from material licensed
8*24e01f59SMarcel Moolenaar  * to the University of California by American Telephone and Telegraph
9*24e01f59SMarcel Moolenaar  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10*24e01f59SMarcel Moolenaar  * the permission of UNIX System Laboratories, Inc.
11*24e01f59SMarcel Moolenaar  *
12*24e01f59SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
13*24e01f59SMarcel Moolenaar  * modification, are permitted provided that the following conditions
14*24e01f59SMarcel Moolenaar  * are met:
15*24e01f59SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
16*24e01f59SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
17*24e01f59SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
18*24e01f59SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
19*24e01f59SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
20*24e01f59SMarcel Moolenaar  * 4. Neither the name of the University nor the names of its contributors
21*24e01f59SMarcel Moolenaar  *    may be used to endorse or promote products derived from this software
22*24e01f59SMarcel Moolenaar  *    without specific prior written permission.
23*24e01f59SMarcel Moolenaar  *
24*24e01f59SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25*24e01f59SMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26*24e01f59SMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27*24e01f59SMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28*24e01f59SMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29*24e01f59SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30*24e01f59SMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31*24e01f59SMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32*24e01f59SMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33*24e01f59SMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34*24e01f59SMarcel Moolenaar  * SUCH DAMAGE.
35*24e01f59SMarcel Moolenaar  */
36*24e01f59SMarcel Moolenaar 
37*24e01f59SMarcel Moolenaar #include <sys/cdefs.h>
38*24e01f59SMarcel Moolenaar __FBSDID("$FreeBSD$");
39*24e01f59SMarcel Moolenaar 
40*24e01f59SMarcel Moolenaar #include <sys/param.h>
41*24e01f59SMarcel Moolenaar #include <sys/conf.h>
42*24e01f59SMarcel Moolenaar #include <sys/fcntl.h>
43*24e01f59SMarcel Moolenaar #include <sys/jail.h>
44*24e01f59SMarcel Moolenaar #include <sys/kernel.h>
45*24e01f59SMarcel Moolenaar #include <sys/libkern.h>
46*24e01f59SMarcel Moolenaar #include <sys/malloc.h>
47*24e01f59SMarcel Moolenaar #include <sys/mount.h>
48*24e01f59SMarcel Moolenaar #include <sys/mutex.h>
49*24e01f59SMarcel Moolenaar #include <sys/namei.h>
50*24e01f59SMarcel Moolenaar #include <sys/priv.h>
51*24e01f59SMarcel Moolenaar #include <sys/proc.h>
52*24e01f59SMarcel Moolenaar #include <sys/filedesc.h>
53*24e01f59SMarcel Moolenaar #include <sys/reboot.h>
54*24e01f59SMarcel Moolenaar #include <sys/syscallsubr.h>
55*24e01f59SMarcel Moolenaar #include <sys/sysproto.h>
56*24e01f59SMarcel Moolenaar #include <sys/sx.h>
57*24e01f59SMarcel Moolenaar #include <sys/sysctl.h>
58*24e01f59SMarcel Moolenaar #include <sys/sysent.h>
59*24e01f59SMarcel Moolenaar #include <sys/systm.h>
60*24e01f59SMarcel Moolenaar #include <sys/vnode.h>
61*24e01f59SMarcel Moolenaar #include <vm/uma.h>
62*24e01f59SMarcel Moolenaar 
63*24e01f59SMarcel Moolenaar #include <geom/geom.h>
64*24e01f59SMarcel Moolenaar 
65*24e01f59SMarcel Moolenaar #include <machine/stdarg.h>
66*24e01f59SMarcel Moolenaar 
67*24e01f59SMarcel Moolenaar #include "opt_rootdevname.h"
68*24e01f59SMarcel Moolenaar 
69*24e01f59SMarcel Moolenaar #define	ROOTNAME		"root_device"
70*24e01f59SMarcel Moolenaar 
71*24e01f59SMarcel Moolenaar static int	vfs_mountroot_ask(void);
72*24e01f59SMarcel Moolenaar static int	vfs_mountroot_try(const char *mountfrom, const char *options);
73*24e01f59SMarcel Moolenaar 
74*24e01f59SMarcel Moolenaar /*
75*24e01f59SMarcel Moolenaar  * The vnode of the system's root (/ in the filesystem, without chroot
76*24e01f59SMarcel Moolenaar  * active.)
77*24e01f59SMarcel Moolenaar  */
78*24e01f59SMarcel Moolenaar struct vnode	*rootvnode;
79*24e01f59SMarcel Moolenaar 
80*24e01f59SMarcel Moolenaar /*
81*24e01f59SMarcel Moolenaar  * The root filesystem is detailed in the kernel environment variable
82*24e01f59SMarcel Moolenaar  * vfs.root.mountfrom, which is expected to be in the general format
83*24e01f59SMarcel Moolenaar  *
84*24e01f59SMarcel Moolenaar  * <vfsname>:[<path>][	<vfsname>:[<path>] ...]
85*24e01f59SMarcel Moolenaar  * vfsname   := the name of a VFS known to the kernel and capable
86*24e01f59SMarcel Moolenaar  *              of being mounted as root
87*24e01f59SMarcel Moolenaar  * path      := disk device name or other data used by the filesystem
88*24e01f59SMarcel Moolenaar  *              to locate its physical store
89*24e01f59SMarcel Moolenaar  *
90*24e01f59SMarcel Moolenaar  * If the environment variable vfs.root.mountfrom is a space separated list,
91*24e01f59SMarcel Moolenaar  * each list element is tried in turn and the root filesystem will be mounted
92*24e01f59SMarcel Moolenaar  * from the first one that suceeds.
93*24e01f59SMarcel Moolenaar  *
94*24e01f59SMarcel Moolenaar  * The environment variable vfs.root.mountfrom.options is a comma delimited
95*24e01f59SMarcel Moolenaar  * set of string mount options.  These mount options must be parseable
96*24e01f59SMarcel Moolenaar  * by nmount() in the kernel.
97*24e01f59SMarcel Moolenaar  */
98*24e01f59SMarcel Moolenaar 
99*24e01f59SMarcel Moolenaar /*
100*24e01f59SMarcel Moolenaar  * The root specifiers we will try if RB_CDROM is specified.
101*24e01f59SMarcel Moolenaar  */
102*24e01f59SMarcel Moolenaar static char *cdrom_rootdevnames[] = {
103*24e01f59SMarcel Moolenaar 	"cd9660:cd0",
104*24e01f59SMarcel Moolenaar 	"cd9660:acd0",
105*24e01f59SMarcel Moolenaar 	NULL
106*24e01f59SMarcel Moolenaar };
107*24e01f59SMarcel Moolenaar 
108*24e01f59SMarcel Moolenaar /* legacy find-root code */
109*24e01f59SMarcel Moolenaar char		*rootdevnames[2] = {NULL, NULL};
110*24e01f59SMarcel Moolenaar #ifndef ROOTDEVNAME
111*24e01f59SMarcel Moolenaar #  define ROOTDEVNAME NULL
112*24e01f59SMarcel Moolenaar #endif
113*24e01f59SMarcel Moolenaar static const char	*ctrootdevname = ROOTDEVNAME;
114*24e01f59SMarcel Moolenaar 
115*24e01f59SMarcel Moolenaar struct root_hold_token {
116*24e01f59SMarcel Moolenaar 	const char			*who;
117*24e01f59SMarcel Moolenaar 	LIST_ENTRY(root_hold_token)	list;
118*24e01f59SMarcel Moolenaar };
119*24e01f59SMarcel Moolenaar 
120*24e01f59SMarcel Moolenaar static LIST_HEAD(, root_hold_token)	root_holds =
121*24e01f59SMarcel Moolenaar     LIST_HEAD_INITIALIZER(root_holds);
122*24e01f59SMarcel Moolenaar 
123*24e01f59SMarcel Moolenaar static int root_mount_complete;
124*24e01f59SMarcel Moolenaar 
125*24e01f59SMarcel Moolenaar struct root_hold_token *
126*24e01f59SMarcel Moolenaar root_mount_hold(const char *identifier)
127*24e01f59SMarcel Moolenaar {
128*24e01f59SMarcel Moolenaar 	struct root_hold_token *h;
129*24e01f59SMarcel Moolenaar 
130*24e01f59SMarcel Moolenaar 	if (root_mounted())
131*24e01f59SMarcel Moolenaar 		return (NULL);
132*24e01f59SMarcel Moolenaar 
133*24e01f59SMarcel Moolenaar 	h = malloc(sizeof *h, M_DEVBUF, M_ZERO | M_WAITOK);
134*24e01f59SMarcel Moolenaar 	h->who = identifier;
135*24e01f59SMarcel Moolenaar 	mtx_lock(&mountlist_mtx);
136*24e01f59SMarcel Moolenaar 	LIST_INSERT_HEAD(&root_holds, h, list);
137*24e01f59SMarcel Moolenaar 	mtx_unlock(&mountlist_mtx);
138*24e01f59SMarcel Moolenaar 	return (h);
139*24e01f59SMarcel Moolenaar }
140*24e01f59SMarcel Moolenaar 
141*24e01f59SMarcel Moolenaar void
142*24e01f59SMarcel Moolenaar root_mount_rel(struct root_hold_token *h)
143*24e01f59SMarcel Moolenaar {
144*24e01f59SMarcel Moolenaar 
145*24e01f59SMarcel Moolenaar 	if (h == NULL)
146*24e01f59SMarcel Moolenaar 		return;
147*24e01f59SMarcel Moolenaar 	mtx_lock(&mountlist_mtx);
148*24e01f59SMarcel Moolenaar 	LIST_REMOVE(h, list);
149*24e01f59SMarcel Moolenaar 	wakeup(&root_holds);
150*24e01f59SMarcel Moolenaar 	mtx_unlock(&mountlist_mtx);
151*24e01f59SMarcel Moolenaar 	free(h, M_DEVBUF);
152*24e01f59SMarcel Moolenaar }
153*24e01f59SMarcel Moolenaar 
154*24e01f59SMarcel Moolenaar static void
155*24e01f59SMarcel Moolenaar root_mount_prepare(void)
156*24e01f59SMarcel Moolenaar {
157*24e01f59SMarcel Moolenaar 	struct root_hold_token *h;
158*24e01f59SMarcel Moolenaar 	struct timeval lastfail;
159*24e01f59SMarcel Moolenaar 	int curfail = 0;
160*24e01f59SMarcel Moolenaar 
161*24e01f59SMarcel Moolenaar 	for (;;) {
162*24e01f59SMarcel Moolenaar 		DROP_GIANT();
163*24e01f59SMarcel Moolenaar 		g_waitidle();
164*24e01f59SMarcel Moolenaar 		PICKUP_GIANT();
165*24e01f59SMarcel Moolenaar 		mtx_lock(&mountlist_mtx);
166*24e01f59SMarcel Moolenaar 		if (LIST_EMPTY(&root_holds)) {
167*24e01f59SMarcel Moolenaar 			mtx_unlock(&mountlist_mtx);
168*24e01f59SMarcel Moolenaar 			break;
169*24e01f59SMarcel Moolenaar 		}
170*24e01f59SMarcel Moolenaar 		if (ppsratecheck(&lastfail, &curfail, 1)) {
171*24e01f59SMarcel Moolenaar 			printf("Root mount waiting for:");
172*24e01f59SMarcel Moolenaar 			LIST_FOREACH(h, &root_holds, list)
173*24e01f59SMarcel Moolenaar 				printf(" %s", h->who);
174*24e01f59SMarcel Moolenaar 			printf("\n");
175*24e01f59SMarcel Moolenaar 		}
176*24e01f59SMarcel Moolenaar 		msleep(&root_holds, &mountlist_mtx, PZERO | PDROP, "roothold",
177*24e01f59SMarcel Moolenaar 		    hz);
178*24e01f59SMarcel Moolenaar 	}
179*24e01f59SMarcel Moolenaar }
180*24e01f59SMarcel Moolenaar 
181*24e01f59SMarcel Moolenaar static void
182*24e01f59SMarcel Moolenaar root_mount_done(void)
183*24e01f59SMarcel Moolenaar {
184*24e01f59SMarcel Moolenaar 
185*24e01f59SMarcel Moolenaar 	/* Keep prison0's root in sync with the global rootvnode. */
186*24e01f59SMarcel Moolenaar 	mtx_lock(&prison0.pr_mtx);
187*24e01f59SMarcel Moolenaar 	prison0.pr_root = rootvnode;
188*24e01f59SMarcel Moolenaar 	vref(prison0.pr_root);
189*24e01f59SMarcel Moolenaar 	mtx_unlock(&prison0.pr_mtx);
190*24e01f59SMarcel Moolenaar 	/*
191*24e01f59SMarcel Moolenaar 	 * Use a mutex to prevent the wakeup being missed and waiting for
192*24e01f59SMarcel Moolenaar 	 * an extra 1 second sleep.
193*24e01f59SMarcel Moolenaar 	 */
194*24e01f59SMarcel Moolenaar 	mtx_lock(&mountlist_mtx);
195*24e01f59SMarcel Moolenaar 	root_mount_complete = 1;
196*24e01f59SMarcel Moolenaar 	wakeup(&root_mount_complete);
197*24e01f59SMarcel Moolenaar 	mtx_unlock(&mountlist_mtx);
198*24e01f59SMarcel Moolenaar }
199*24e01f59SMarcel Moolenaar 
200*24e01f59SMarcel Moolenaar int
201*24e01f59SMarcel Moolenaar root_mounted(void)
202*24e01f59SMarcel Moolenaar {
203*24e01f59SMarcel Moolenaar 
204*24e01f59SMarcel Moolenaar 	/* No mutex is acquired here because int stores are atomic. */
205*24e01f59SMarcel Moolenaar 	return (root_mount_complete);
206*24e01f59SMarcel Moolenaar }
207*24e01f59SMarcel Moolenaar 
208*24e01f59SMarcel Moolenaar void
209*24e01f59SMarcel Moolenaar root_mount_wait(void)
210*24e01f59SMarcel Moolenaar {
211*24e01f59SMarcel Moolenaar 
212*24e01f59SMarcel Moolenaar 	/*
213*24e01f59SMarcel Moolenaar 	 * Panic on an obvious deadlock - the function can't be called from
214*24e01f59SMarcel Moolenaar 	 * a thread which is doing the whole SYSINIT stuff.
215*24e01f59SMarcel Moolenaar 	 */
216*24e01f59SMarcel Moolenaar 	KASSERT(curthread->td_proc->p_pid != 0,
217*24e01f59SMarcel Moolenaar 	    ("root_mount_wait: cannot be called from the swapper thread"));
218*24e01f59SMarcel Moolenaar 	mtx_lock(&mountlist_mtx);
219*24e01f59SMarcel Moolenaar 	while (!root_mount_complete) {
220*24e01f59SMarcel Moolenaar 		msleep(&root_mount_complete, &mountlist_mtx, PZERO, "rootwait",
221*24e01f59SMarcel Moolenaar 		    hz);
222*24e01f59SMarcel Moolenaar 	}
223*24e01f59SMarcel Moolenaar 	mtx_unlock(&mountlist_mtx);
224*24e01f59SMarcel Moolenaar }
225*24e01f59SMarcel Moolenaar 
226*24e01f59SMarcel Moolenaar static void
227*24e01f59SMarcel Moolenaar set_rootvnode(void)
228*24e01f59SMarcel Moolenaar {
229*24e01f59SMarcel Moolenaar 	struct proc *p;
230*24e01f59SMarcel Moolenaar 
231*24e01f59SMarcel Moolenaar 	if (VFS_ROOT(TAILQ_FIRST(&mountlist), LK_EXCLUSIVE, &rootvnode))
232*24e01f59SMarcel Moolenaar 		panic("Cannot find root vnode");
233*24e01f59SMarcel Moolenaar 
234*24e01f59SMarcel Moolenaar 	VOP_UNLOCK(rootvnode, 0);
235*24e01f59SMarcel Moolenaar 
236*24e01f59SMarcel Moolenaar 	p = curthread->td_proc;
237*24e01f59SMarcel Moolenaar 	FILEDESC_XLOCK(p->p_fd);
238*24e01f59SMarcel Moolenaar 
239*24e01f59SMarcel Moolenaar 	if (p->p_fd->fd_cdir != NULL)
240*24e01f59SMarcel Moolenaar 		vrele(p->p_fd->fd_cdir);
241*24e01f59SMarcel Moolenaar 	p->p_fd->fd_cdir = rootvnode;
242*24e01f59SMarcel Moolenaar 	VREF(rootvnode);
243*24e01f59SMarcel Moolenaar 
244*24e01f59SMarcel Moolenaar 	if (p->p_fd->fd_rdir != NULL)
245*24e01f59SMarcel Moolenaar 		vrele(p->p_fd->fd_rdir);
246*24e01f59SMarcel Moolenaar 	p->p_fd->fd_rdir = rootvnode;
247*24e01f59SMarcel Moolenaar 	VREF(rootvnode);
248*24e01f59SMarcel Moolenaar 
249*24e01f59SMarcel Moolenaar 	FILEDESC_XUNLOCK(p->p_fd);
250*24e01f59SMarcel Moolenaar 
251*24e01f59SMarcel Moolenaar 	EVENTHANDLER_INVOKE(mountroot);
252*24e01f59SMarcel Moolenaar }
253*24e01f59SMarcel Moolenaar 
254*24e01f59SMarcel Moolenaar static void
255*24e01f59SMarcel Moolenaar devfs_first(void)
256*24e01f59SMarcel Moolenaar {
257*24e01f59SMarcel Moolenaar 	struct thread *td = curthread;
258*24e01f59SMarcel Moolenaar 	struct vfsoptlist *opts;
259*24e01f59SMarcel Moolenaar 	struct vfsconf *vfsp;
260*24e01f59SMarcel Moolenaar 	struct mount *mp = NULL;
261*24e01f59SMarcel Moolenaar 	int error;
262*24e01f59SMarcel Moolenaar 
263*24e01f59SMarcel Moolenaar 	vfsp = vfs_byname("devfs");
264*24e01f59SMarcel Moolenaar 	KASSERT(vfsp != NULL, ("Could not find devfs by name"));
265*24e01f59SMarcel Moolenaar 	if (vfsp == NULL)
266*24e01f59SMarcel Moolenaar 		return;
267*24e01f59SMarcel Moolenaar 
268*24e01f59SMarcel Moolenaar 	mp = vfs_mount_alloc(NULLVP, vfsp, "/dev", td->td_ucred);
269*24e01f59SMarcel Moolenaar 
270*24e01f59SMarcel Moolenaar 	error = VFS_MOUNT(mp);
271*24e01f59SMarcel Moolenaar 	KASSERT(error == 0, ("VFS_MOUNT(devfs) failed %d", error));
272*24e01f59SMarcel Moolenaar 	if (error)
273*24e01f59SMarcel Moolenaar 		return;
274*24e01f59SMarcel Moolenaar 
275*24e01f59SMarcel Moolenaar 	opts = malloc(sizeof(struct vfsoptlist), M_MOUNT, M_WAITOK);
276*24e01f59SMarcel Moolenaar 	TAILQ_INIT(opts);
277*24e01f59SMarcel Moolenaar 	mp->mnt_opt = opts;
278*24e01f59SMarcel Moolenaar 
279*24e01f59SMarcel Moolenaar 	mtx_lock(&mountlist_mtx);
280*24e01f59SMarcel Moolenaar 	TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list);
281*24e01f59SMarcel Moolenaar 	mtx_unlock(&mountlist_mtx);
282*24e01f59SMarcel Moolenaar 
283*24e01f59SMarcel Moolenaar 	set_rootvnode();
284*24e01f59SMarcel Moolenaar 
285*24e01f59SMarcel Moolenaar 	error = kern_symlink(td, "/", "dev", UIO_SYSSPACE);
286*24e01f59SMarcel Moolenaar 	if (error)
287*24e01f59SMarcel Moolenaar 		printf("kern_symlink /dev -> / returns %d\n", error);
288*24e01f59SMarcel Moolenaar }
289*24e01f59SMarcel Moolenaar 
290*24e01f59SMarcel Moolenaar static void
291*24e01f59SMarcel Moolenaar devfs_fixup(struct thread *td)
292*24e01f59SMarcel Moolenaar {
293*24e01f59SMarcel Moolenaar 	struct nameidata nd;
294*24e01f59SMarcel Moolenaar 	struct vnode *vp, *dvp;
295*24e01f59SMarcel Moolenaar 	struct mount *mp;
296*24e01f59SMarcel Moolenaar 	int error;
297*24e01f59SMarcel Moolenaar 
298*24e01f59SMarcel Moolenaar 	/* Remove our devfs mount from the mountlist and purge the cache */
299*24e01f59SMarcel Moolenaar 	mtx_lock(&mountlist_mtx);
300*24e01f59SMarcel Moolenaar 	mp = TAILQ_FIRST(&mountlist);
301*24e01f59SMarcel Moolenaar 	TAILQ_REMOVE(&mountlist, mp, mnt_list);
302*24e01f59SMarcel Moolenaar 	mtx_unlock(&mountlist_mtx);
303*24e01f59SMarcel Moolenaar 	cache_purgevfs(mp);
304*24e01f59SMarcel Moolenaar 
305*24e01f59SMarcel Moolenaar 	VFS_ROOT(mp, LK_EXCLUSIVE, &dvp);
306*24e01f59SMarcel Moolenaar 	VI_LOCK(dvp);
307*24e01f59SMarcel Moolenaar 	dvp->v_iflag &= ~VI_MOUNT;
308*24e01f59SMarcel Moolenaar 	VI_UNLOCK(dvp);
309*24e01f59SMarcel Moolenaar 	dvp->v_mountedhere = NULL;
310*24e01f59SMarcel Moolenaar 
311*24e01f59SMarcel Moolenaar 	/* Set up the real rootvnode, and purge the cache */
312*24e01f59SMarcel Moolenaar 	TAILQ_FIRST(&mountlist)->mnt_vnodecovered = NULL;
313*24e01f59SMarcel Moolenaar 	set_rootvnode();
314*24e01f59SMarcel Moolenaar 	cache_purgevfs(rootvnode->v_mount);
315*24e01f59SMarcel Moolenaar 
316*24e01f59SMarcel Moolenaar 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, "/dev", td);
317*24e01f59SMarcel Moolenaar 	error = namei(&nd);
318*24e01f59SMarcel Moolenaar 	if (error) {
319*24e01f59SMarcel Moolenaar 		printf("Lookup of /dev for devfs, error: %d\n", error);
320*24e01f59SMarcel Moolenaar 		vput(dvp);
321*24e01f59SMarcel Moolenaar 		vfs_unbusy(mp);
322*24e01f59SMarcel Moolenaar 		return;
323*24e01f59SMarcel Moolenaar 	}
324*24e01f59SMarcel Moolenaar 	NDFREE(&nd, NDF_ONLY_PNBUF);
325*24e01f59SMarcel Moolenaar 	vp = nd.ni_vp;
326*24e01f59SMarcel Moolenaar 	if (vp->v_type != VDIR) {
327*24e01f59SMarcel Moolenaar 		printf("/dev is not a directory\n");
328*24e01f59SMarcel Moolenaar 		vput(dvp);
329*24e01f59SMarcel Moolenaar 		vput(vp);
330*24e01f59SMarcel Moolenaar 		vfs_unbusy(mp);
331*24e01f59SMarcel Moolenaar 		return;
332*24e01f59SMarcel Moolenaar 	}
333*24e01f59SMarcel Moolenaar 	error = vinvalbuf(vp, V_SAVE, 0, 0);
334*24e01f59SMarcel Moolenaar 	if (error) {
335*24e01f59SMarcel Moolenaar 		printf("vinvalbuf() of /dev failed, error: %d\n", error);
336*24e01f59SMarcel Moolenaar 		vput(dvp);
337*24e01f59SMarcel Moolenaar 		vput(vp);
338*24e01f59SMarcel Moolenaar 		vfs_unbusy(mp);
339*24e01f59SMarcel Moolenaar 		return;
340*24e01f59SMarcel Moolenaar 	}
341*24e01f59SMarcel Moolenaar 	cache_purge(vp);
342*24e01f59SMarcel Moolenaar 	mp->mnt_vnodecovered = vp;
343*24e01f59SMarcel Moolenaar 	vp->v_mountedhere = mp;
344*24e01f59SMarcel Moolenaar 	mtx_lock(&mountlist_mtx);
345*24e01f59SMarcel Moolenaar 	TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
346*24e01f59SMarcel Moolenaar 	mtx_unlock(&mountlist_mtx);
347*24e01f59SMarcel Moolenaar 	VOP_UNLOCK(vp, 0);
348*24e01f59SMarcel Moolenaar 	vput(dvp);
349*24e01f59SMarcel Moolenaar 	vfs_unbusy(mp);
350*24e01f59SMarcel Moolenaar 
351*24e01f59SMarcel Moolenaar 	/* Unlink the no longer needed /dev/dev -> / symlink */
352*24e01f59SMarcel Moolenaar 	error = kern_unlink(td, "/dev/dev", UIO_SYSSPACE);
353*24e01f59SMarcel Moolenaar 	if (error)
354*24e01f59SMarcel Moolenaar 		printf("kern_unlink of /dev/dev failed, error: %d\n", error);
355*24e01f59SMarcel Moolenaar }
356*24e01f59SMarcel Moolenaar 
357*24e01f59SMarcel Moolenaar void
358*24e01f59SMarcel Moolenaar vfs_mountroot(void)
359*24e01f59SMarcel Moolenaar {
360*24e01f59SMarcel Moolenaar 	char *cp, *cpt, *options, *tmpdev;
361*24e01f59SMarcel Moolenaar 	int error, i, asked = 0;
362*24e01f59SMarcel Moolenaar 
363*24e01f59SMarcel Moolenaar 	options = NULL;
364*24e01f59SMarcel Moolenaar 
365*24e01f59SMarcel Moolenaar 	root_mount_prepare();
366*24e01f59SMarcel Moolenaar 
367*24e01f59SMarcel Moolenaar 	devfs_first();
368*24e01f59SMarcel Moolenaar 
369*24e01f59SMarcel Moolenaar 	/*
370*24e01f59SMarcel Moolenaar 	 * We are booted with instructions to prompt for the root filesystem.
371*24e01f59SMarcel Moolenaar 	 */
372*24e01f59SMarcel Moolenaar 	if (boothowto & RB_ASKNAME) {
373*24e01f59SMarcel Moolenaar 		if (!vfs_mountroot_ask())
374*24e01f59SMarcel Moolenaar 			goto mounted;
375*24e01f59SMarcel Moolenaar 		asked = 1;
376*24e01f59SMarcel Moolenaar 	}
377*24e01f59SMarcel Moolenaar 
378*24e01f59SMarcel Moolenaar 	options = getenv("vfs.root.mountfrom.options");
379*24e01f59SMarcel Moolenaar 
380*24e01f59SMarcel Moolenaar 	/*
381*24e01f59SMarcel Moolenaar 	 * The root filesystem information is compiled in, and we are
382*24e01f59SMarcel Moolenaar 	 * booted with instructions to use it.
383*24e01f59SMarcel Moolenaar 	 */
384*24e01f59SMarcel Moolenaar 	if (ctrootdevname != NULL && (boothowto & RB_DFLTROOT)) {
385*24e01f59SMarcel Moolenaar 		if (!vfs_mountroot_try(ctrootdevname, options))
386*24e01f59SMarcel Moolenaar 			goto mounted;
387*24e01f59SMarcel Moolenaar 		ctrootdevname = NULL;
388*24e01f59SMarcel Moolenaar 	}
389*24e01f59SMarcel Moolenaar 
390*24e01f59SMarcel Moolenaar 	/*
391*24e01f59SMarcel Moolenaar 	 * We've been given the generic "use CDROM as root" flag.  This is
392*24e01f59SMarcel Moolenaar 	 * necessary because one media may be used in many different
393*24e01f59SMarcel Moolenaar 	 * devices, so we need to search for them.
394*24e01f59SMarcel Moolenaar 	 */
395*24e01f59SMarcel Moolenaar 	if (boothowto & RB_CDROM) {
396*24e01f59SMarcel Moolenaar 		for (i = 0; cdrom_rootdevnames[i] != NULL; i++) {
397*24e01f59SMarcel Moolenaar 			if (!vfs_mountroot_try(cdrom_rootdevnames[i], options))
398*24e01f59SMarcel Moolenaar 				goto mounted;
399*24e01f59SMarcel Moolenaar 		}
400*24e01f59SMarcel Moolenaar 	}
401*24e01f59SMarcel Moolenaar 
402*24e01f59SMarcel Moolenaar 	/*
403*24e01f59SMarcel Moolenaar 	 * Try to use the value read by the loader from /etc/fstab, or
404*24e01f59SMarcel Moolenaar 	 * supplied via some other means.  This is the preferred
405*24e01f59SMarcel Moolenaar 	 * mechanism.
406*24e01f59SMarcel Moolenaar 	 */
407*24e01f59SMarcel Moolenaar 	cp = getenv("vfs.root.mountfrom");
408*24e01f59SMarcel Moolenaar 	if (cp != NULL) {
409*24e01f59SMarcel Moolenaar 		cpt = cp;
410*24e01f59SMarcel Moolenaar 		while ((tmpdev = strsep(&cpt, " \t")) != NULL) {
411*24e01f59SMarcel Moolenaar 			error = vfs_mountroot_try(tmpdev, options);
412*24e01f59SMarcel Moolenaar 			if (error == 0) {
413*24e01f59SMarcel Moolenaar 				freeenv(cp);
414*24e01f59SMarcel Moolenaar 				goto mounted;
415*24e01f59SMarcel Moolenaar 			}
416*24e01f59SMarcel Moolenaar 		}
417*24e01f59SMarcel Moolenaar 		freeenv(cp);
418*24e01f59SMarcel Moolenaar 	}
419*24e01f59SMarcel Moolenaar 
420*24e01f59SMarcel Moolenaar 	/*
421*24e01f59SMarcel Moolenaar 	 * Try values that may have been computed by code during boot
422*24e01f59SMarcel Moolenaar 	 */
423*24e01f59SMarcel Moolenaar 	if (!vfs_mountroot_try(rootdevnames[0], options))
424*24e01f59SMarcel Moolenaar 		goto mounted;
425*24e01f59SMarcel Moolenaar 	if (!vfs_mountroot_try(rootdevnames[1], options))
426*24e01f59SMarcel Moolenaar 		goto mounted;
427*24e01f59SMarcel Moolenaar 
428*24e01f59SMarcel Moolenaar 	/*
429*24e01f59SMarcel Moolenaar 	 * If we (still) have a compiled-in default, try it.
430*24e01f59SMarcel Moolenaar 	 */
431*24e01f59SMarcel Moolenaar 	if (ctrootdevname != NULL)
432*24e01f59SMarcel Moolenaar 		if (!vfs_mountroot_try(ctrootdevname, options))
433*24e01f59SMarcel Moolenaar 			goto mounted;
434*24e01f59SMarcel Moolenaar 	/*
435*24e01f59SMarcel Moolenaar 	 * Everything so far has failed, prompt on the console if we haven't
436*24e01f59SMarcel Moolenaar 	 * already tried that.
437*24e01f59SMarcel Moolenaar 	 */
438*24e01f59SMarcel Moolenaar 	if (!asked)
439*24e01f59SMarcel Moolenaar 		if (!vfs_mountroot_ask())
440*24e01f59SMarcel Moolenaar 			goto mounted;
441*24e01f59SMarcel Moolenaar 
442*24e01f59SMarcel Moolenaar 	panic("Root mount failed, startup aborted.");
443*24e01f59SMarcel Moolenaar 
444*24e01f59SMarcel Moolenaar mounted:
445*24e01f59SMarcel Moolenaar 	root_mount_done();
446*24e01f59SMarcel Moolenaar 	freeenv(options);
447*24e01f59SMarcel Moolenaar }
448*24e01f59SMarcel Moolenaar 
449*24e01f59SMarcel Moolenaar static struct mntarg *
450*24e01f59SMarcel Moolenaar parse_mountroot_options(struct mntarg *ma, const char *options)
451*24e01f59SMarcel Moolenaar {
452*24e01f59SMarcel Moolenaar 	char *p;
453*24e01f59SMarcel Moolenaar 	char *name, *name_arg;
454*24e01f59SMarcel Moolenaar 	char *val, *val_arg;
455*24e01f59SMarcel Moolenaar 	char *opts;
456*24e01f59SMarcel Moolenaar 
457*24e01f59SMarcel Moolenaar 	if (options == NULL || options[0] == '\0')
458*24e01f59SMarcel Moolenaar 		return (ma);
459*24e01f59SMarcel Moolenaar 
460*24e01f59SMarcel Moolenaar 	p = opts = strdup(options, M_MOUNT);
461*24e01f59SMarcel Moolenaar 	if (opts == NULL) {
462*24e01f59SMarcel Moolenaar 		return (ma);
463*24e01f59SMarcel Moolenaar 	}
464*24e01f59SMarcel Moolenaar 
465*24e01f59SMarcel Moolenaar 	while((name = strsep(&p, ",")) != NULL) {
466*24e01f59SMarcel Moolenaar 		if (name[0] == '\0')
467*24e01f59SMarcel Moolenaar 			break;
468*24e01f59SMarcel Moolenaar 
469*24e01f59SMarcel Moolenaar 		val = strchr(name, '=');
470*24e01f59SMarcel Moolenaar 		if (val != NULL) {
471*24e01f59SMarcel Moolenaar 			*val = '\0';
472*24e01f59SMarcel Moolenaar 			++val;
473*24e01f59SMarcel Moolenaar 		}
474*24e01f59SMarcel Moolenaar 		if( strcmp(name, "rw") == 0 ||
475*24e01f59SMarcel Moolenaar 		    strcmp(name, "noro") == 0) {
476*24e01f59SMarcel Moolenaar 			/*
477*24e01f59SMarcel Moolenaar 			 * The first time we mount the root file system,
478*24e01f59SMarcel Moolenaar 			 * we need to mount 'ro', so We need to ignore
479*24e01f59SMarcel Moolenaar 			 * 'rw' and 'noro' mount options.
480*24e01f59SMarcel Moolenaar 			 */
481*24e01f59SMarcel Moolenaar 			continue;
482*24e01f59SMarcel Moolenaar 		}
483*24e01f59SMarcel Moolenaar 		name_arg = strdup(name, M_MOUNT);
484*24e01f59SMarcel Moolenaar 		val_arg = NULL;
485*24e01f59SMarcel Moolenaar 		if (val != NULL)
486*24e01f59SMarcel Moolenaar 			val_arg = strdup(val, M_MOUNT);
487*24e01f59SMarcel Moolenaar 
488*24e01f59SMarcel Moolenaar 		ma = mount_arg(ma, name_arg, val_arg,
489*24e01f59SMarcel Moolenaar 		    (val_arg != NULL ? -1 : 0));
490*24e01f59SMarcel Moolenaar 	}
491*24e01f59SMarcel Moolenaar 	free(opts, M_MOUNT);
492*24e01f59SMarcel Moolenaar 	return (ma);
493*24e01f59SMarcel Moolenaar }
494*24e01f59SMarcel Moolenaar 
495*24e01f59SMarcel Moolenaar /*
496*24e01f59SMarcel Moolenaar  * Mount (mountfrom) as the root filesystem.
497*24e01f59SMarcel Moolenaar  */
498*24e01f59SMarcel Moolenaar static int
499*24e01f59SMarcel Moolenaar vfs_mountroot_try(const char *mountfrom, const char *options)
500*24e01f59SMarcel Moolenaar {
501*24e01f59SMarcel Moolenaar 	struct mount	*mp;
502*24e01f59SMarcel Moolenaar 	struct mntarg	*ma;
503*24e01f59SMarcel Moolenaar 	char		*vfsname, *path;
504*24e01f59SMarcel Moolenaar 	time_t		timebase;
505*24e01f59SMarcel Moolenaar 	int		error;
506*24e01f59SMarcel Moolenaar 	char		patt[32];
507*24e01f59SMarcel Moolenaar 	char		errmsg[255];
508*24e01f59SMarcel Moolenaar 
509*24e01f59SMarcel Moolenaar 	vfsname = NULL;
510*24e01f59SMarcel Moolenaar 	path    = NULL;
511*24e01f59SMarcel Moolenaar 	mp      = NULL;
512*24e01f59SMarcel Moolenaar 	ma	= NULL;
513*24e01f59SMarcel Moolenaar 	error   = EINVAL;
514*24e01f59SMarcel Moolenaar 	bzero(errmsg, sizeof(errmsg));
515*24e01f59SMarcel Moolenaar 
516*24e01f59SMarcel Moolenaar 	if (mountfrom == NULL)
517*24e01f59SMarcel Moolenaar 		return (error);		/* don't complain */
518*24e01f59SMarcel Moolenaar 	printf("Trying to mount root from %s\n", mountfrom);
519*24e01f59SMarcel Moolenaar 
520*24e01f59SMarcel Moolenaar 	/* parse vfs name and path */
521*24e01f59SMarcel Moolenaar 	vfsname = malloc(MFSNAMELEN, M_MOUNT, M_WAITOK);
522*24e01f59SMarcel Moolenaar 	path = malloc(MNAMELEN, M_MOUNT, M_WAITOK);
523*24e01f59SMarcel Moolenaar 	vfsname[0] = path[0] = 0;
524*24e01f59SMarcel Moolenaar 	sprintf(patt, "%%%d[a-z0-9]:%%%ds", MFSNAMELEN, MNAMELEN);
525*24e01f59SMarcel Moolenaar 	if (sscanf(mountfrom, patt, vfsname, path) < 1)
526*24e01f59SMarcel Moolenaar 		goto out;
527*24e01f59SMarcel Moolenaar 
528*24e01f59SMarcel Moolenaar 	if (path[0] == '\0')
529*24e01f59SMarcel Moolenaar 		strcpy(path, ROOTNAME);
530*24e01f59SMarcel Moolenaar 
531*24e01f59SMarcel Moolenaar 	ma = mount_arg(ma, "fstype", vfsname, -1);
532*24e01f59SMarcel Moolenaar 	ma = mount_arg(ma, "fspath", "/", -1);
533*24e01f59SMarcel Moolenaar 	ma = mount_arg(ma, "from", path, -1);
534*24e01f59SMarcel Moolenaar 	ma = mount_arg(ma, "errmsg", errmsg, sizeof(errmsg));
535*24e01f59SMarcel Moolenaar 	ma = mount_arg(ma, "ro", NULL, 0);
536*24e01f59SMarcel Moolenaar 	ma = parse_mountroot_options(ma, options);
537*24e01f59SMarcel Moolenaar 	error = kernel_mount(ma, MNT_ROOTFS);
538*24e01f59SMarcel Moolenaar 
539*24e01f59SMarcel Moolenaar 	if (error == 0) {
540*24e01f59SMarcel Moolenaar 		/*
541*24e01f59SMarcel Moolenaar 		 * We mount devfs prior to mounting the / FS, so the first
542*24e01f59SMarcel Moolenaar 		 * entry will typically be devfs.
543*24e01f59SMarcel Moolenaar 		 */
544*24e01f59SMarcel Moolenaar 		mp = TAILQ_FIRST(&mountlist);
545*24e01f59SMarcel Moolenaar 		KASSERT(mp != NULL, ("%s: mountlist is empty", __func__));
546*24e01f59SMarcel Moolenaar 
547*24e01f59SMarcel Moolenaar 		/*
548*24e01f59SMarcel Moolenaar 		 * Iterate over all currently mounted file systems and use
549*24e01f59SMarcel Moolenaar 		 * the time stamp found to check and/or initialize the RTC.
550*24e01f59SMarcel Moolenaar 		 * Typically devfs has no time stamp and the only other FS
551*24e01f59SMarcel Moolenaar 		 * is the actual / FS.
552*24e01f59SMarcel Moolenaar 		 * Call inittodr() only once and pass it the largest of the
553*24e01f59SMarcel Moolenaar 		 * timestamps we encounter.
554*24e01f59SMarcel Moolenaar 		 */
555*24e01f59SMarcel Moolenaar 		timebase = 0;
556*24e01f59SMarcel Moolenaar 		do {
557*24e01f59SMarcel Moolenaar 			if (mp->mnt_time > timebase)
558*24e01f59SMarcel Moolenaar 				timebase = mp->mnt_time;
559*24e01f59SMarcel Moolenaar 			mp = TAILQ_NEXT(mp, mnt_list);
560*24e01f59SMarcel Moolenaar 		} while (mp != NULL);
561*24e01f59SMarcel Moolenaar 		inittodr(timebase);
562*24e01f59SMarcel Moolenaar 
563*24e01f59SMarcel Moolenaar 		devfs_fixup(curthread);
564*24e01f59SMarcel Moolenaar 	}
565*24e01f59SMarcel Moolenaar 
566*24e01f59SMarcel Moolenaar 	if (error != 0 ) {
567*24e01f59SMarcel Moolenaar 		printf("ROOT MOUNT ERROR: %s\n", errmsg);
568*24e01f59SMarcel Moolenaar 		printf("If you have invalid mount options, reboot, and ");
569*24e01f59SMarcel Moolenaar 		printf("first try the following from\n");
570*24e01f59SMarcel Moolenaar 		printf("the loader prompt:\n\n");
571*24e01f59SMarcel Moolenaar 		printf("     set vfs.root.mountfrom.options=rw\n\n");
572*24e01f59SMarcel Moolenaar 		printf("and then remove invalid mount options from ");
573*24e01f59SMarcel Moolenaar 		printf("/etc/fstab.\n\n");
574*24e01f59SMarcel Moolenaar 	}
575*24e01f59SMarcel Moolenaar out:
576*24e01f59SMarcel Moolenaar 	free(path, M_MOUNT);
577*24e01f59SMarcel Moolenaar 	free(vfsname, M_MOUNT);
578*24e01f59SMarcel Moolenaar 	return (error);
579*24e01f59SMarcel Moolenaar }
580*24e01f59SMarcel Moolenaar 
581*24e01f59SMarcel Moolenaar static int
582*24e01f59SMarcel Moolenaar vfs_mountroot_ask(void)
583*24e01f59SMarcel Moolenaar {
584*24e01f59SMarcel Moolenaar 	char name[128];
585*24e01f59SMarcel Moolenaar 	char *mountfrom;
586*24e01f59SMarcel Moolenaar 	char *options;
587*24e01f59SMarcel Moolenaar 
588*24e01f59SMarcel Moolenaar 	for(;;) {
589*24e01f59SMarcel Moolenaar 		printf("Loader variables:\n");
590*24e01f59SMarcel Moolenaar 		printf("vfs.root.mountfrom=");
591*24e01f59SMarcel Moolenaar 		mountfrom = getenv("vfs.root.mountfrom");
592*24e01f59SMarcel Moolenaar 		if (mountfrom != NULL) {
593*24e01f59SMarcel Moolenaar 			printf("%s", mountfrom);
594*24e01f59SMarcel Moolenaar 		}
595*24e01f59SMarcel Moolenaar 		printf("\n");
596*24e01f59SMarcel Moolenaar 		printf("vfs.root.mountfrom.options=");
597*24e01f59SMarcel Moolenaar 		options = getenv("vfs.root.mountfrom.options");
598*24e01f59SMarcel Moolenaar 		if (options != NULL) {
599*24e01f59SMarcel Moolenaar 			printf("%s", options);
600*24e01f59SMarcel Moolenaar 		}
601*24e01f59SMarcel Moolenaar 		printf("\n");
602*24e01f59SMarcel Moolenaar 		freeenv(mountfrom);
603*24e01f59SMarcel Moolenaar 		freeenv(options);
604*24e01f59SMarcel Moolenaar 		printf("\nManual root filesystem specification:\n");
605*24e01f59SMarcel Moolenaar 		printf("  <fstype>:<device>  Mount <device> using filesystem <fstype>\n");
606*24e01f59SMarcel Moolenaar 		printf("                       eg. zfs:tank\n");
607*24e01f59SMarcel Moolenaar 		printf("                       eg. ufs:/dev/da0s1a\n");
608*24e01f59SMarcel Moolenaar 		printf("                       eg. cd9660:/dev/acd0\n");
609*24e01f59SMarcel Moolenaar 		printf("                       This is equivalent to: ");
610*24e01f59SMarcel Moolenaar 		printf("mount -t cd9660 /dev/acd0 /\n");
611*24e01f59SMarcel Moolenaar 		printf("\n");
612*24e01f59SMarcel Moolenaar 		printf("  ?                  List valid disk boot devices\n");
613*24e01f59SMarcel Moolenaar 		printf("  <empty line>       Abort manual input\n");
614*24e01f59SMarcel Moolenaar 		printf("\nmountroot> ");
615*24e01f59SMarcel Moolenaar 		gets(name, sizeof(name), 1);
616*24e01f59SMarcel Moolenaar 		if (name[0] == '\0')
617*24e01f59SMarcel Moolenaar 			return (1);
618*24e01f59SMarcel Moolenaar 		if (name[0] == '?') {
619*24e01f59SMarcel Moolenaar 			printf("\nList of GEOM managed disk devices:\n  ");
620*24e01f59SMarcel Moolenaar 			g_dev_print();
621*24e01f59SMarcel Moolenaar 			continue;
622*24e01f59SMarcel Moolenaar 		}
623*24e01f59SMarcel Moolenaar 		if (!vfs_mountroot_try(name, NULL))
624*24e01f59SMarcel Moolenaar 			return (0);
625*24e01f59SMarcel Moolenaar 	}
626*24e01f59SMarcel Moolenaar }
627