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