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