1 /*- 2 * Copyright (c) 1999 Michael Smith 3 * All rights reserved. 4 * Copyright (c) 1999 Poul-Henning Kamp 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: src/sys/kern/vfs_conf.c,v 1.49.2.5 2003/01/07 11:56:53 joerg Exp $ 29 * $DragonFly: src/sys/kern/vfs_conf.c,v 1.34 2008/05/24 19:08:28 dillon Exp $ 30 */ 31 32 /* 33 * Locate and mount the root filesystem. 34 * 35 * The root filesystem is detailed in the kernel environment variable 36 * vfs.root.mountfrom, which is expected to be in the general format 37 * 38 * <vfsname>:[<path>] 39 * vfsname := the name of a VFS known to the kernel and capable 40 * of being mounted as root 41 * path := disk device name or other data used by the filesystem 42 * to locate its physical store 43 * 44 */ 45 46 #include "opt_rootdevname.h" 47 48 #include <sys/param.h> 49 #include <sys/kernel.h> 50 #include <sys/systm.h> 51 #include <sys/proc.h> 52 #include <sys/vnode.h> 53 #include <sys/mount.h> 54 #include <sys/malloc.h> 55 #include <sys/reboot.h> 56 #include <sys/diskslice.h> 57 #include <sys/conf.h> 58 #include <sys/cons.h> 59 #include <sys/device.h> 60 #include <sys/disk.h> 61 #include <sys/namecache.h> 62 #include <sys/paths.h> 63 #include <sys/thread2.h> 64 #include <sys/nlookup.h> 65 #include <sys/devfs.h> 66 67 #include "opt_ddb.h" 68 #ifdef DDB 69 #include <ddb/ddb.h> 70 #endif 71 72 MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount structure"); 73 74 #define ROOTNAME "root_device" 75 76 struct vnode *rootvnode; 77 struct nchandle rootnch; 78 79 /* 80 * The root specifiers we will try if RB_CDROM is specified. Note that 81 * with DEVFS we do not use the compatibility slice's whole-disk 'c' 82 * partition. Instead we just use the whole disk, e.g. cd0 or cd0s0. 83 */ 84 static char *cdrom_rootdevnames[] = { 85 "cd9660:cd0", 86 "cd9660:acd0", 87 "cd9660:cd1", 88 "cd9660:acd1", 89 NULL 90 }; 91 92 int vfs_mountroot_devfs(void); 93 static void vfs_mountroot(void *junk); 94 static int vfs_mountroot_try(const char *mountfrom); 95 static int vfs_mountroot_ask(void); 96 static int getline(char *cp, int limit); 97 98 /* legacy find-root code */ 99 char *rootdevnames[2] = {NULL, NULL}; 100 static int setrootbyname(char *name); 101 102 SYSINIT(mountroot, SI_SUB_MOUNT_ROOT, SI_ORDER_SECOND, vfs_mountroot, NULL); 103 104 /* 105 * Find and mount the root filesystem 106 */ 107 static void 108 vfs_mountroot(void *junk) 109 { 110 int i; 111 cdev_t save_rootdev = rootdev; 112 113 /* 114 * Make sure all disk devices created so far have also been probed, 115 * and also make sure that the newly created device nodes for 116 * probed disks are ready, too. 117 * 118 * Messages can fly around here so get good synchronization 119 * coverage. 120 */ 121 sync_devs(); 122 123 /* 124 * The root filesystem information is compiled in, and we are 125 * booted with instructions to use it. 126 */ 127 #ifdef ROOTDEVNAME 128 if ((boothowto & RB_DFLTROOT) && 129 !vfs_mountroot_try(ROOTDEVNAME)) 130 return; 131 #endif 132 /* 133 * We are booted with instructions to prompt for the root filesystem, 134 * or to use the compiled-in default when it doesn't exist. 135 */ 136 if (boothowto & (RB_DFLTROOT | RB_ASKNAME)) { 137 if (!vfs_mountroot_ask()) 138 return; 139 } 140 141 /* 142 * We've been given the generic "use CDROM as root" flag. This is 143 * necessary because one media may be used in many different 144 * devices, so we need to search for them. 145 */ 146 if (boothowto & RB_CDROM) { 147 for (i = 0; cdrom_rootdevnames[i] != NULL; i++) { 148 if (!vfs_mountroot_try(cdrom_rootdevnames[i])) 149 return; 150 } 151 } 152 153 /* 154 * Try to use the value read by the loader from /etc/fstab, or 155 * supplied via some other means. This is the preferred 156 * mechanism. 157 */ 158 if (!vfs_mountroot_try(kgetenv("vfs.root.mountfrom"))) 159 return; 160 161 /* 162 * If a vfs set rootdev, try it (XXX VINUM HACK!) 163 */ 164 if (save_rootdev != NULL) { 165 rootdev = save_rootdev; 166 if (!vfs_mountroot_try("")) 167 return; 168 } 169 170 /* 171 * Try values that may have been computed by the machine-dependant 172 * legacy code. 173 */ 174 if (rootdevnames[0] && !vfs_mountroot_try(rootdevnames[0])) 175 return; 176 if (rootdevnames[1] && !vfs_mountroot_try(rootdevnames[1])) 177 return; 178 179 /* 180 * If we have a compiled-in default, and haven't already tried it, try 181 * it now. 182 */ 183 #ifdef ROOTDEVNAME 184 if (!(boothowto & RB_DFLTROOT)) 185 if (!vfs_mountroot_try(ROOTDEVNAME)) 186 return; 187 #endif 188 189 /* 190 * Everything so far has failed, prompt on the console if we haven't 191 * already tried that. 192 */ 193 if (!(boothowto & (RB_DFLTROOT | RB_ASKNAME)) && !vfs_mountroot_ask()) 194 return; 195 panic("Root mount failed, startup aborted."); 196 } 197 198 199 int 200 vfs_mountroot_devfs(void) 201 { 202 struct vnode *vp; 203 struct nchandle nch; 204 struct nlookupdata nd; 205 struct mount *mp; 206 struct vfsconf *vfsp; 207 int error; 208 struct ucred *cred = proc0.p_ucred; 209 210 /* 211 * Lookup the requested path and extract the nch and vnode. 212 */ 213 error = nlookup_init_raw(&nd, 214 "/dev", UIO_SYSSPACE, NLC_FOLLOW, 215 cred, &rootnch); 216 217 if (error == 0) { 218 devfs_debug(DEVFS_DEBUG_DEBUG, "vfs_mountroot_devfs: nlookup_init is ok...\n"); 219 if ((error = nlookup(&nd)) == 0) { 220 devfs_debug(DEVFS_DEBUG_DEBUG, "vfs_mountroot_devfs: nlookup is ok...\n"); 221 if (nd.nl_nch.ncp->nc_vp == NULL) { 222 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: nlookup: simply not found\n"); 223 error = ENOENT; 224 } 225 } 226 } 227 if (error) { 228 nlookup_done(&nd); 229 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: nlookup failed, error: %d\n", error); 230 return (error); 231 } 232 233 /* 234 * Extract the locked+refd ncp and cleanup the nd structure 235 */ 236 nch = nd.nl_nch; 237 cache_zero(&nd.nl_nch); 238 nlookup_done(&nd); 239 240 /* 241 * now we have the locked ref'd nch and unreferenced vnode. 242 */ 243 vp = nch.ncp->nc_vp; 244 if ((error = vget(vp, LK_EXCLUSIVE)) != 0) { 245 cache_put(&nch); 246 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vget failed\n"); 247 return (error); 248 } 249 cache_unlock(&nch); 250 251 if ((error = vinvalbuf(vp, V_SAVE, 0, 0)) != 0) { 252 cache_drop(&nch); 253 vput(vp); 254 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vinvalbuf failed\n"); 255 return (error); 256 } 257 if (vp->v_type != VDIR) { 258 cache_drop(&nch); 259 vput(vp); 260 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vp is not VDIR\n"); 261 return (ENOTDIR); 262 } 263 264 vfsp = vfsconf_find_by_name("devfs"); 265 vp->v_flag |= VMOUNT; 266 267 /* 268 * Allocate and initialize the filesystem. 269 */ 270 mp = kmalloc(sizeof(struct mount), M_MOUNT, M_ZERO|M_WAITOK); 271 TAILQ_INIT(&mp->mnt_nvnodelist); 272 TAILQ_INIT(&mp->mnt_reservedvnlist); 273 TAILQ_INIT(&mp->mnt_jlist); 274 mp->mnt_nvnodelistsize = 0; 275 lockinit(&mp->mnt_lock, "vfslock", 0, 0); 276 vfs_busy(mp, LK_NOWAIT); 277 mp->mnt_op = vfsp->vfc_vfsops; 278 mp->mnt_vfc = vfsp; 279 vfsp->vfc_refcount++; 280 mp->mnt_stat.f_type = vfsp->vfc_typenum; 281 mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; 282 strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); 283 mp->mnt_stat.f_owner = cred->cr_uid; 284 mp->mnt_iosize_max = DFLTPHYS; 285 vn_unlock(vp); 286 287 /* 288 * Mount the filesystem. 289 */ 290 error = VFS_MOUNT(mp, "/dev", NULL, cred); 291 292 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 293 294 /* 295 * Put the new filesystem on the mount list after root. The mount 296 * point gets its own mnt_ncmountpt (unless the VFS already set one 297 * up) which represents the root of the mount. The lookup code 298 * detects the mount point going forward and checks the root of 299 * the mount going backwards. 300 * 301 * It is not necessary to invalidate or purge the vnode underneath 302 * because elements under the mount will be given their own glue 303 * namecache record. 304 */ 305 if (!error) { 306 if (mp->mnt_ncmountpt.ncp == NULL) { 307 /* 308 * allocate, then unlock, but leave the ref intact 309 */ 310 cache_allocroot(&mp->mnt_ncmountpt, mp, NULL); 311 cache_unlock(&mp->mnt_ncmountpt); 312 } 313 mp->mnt_ncmounton = nch; /* inherits ref */ 314 nch.ncp->nc_flag |= NCF_ISMOUNTPT; 315 316 /* XXX get the root of the fs and cache_setvp(mnt_ncmountpt...) */ 317 vp->v_flag &= ~VMOUNT; 318 mountlist_insert(mp, MNTINS_LAST); 319 vn_unlock(vp); 320 //checkdirs(&mp->mnt_ncmounton, &mp->mnt_ncmountpt); 321 error = vfs_allocate_syncvnode(mp); 322 if (error) { 323 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vfs_allocate_syncvnode failed\n"); 324 } 325 vfs_unbusy(mp); 326 error = VFS_START(mp, 0); 327 vrele(vp); 328 } else { 329 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_coherency_ops); 330 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_journal_ops); 331 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_norm_ops); 332 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_spec_ops); 333 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_fifo_ops); 334 vp->v_flag &= ~VMOUNT; 335 mp->mnt_vfc->vfc_refcount--; 336 vfs_unbusy(mp); 337 kfree(mp, M_MOUNT); 338 cache_drop(&nch); 339 vput(vp); 340 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: mount failed\n"); 341 } 342 343 devfs_debug(DEVFS_DEBUG_DEBUG, "rootmount_devfs done with error: %d\n", error); 344 return (error); 345 } 346 347 348 /* 349 * Mount (mountfrom) as the root filesystem. 350 */ 351 static int 352 vfs_mountroot_try(const char *mountfrom) 353 { 354 struct mount *mp, *mp2; 355 char *vfsname, *devname; 356 int error; 357 char patt[32]; 358 359 vfsname = NULL; 360 devname = NULL; 361 mp = NULL; 362 mp2 = NULL; 363 error = EINVAL; 364 365 if (mountfrom == NULL) 366 return(error); /* don't complain */ 367 368 crit_enter(); 369 kprintf("Mounting root from %s\n", mountfrom); 370 crit_exit(); 371 372 /* parse vfs name and devname */ 373 vfsname = kmalloc(MFSNAMELEN, M_MOUNT, M_WAITOK); 374 devname = kmalloc(MNAMELEN, M_MOUNT, M_WAITOK); 375 vfsname[0] = devname[0] = 0; 376 ksprintf(patt, "%%%d[a-z0-9]:%%%ds", MFSNAMELEN, MNAMELEN); 377 if (ksscanf(mountfrom, patt, vfsname, devname) < 1) 378 goto done; 379 380 /* allocate a root mount */ 381 error = vfs_rootmountalloc(vfsname, 382 devname[0] != 0 ? devname : ROOTNAME, &mp); 383 if (error != 0) { 384 kprintf("Can't allocate root mount for filesystem '%s': %d\n", 385 vfsname, error); 386 goto done; 387 } 388 mp->mnt_flag |= MNT_ROOTFS; 389 390 /* do our best to set rootdev */ 391 if ((devname[0] != 0) && setrootbyname(devname)) 392 kprintf("setrootbyname failed\n"); 393 394 /* If the root device is a type "memory disk", mount RW */ 395 if (rootdev != NULL && dev_is_good(rootdev) && 396 (dev_dflags(rootdev) & D_MEMDISK)) { 397 mp->mnt_flag &= ~MNT_RDONLY; 398 } 399 400 error = VFS_MOUNT(mp, NULL, NULL, proc0.p_ucred); 401 402 if (!error) { 403 //kprintf("Trying vfs_mountroot_devfs!\n"); 404 //vfs_mountroot_devfs(); 405 } 406 407 done: 408 if (vfsname != NULL) 409 kfree(vfsname, M_MOUNT); 410 if (devname != NULL) 411 kfree(devname, M_MOUNT); 412 if (error == 0) { 413 /* register with list of mounted filesystems */ 414 mountlist_insert(mp, MNTINS_FIRST); 415 416 /* sanity check system clock against root fs timestamp */ 417 inittodr(mp->mnt_time); 418 vfs_unbusy(mp); 419 if (mp->mnt_syncer == NULL) { 420 error = vfs_allocate_syncvnode(mp); 421 if (error) 422 kprintf("Warning: no syncer vp for root!\n"); 423 error = 0; 424 } 425 } else { 426 if (mp != NULL) { 427 vfs_unbusy(mp); 428 kfree(mp, M_MOUNT); 429 } 430 kprintf("Root mount failed: %d\n", error); 431 } 432 return(error); 433 } 434 435 436 static void vfs_mountroot_ask_callback(cdev_t); 437 438 /* 439 * Spin prompting on the console for a suitable root filesystem 440 */ 441 442 static int 443 vfs_mountroot_ask(void) 444 { 445 char name[128]; 446 int llimit = 100; 447 448 kprintf("\nManual root filesystem specification:\n"); 449 kprintf(" <fstype>:<device> Specify root (e.g. ufs:da0s1a)\n"); 450 kprintf(" ? List valid disk boot devices\n"); 451 kprintf(" panic Just panic\n"); 452 kprintf(" abort Abort manual input\n"); 453 while (llimit--) { 454 kprintf("\nmountroot> "); 455 456 if (getline(name, 128) < 0) 457 break; 458 if (name[0] == 0) { 459 ; 460 } else if (name[0] == '?') { 461 kprintf("Possibly valid devices for root FS:\n"); 462 //enumerate all disk devices 463 devfs_scan_callback(vfs_mountroot_ask_callback); 464 kprintf("\n"); 465 continue; 466 } else if (strcmp(name, "panic") == 0) { 467 panic("panic from console"); 468 } else if (strcmp(name, "abort") == 0) { 469 break; 470 } else if (vfs_mountroot_try(name) == 0) { 471 return(0); 472 } 473 } 474 return(1); 475 } 476 477 478 static void 479 vfs_mountroot_ask_callback(cdev_t dev) 480 { 481 if (dev_is_good(dev) && (dev_dflags(dev) & D_DISK)) 482 kprintf(" \"%s\" ", dev->si_name); 483 } 484 485 486 static int 487 getline(char *cp, int limit) 488 { 489 char *lp; 490 int c; 491 492 lp = cp; 493 for (;;) { 494 c = cngetc(); 495 496 switch (c) { 497 case -1: 498 return(-1); 499 case '\n': 500 case '\r': 501 kprintf("\n"); 502 *lp++ = '\0'; 503 return(0); 504 case '\b': 505 case '\177': 506 if (lp > cp) { 507 kprintf("\b \b"); 508 lp--; 509 } else { 510 kprintf("%c", 7); 511 } 512 continue; 513 case '#': 514 kprintf("#"); 515 lp--; 516 if (lp < cp) 517 lp = cp; 518 continue; 519 case '@': 520 case 'u' & 037: 521 lp = cp; 522 kprintf("%c", '\n'); 523 continue; 524 default: 525 if (lp - cp >= limit - 1) { 526 kprintf("%c", 7); 527 } else { 528 kprintf("%c", c); 529 *lp++ = c; 530 } 531 continue; 532 } 533 } 534 } 535 536 /* 537 * Convert a given name to the cdev_t of the disk-like device 538 * it refers to. 539 */ 540 struct kdbn_info { 541 const char *name; 542 int nlen; 543 int minor; 544 cdev_t dev; 545 }; 546 547 548 cdev_t 549 kgetdiskbyname(const char *name) 550 { 551 char *cp; 552 cdev_t rdev; 553 554 /* 555 * Get the base name of the device 556 */ 557 if (strncmp(name, __SYS_PATH_DEV, sizeof(__SYS_PATH_DEV) - 1) == 0) 558 name += sizeof(__SYS_PATH_DEV) - 1; 559 cp = __DECONST(char *, name); 560 561 /* 562 * Locate the device 563 */ 564 kprintf("tryroot %s\n", name); 565 rdev = devfs_find_device_by_name(name); 566 if (rdev == NULL) { 567 kprintf("no disk named '%s'\n", name); 568 } 569 /* 570 * FOUND DEVICE 571 */ 572 return(rdev); 573 } 574 575 /* 576 * Set rootdev to match (name), given that we expect it to 577 * refer to a disk-like device. 578 */ 579 static int 580 setrootbyname(char *name) 581 { 582 cdev_t diskdev; 583 584 diskdev = kgetdiskbyname(name); 585 if (diskdev != NULL) { 586 rootdev = diskdev; 587 return (0); 588 } 589 /* set to NULL if kgetdiskbyname() fails so that if the first rootdev is 590 * found by fails to mount and the second one isn't found, mountroot_try 591 * doesn't try again with the first one 592 */ 593 rootdev = NULL; 594 return (1); 595 } 596 597 #ifdef DDB 598 DB_SHOW_COMMAND(disk, db_getdiskbyname) 599 { 600 cdev_t dev; 601 602 if (modif[0] == '\0') { 603 db_error("usage: show disk/devicename"); 604 return; 605 } 606 dev = kgetdiskbyname(modif); 607 if (dev != NULL) 608 db_printf("cdev_t = %p\n", dev); 609 else 610 db_printf("No disk device matched.\n"); 611 } 612 #endif 613