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", /* SCSI (including AHCI and SILI) */ 86 "cd9660:acd0", /* NATA */ 87 "cd9660:cd1", /* SCSI (including AHCI and SILI) */ 88 "cd9660:acd1", /* NATA */ 89 "cd9660:cd8", /* USB */ 90 "cd9660:cd9", /* USB */ 91 NULL 92 }; 93 94 int vfs_mountroot_devfs(void); 95 static void vfs_mountroot(void *junk); 96 static int vfs_mountroot_try(const char *mountfrom); 97 static int vfs_mountroot_ask(void); 98 static int getline(char *cp, int limit); 99 100 /* legacy find-root code */ 101 char *rootdevnames[2] = {NULL, NULL}; 102 static int setrootbyname(char *name); 103 104 SYSINIT(mountroot, SI_SUB_MOUNT_ROOT, SI_ORDER_SECOND, vfs_mountroot, NULL); 105 106 /* 107 * Find and mount the root filesystem 108 */ 109 static void 110 vfs_mountroot(void *junk) 111 { 112 int i; 113 cdev_t save_rootdev = rootdev; 114 115 /* 116 * Make sure all disk devices created so far have also been probed, 117 * and also make sure that the newly created device nodes for 118 * probed disks are ready, too. 119 * 120 * Messages can fly around here so get good synchronization 121 * coverage. 122 */ 123 sync_devs(); 124 125 /* 126 * The root filesystem information is compiled in, and we are 127 * booted with instructions to use it. 128 */ 129 #ifdef ROOTDEVNAME 130 if ((boothowto & RB_DFLTROOT) && 131 !vfs_mountroot_try(ROOTDEVNAME)) 132 return; 133 #endif 134 /* 135 * We are booted with instructions to prompt for the root filesystem, 136 * or to use the compiled-in default when it doesn't exist. 137 */ 138 if (boothowto & (RB_DFLTROOT | RB_ASKNAME)) { 139 if (!vfs_mountroot_ask()) 140 return; 141 } 142 143 /* 144 * We've been given the generic "use CDROM as root" flag. This is 145 * necessary because one media may be used in many different 146 * devices, so we need to search for them. 147 */ 148 if (boothowto & RB_CDROM) { 149 for (i = 0; cdrom_rootdevnames[i] != NULL; i++) { 150 if (!vfs_mountroot_try(cdrom_rootdevnames[i])) 151 return; 152 } 153 } 154 155 /* 156 * Try to use the value read by the loader from /etc/fstab, or 157 * supplied via some other means. This is the preferred 158 * mechanism. 159 */ 160 if (!vfs_mountroot_try(kgetenv("vfs.root.mountfrom"))) 161 return; 162 163 /* 164 * If a vfs set rootdev, try it (XXX VINUM HACK!) 165 */ 166 if (save_rootdev != NULL) { 167 rootdev = save_rootdev; 168 if (!vfs_mountroot_try("")) 169 return; 170 } 171 172 /* 173 * Try values that may have been computed by the machine-dependant 174 * legacy code. 175 */ 176 if (rootdevnames[0] && !vfs_mountroot_try(rootdevnames[0])) 177 return; 178 if (rootdevnames[1] && !vfs_mountroot_try(rootdevnames[1])) 179 return; 180 181 /* 182 * If we have a compiled-in default, and haven't already tried it, try 183 * it now. 184 */ 185 #ifdef ROOTDEVNAME 186 if (!(boothowto & RB_DFLTROOT)) 187 if (!vfs_mountroot_try(ROOTDEVNAME)) 188 return; 189 #endif 190 191 /* 192 * Everything so far has failed, prompt on the console if we haven't 193 * already tried that. 194 */ 195 if (!(boothowto & (RB_DFLTROOT | RB_ASKNAME)) && !vfs_mountroot_ask()) 196 return; 197 panic("Root mount failed, startup aborted."); 198 } 199 200 201 int 202 vfs_mountroot_devfs(void) 203 { 204 struct vnode *vp; 205 struct nchandle nch; 206 struct nlookupdata nd; 207 struct mount *mp; 208 struct vfsconf *vfsp; 209 int error; 210 struct ucred *cred = proc0.p_ucred; 211 212 /* 213 * Lookup the requested path and extract the nch and vnode. 214 */ 215 error = nlookup_init_raw(&nd, 216 "/dev", UIO_SYSSPACE, NLC_FOLLOW, 217 cred, &rootnch); 218 219 if (error == 0) { 220 devfs_debug(DEVFS_DEBUG_DEBUG, "vfs_mountroot_devfs: nlookup_init is ok...\n"); 221 if ((error = nlookup(&nd)) == 0) { 222 devfs_debug(DEVFS_DEBUG_DEBUG, "vfs_mountroot_devfs: nlookup is ok...\n"); 223 if (nd.nl_nch.ncp->nc_vp == NULL) { 224 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: nlookup: simply not found\n"); 225 error = ENOENT; 226 } 227 } 228 } 229 if (error) { 230 nlookup_done(&nd); 231 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: nlookup failed, error: %d\n", error); 232 return (error); 233 } 234 235 /* 236 * Extract the locked+refd ncp and cleanup the nd structure 237 */ 238 nch = nd.nl_nch; 239 cache_zero(&nd.nl_nch); 240 nlookup_done(&nd); 241 242 /* 243 * now we have the locked ref'd nch and unreferenced vnode. 244 */ 245 vp = nch.ncp->nc_vp; 246 if ((error = vget(vp, LK_EXCLUSIVE)) != 0) { 247 cache_put(&nch); 248 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vget failed\n"); 249 return (error); 250 } 251 cache_unlock(&nch); 252 253 if ((error = vinvalbuf(vp, V_SAVE, 0, 0)) != 0) { 254 cache_drop(&nch); 255 vput(vp); 256 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vinvalbuf failed\n"); 257 return (error); 258 } 259 if (vp->v_type != VDIR) { 260 cache_drop(&nch); 261 vput(vp); 262 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vp is not VDIR\n"); 263 return (ENOTDIR); 264 } 265 266 vfsp = vfsconf_find_by_name("devfs"); 267 vp->v_flag |= VMOUNT; 268 269 /* 270 * Allocate and initialize the filesystem. 271 */ 272 mp = kmalloc(sizeof(struct mount), M_MOUNT, M_ZERO|M_WAITOK); 273 TAILQ_INIT(&mp->mnt_nvnodelist); 274 TAILQ_INIT(&mp->mnt_reservedvnlist); 275 TAILQ_INIT(&mp->mnt_jlist); 276 mp->mnt_nvnodelistsize = 0; 277 lockinit(&mp->mnt_lock, "vfslock", 0, 0); 278 vfs_busy(mp, LK_NOWAIT); 279 mp->mnt_op = vfsp->vfc_vfsops; 280 mp->mnt_vfc = vfsp; 281 vfsp->vfc_refcount++; 282 mp->mnt_stat.f_type = vfsp->vfc_typenum; 283 mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; 284 strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); 285 mp->mnt_stat.f_owner = cred->cr_uid; 286 mp->mnt_iosize_max = DFLTPHYS; 287 vn_unlock(vp); 288 289 /* 290 * Mount the filesystem. 291 */ 292 error = VFS_MOUNT(mp, "/dev", NULL, cred); 293 294 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 295 296 /* 297 * Put the new filesystem on the mount list after root. The mount 298 * point gets its own mnt_ncmountpt (unless the VFS already set one 299 * up) which represents the root of the mount. The lookup code 300 * detects the mount point going forward and checks the root of 301 * the mount going backwards. 302 * 303 * It is not necessary to invalidate or purge the vnode underneath 304 * because elements under the mount will be given their own glue 305 * namecache record. 306 */ 307 if (!error) { 308 if (mp->mnt_ncmountpt.ncp == NULL) { 309 /* 310 * allocate, then unlock, but leave the ref intact 311 */ 312 cache_allocroot(&mp->mnt_ncmountpt, mp, NULL); 313 cache_unlock(&mp->mnt_ncmountpt); 314 } 315 mp->mnt_ncmounton = nch; /* inherits ref */ 316 nch.ncp->nc_flag |= NCF_ISMOUNTPT; 317 318 /* XXX get the root of the fs and cache_setvp(mnt_ncmountpt...) */ 319 vp->v_flag &= ~VMOUNT; 320 mountlist_insert(mp, MNTINS_LAST); 321 vn_unlock(vp); 322 //checkdirs(&mp->mnt_ncmounton, &mp->mnt_ncmountpt); 323 error = vfs_allocate_syncvnode(mp); 324 if (error) { 325 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: vfs_allocate_syncvnode failed\n"); 326 } 327 vfs_unbusy(mp); 328 error = VFS_START(mp, 0); 329 vrele(vp); 330 } else { 331 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_coherency_ops); 332 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_journal_ops); 333 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_norm_ops); 334 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_spec_ops); 335 vfs_rm_vnodeops(mp, NULL, &mp->mnt_vn_fifo_ops); 336 vp->v_flag &= ~VMOUNT; 337 mp->mnt_vfc->vfc_refcount--; 338 vfs_unbusy(mp); 339 kfree(mp, M_MOUNT); 340 cache_drop(&nch); 341 vput(vp); 342 devfs_debug(DEVFS_DEBUG_SHOW, "vfs_mountroot_devfs: mount failed\n"); 343 } 344 345 devfs_debug(DEVFS_DEBUG_DEBUG, "rootmount_devfs done with error: %d\n", error); 346 return (error); 347 } 348 349 350 /* 351 * Mount (mountfrom) as the root filesystem. 352 */ 353 static int 354 vfs_mountroot_try(const char *mountfrom) 355 { 356 struct mount *mp, *mp2; 357 char *vfsname, *devname; 358 int error; 359 char patt[32]; 360 361 vfsname = NULL; 362 devname = NULL; 363 mp = NULL; 364 mp2 = NULL; 365 error = EINVAL; 366 367 if (mountfrom == NULL) 368 return(error); /* don't complain */ 369 370 crit_enter(); 371 kprintf("Mounting root from %s\n", mountfrom); 372 crit_exit(); 373 374 /* parse vfs name and devname */ 375 vfsname = kmalloc(MFSNAMELEN, M_MOUNT, M_WAITOK); 376 devname = kmalloc(MNAMELEN, M_MOUNT, M_WAITOK); 377 vfsname[0] = devname[0] = 0; 378 ksprintf(patt, "%%%d[a-z0-9]:%%%ds", MFSNAMELEN, MNAMELEN); 379 if (ksscanf(mountfrom, patt, vfsname, devname) < 1) 380 goto done; 381 382 /* allocate a root mount */ 383 error = vfs_rootmountalloc(vfsname, 384 devname[0] != 0 ? devname : ROOTNAME, &mp); 385 if (error != 0) { 386 kprintf("Can't allocate root mount for filesystem '%s': %d\n", 387 vfsname, error); 388 goto done; 389 } 390 mp->mnt_flag |= MNT_ROOTFS; 391 392 /* do our best to set rootdev */ 393 if ((devname[0] != 0) && setrootbyname(devname)) 394 kprintf("setrootbyname failed\n"); 395 396 /* If the root device is a type "memory disk", mount RW */ 397 if (rootdev != NULL && dev_is_good(rootdev) && 398 (dev_dflags(rootdev) & D_MEMDISK)) { 399 mp->mnt_flag &= ~MNT_RDONLY; 400 } 401 402 error = VFS_MOUNT(mp, NULL, NULL, proc0.p_ucred); 403 404 if (!error) { 405 //kprintf("Trying vfs_mountroot_devfs!\n"); 406 //vfs_mountroot_devfs(); 407 } 408 409 done: 410 if (vfsname != NULL) 411 kfree(vfsname, M_MOUNT); 412 if (devname != NULL) 413 kfree(devname, M_MOUNT); 414 if (error == 0) { 415 /* register with list of mounted filesystems */ 416 mountlist_insert(mp, MNTINS_FIRST); 417 418 /* sanity check system clock against root fs timestamp */ 419 inittodr(mp->mnt_time); 420 vfs_unbusy(mp); 421 if (mp->mnt_syncer == NULL) { 422 error = vfs_allocate_syncvnode(mp); 423 if (error) 424 kprintf("Warning: no syncer vp for root!\n"); 425 error = 0; 426 } 427 } else { 428 if (mp != NULL) { 429 vfs_unbusy(mp); 430 kfree(mp, M_MOUNT); 431 } 432 kprintf("Root mount failed: %d\n", error); 433 } 434 return(error); 435 } 436 437 438 static void vfs_mountroot_ask_callback(cdev_t); 439 440 /* 441 * Spin prompting on the console for a suitable root filesystem 442 */ 443 444 static int 445 vfs_mountroot_ask(void) 446 { 447 char name[128]; 448 int llimit = 100; 449 450 kprintf("\nManual root filesystem specification:\n"); 451 kprintf(" <fstype>:<device> Specify root (e.g. ufs:da0s1a)\n"); 452 kprintf(" ? List valid disk boot devices\n"); 453 kprintf(" panic Just panic\n"); 454 kprintf(" abort Abort manual input\n"); 455 while (llimit--) { 456 kprintf("\nmountroot> "); 457 458 if (getline(name, 128) < 0) 459 break; 460 if (name[0] == 0) { 461 ; 462 } else if (name[0] == '?') { 463 kprintf("Possibly valid devices for root FS:\n"); 464 //enumerate all disk devices 465 devfs_scan_callback(vfs_mountroot_ask_callback); 466 kprintf("\n"); 467 continue; 468 } else if (strcmp(name, "panic") == 0) { 469 panic("panic from console"); 470 } else if (strcmp(name, "abort") == 0) { 471 break; 472 } else if (vfs_mountroot_try(name) == 0) { 473 return(0); 474 } 475 } 476 return(1); 477 } 478 479 480 static void 481 vfs_mountroot_ask_callback(cdev_t dev) 482 { 483 if (dev_is_good(dev) && (dev_dflags(dev) & D_DISK)) 484 kprintf(" \"%s\" ", dev->si_name); 485 } 486 487 488 static int 489 getline(char *cp, int limit) 490 { 491 char *lp; 492 int c; 493 494 lp = cp; 495 for (;;) { 496 c = cngetc(); 497 498 switch (c) { 499 case -1: 500 return(-1); 501 case '\n': 502 case '\r': 503 kprintf("\n"); 504 *lp++ = '\0'; 505 return(0); 506 case '\b': 507 case '\177': 508 if (lp > cp) { 509 kprintf("\b \b"); 510 lp--; 511 } else { 512 kprintf("%c", 7); 513 } 514 continue; 515 case '#': 516 kprintf("#"); 517 lp--; 518 if (lp < cp) 519 lp = cp; 520 continue; 521 case '@': 522 case 'u' & 037: 523 lp = cp; 524 kprintf("%c", '\n'); 525 continue; 526 default: 527 if (lp - cp >= limit - 1) { 528 kprintf("%c", 7); 529 } else { 530 kprintf("%c", c); 531 *lp++ = c; 532 } 533 continue; 534 } 535 } 536 } 537 538 /* 539 * Convert a given name to the cdev_t of the disk-like device 540 * it refers to. 541 */ 542 struct kdbn_info { 543 const char *name; 544 int nlen; 545 int minor; 546 cdev_t dev; 547 }; 548 549 550 cdev_t 551 kgetdiskbyname(const char *name) 552 { 553 char *cp; 554 cdev_t rdev; 555 556 /* 557 * Get the base name of the device 558 */ 559 if (strncmp(name, __SYS_PATH_DEV, sizeof(__SYS_PATH_DEV) - 1) == 0) 560 name += sizeof(__SYS_PATH_DEV) - 1; 561 cp = __DECONST(char *, name); 562 563 /* 564 * Locate the device 565 */ 566 kprintf("tryroot %s\n", name); 567 rdev = devfs_find_device_by_name(name); 568 if (rdev == NULL) { 569 kprintf("no disk named '%s'\n", name); 570 } 571 /* 572 * FOUND DEVICE 573 */ 574 return(rdev); 575 } 576 577 /* 578 * Set rootdev to match (name), given that we expect it to 579 * refer to a disk-like device. 580 */ 581 static int 582 setrootbyname(char *name) 583 { 584 cdev_t diskdev; 585 586 diskdev = kgetdiskbyname(name); 587 if (diskdev != NULL) { 588 rootdev = diskdev; 589 return (0); 590 } 591 /* set to NULL if kgetdiskbyname() fails so that if the first rootdev is 592 * found by fails to mount and the second one isn't found, mountroot_try 593 * doesn't try again with the first one 594 */ 595 rootdev = NULL; 596 return (1); 597 } 598 599 #ifdef DDB 600 DB_SHOW_COMMAND(disk, db_getdiskbyname) 601 { 602 cdev_t dev; 603 604 if (modif[0] == '\0') { 605 db_error("usage: show disk/devicename"); 606 return; 607 } 608 dev = kgetdiskbyname(modif); 609 if (dev != NULL) 610 db_printf("cdev_t = %p\n", dev); 611 else 612 db_printf("No disk device matched.\n"); 613 } 614 #endif 615