vfs_mount.c revision 137509
1/* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * Copyright (c) 1999 Michael Smith 35 * All rights reserved. 36 * Copyright (c) 1999 Poul-Henning Kamp 37 * All rights reserved. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 */ 60 61#include <sys/cdefs.h> 62__FBSDID("$FreeBSD: head/sys/kern/vfs_mount.c 137509 2004-11-10 07:36:09Z phk $"); 63 64#include <sys/param.h> 65#include <sys/conf.h> 66#include <sys/cons.h> 67#include <sys/jail.h> 68#include <sys/kernel.h> 69#include <sys/linker.h> 70#include <sys/mac.h> 71#include <sys/malloc.h> 72#include <sys/mount.h> 73#include <sys/mutex.h> 74#include <sys/namei.h> 75#include <sys/proc.h> 76#include <sys/filedesc.h> 77#include <sys/reboot.h> 78#include <sys/sysproto.h> 79#include <sys/sx.h> 80#include <sys/sysctl.h> 81#include <sys/sysent.h> 82#include <sys/systm.h> 83#include <sys/vnode.h> 84 85#include <geom/geom.h> 86 87#include <machine/stdarg.h> 88 89#include "opt_rootdevname.h" 90#include "opt_ddb.h" 91#include "opt_mac.h" 92 93#ifdef DDB 94#include <ddb/ddb.h> 95#endif 96 97#define ROOTNAME "root_device" 98#define VFS_MOUNTARG_SIZE_MAX (1024 * 64) 99 100static void checkdirs(struct vnode *olddp, struct vnode *newdp); 101static struct cdev *getdiskbyname(char *_name); 102static void gets(char *cp); 103static int vfs_domount(struct thread *td, const char *fstype, 104 char *fspath, int fsflags, void *fsdata, int compat); 105static int vfs_mount_alloc(struct vnode *dvp, struct vfsconf *vfsp, 106 const char *fspath, struct thread *td, struct mount **mpp); 107static int vfs_mountroot_ask(void); 108static int vfs_mountroot_try(const char *mountfrom); 109static int vfs_donmount(struct thread *td, int fsflags, 110 struct uio *fsoptions); 111 112static int usermount = 0; 113SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0, 114 "Unprivileged users may mount and unmount file systems"); 115 116MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount structure"); 117 118/* List of mounted filesystems. */ 119struct mntlist mountlist = TAILQ_HEAD_INITIALIZER(mountlist); 120 121/* For any iteration/modification of mountlist */ 122struct mtx mountlist_mtx; 123 124/* 125 * The vnode of the system's root (/ in the filesystem, without chroot 126 * active.) 127 */ 128struct vnode *rootvnode; 129 130/* 131 * The root filesystem is detailed in the kernel environment variable 132 * vfs.root.mountfrom, which is expected to be in the general format 133 * 134 * <vfsname>:[<path>] 135 * vfsname := the name of a VFS known to the kernel and capable 136 * of being mounted as root 137 * path := disk device name or other data used by the filesystem 138 * to locate its physical store 139 */ 140 141/* 142 * The root specifiers we will try if RB_CDROM is specified. 143 */ 144static char *cdrom_rootdevnames[] = { 145 "cd9660:cd0", 146 "cd9660:acd0", 147 NULL 148}; 149 150/* legacy find-root code */ 151char *rootdevnames[2] = {NULL, NULL}; 152struct cdev *rootdev = NULL; 153#ifdef ROOTDEVNAME 154const char *ctrootdevname = ROOTDEVNAME; 155#else 156const char *ctrootdevname = NULL; 157#endif 158 159/* 160 * Has to be dynamic as the value of rootdev can change; however, it can't 161 * change after the root is mounted, so a user process can't access this 162 * sysctl until after the value is unchangeable. 163 */ 164static int 165sysctl_rootdev(SYSCTL_HANDLER_ARGS) 166{ 167 int error; 168 169 /* _RD prevents this from happening. */ 170 KASSERT(req->newptr == NULL, ("Attempt to change root device name")); 171 172 if (rootdev != NULL) 173 error = sysctl_handle_string(oidp, rootdev->si_name, 0, req); 174 else 175 error = sysctl_handle_string(oidp, "", 0, req); 176 177 return (error); 178} 179 180SYSCTL_PROC(_kern, OID_AUTO, rootdev, CTLTYPE_STRING | CTLFLAG_RD, 181 0, 0, sysctl_rootdev, "A", "Root file system device"); 182 183/* Remove one mount option. */ 184static void 185vfs_freeopt(struct vfsoptlist *opts, struct vfsopt *opt) 186{ 187 188 TAILQ_REMOVE(opts, opt, link); 189 free(opt->name, M_MOUNT); 190 if (opt->value != NULL) 191 free(opt->value, M_MOUNT); 192#ifdef INVARIANTS 193 else if (opt->len != 0) 194 panic("%s: mount option with NULL value but length != 0", 195 __func__); 196#endif 197 free(opt, M_MOUNT); 198} 199 200/* Release all resources related to the mount options. */ 201static void 202vfs_freeopts(struct vfsoptlist *opts) 203{ 204 struct vfsopt *opt; 205 206 while (!TAILQ_EMPTY(opts)) { 207 opt = TAILQ_FIRST(opts); 208 vfs_freeopt(opts, opt); 209 } 210 free(opts, M_MOUNT); 211} 212 213/* 214 * Check if options are equal (with or without the "no" prefix). 215 */ 216static int 217vfs_equalopts(const char *opt1, const char *opt2) 218{ 219 220 /* "opt" vs. "opt" or "noopt" vs. "noopt" */ 221 if (strcmp(opt1, opt2) == 0) 222 return (1); 223 /* "noopt" vs. "opt" */ 224 if (strncmp(opt1, "no", 2) == 0 && strcmp(opt1 + 2, opt2) == 0) 225 return (1); 226 /* "opt" vs. "noopt" */ 227 if (strncmp(opt2, "no", 2) == 0 && strcmp(opt1, opt2 + 2) == 0) 228 return (1); 229 return (0); 230} 231 232/* 233 * If a mount option is specified several times, 234 * (with or without the "no" prefix) only keep 235 * the last occurence of it. 236 */ 237static void 238vfs_sanitizeopts(struct vfsoptlist *opts) 239{ 240 struct vfsopt *opt, *opt2, *tmp; 241 242 TAILQ_FOREACH_REVERSE(opt, opts, vfsoptlist, link) { 243 opt2 = TAILQ_PREV(opt, vfsoptlist, link); 244 while (opt2 != NULL) { 245 if (vfs_equalopts(opt->name, opt2->name)) { 246 tmp = TAILQ_PREV(opt2, vfsoptlist, link); 247 vfs_freeopt(opts, opt2); 248 opt2 = tmp; 249 } else { 250 opt2 = TAILQ_PREV(opt2, vfsoptlist, link); 251 } 252 } 253 } 254} 255 256/* 257 * Build a linked list of mount options from a struct uio. 258 */ 259static int 260vfs_buildopts(struct uio *auio, struct vfsoptlist **options) 261{ 262 struct vfsoptlist *opts; 263 struct vfsopt *opt; 264 size_t memused; 265 unsigned int i, iovcnt; 266 int error, namelen, optlen; 267 268 opts = malloc(sizeof(struct vfsoptlist), M_MOUNT, M_WAITOK); 269 TAILQ_INIT(opts); 270 memused = 0; 271 iovcnt = auio->uio_iovcnt; 272 for (i = 0; i < iovcnt; i += 2) { 273 opt = malloc(sizeof(struct vfsopt), M_MOUNT, M_WAITOK); 274 namelen = auio->uio_iov[i].iov_len; 275 optlen = auio->uio_iov[i + 1].iov_len; 276 opt->name = malloc(namelen, M_MOUNT, M_WAITOK); 277 opt->value = NULL; 278 opt->len = 0; 279 280 /* 281 * Do this early, so jumps to "bad" will free the current 282 * option. 283 */ 284 TAILQ_INSERT_TAIL(opts, opt, link); 285 memused += sizeof(struct vfsopt) + optlen + namelen; 286 287 /* 288 * Avoid consuming too much memory, and attempts to overflow 289 * memused. 290 */ 291 if (memused > VFS_MOUNTARG_SIZE_MAX || 292 optlen > VFS_MOUNTARG_SIZE_MAX || 293 namelen > VFS_MOUNTARG_SIZE_MAX) { 294 error = EINVAL; 295 goto bad; 296 } 297 298 if (auio->uio_segflg == UIO_SYSSPACE) { 299 bcopy(auio->uio_iov[i].iov_base, opt->name, namelen); 300 } else { 301 error = copyin(auio->uio_iov[i].iov_base, opt->name, 302 namelen); 303 if (error) 304 goto bad; 305 } 306 /* Ensure names are null-terminated strings. */ 307 if (opt->name[namelen - 1] != '\0') { 308 error = EINVAL; 309 goto bad; 310 } 311 if (optlen != 0) { 312 opt->len = optlen; 313 opt->value = malloc(optlen, M_MOUNT, M_WAITOK); 314 if (auio->uio_segflg == UIO_SYSSPACE) { 315 bcopy(auio->uio_iov[i + 1].iov_base, opt->value, 316 optlen); 317 } else { 318 error = copyin(auio->uio_iov[i + 1].iov_base, 319 opt->value, optlen); 320 if (error) 321 goto bad; 322 } 323 } 324 } 325 vfs_sanitizeopts(opts); 326 *options = opts; 327 return (0); 328bad: 329 vfs_freeopts(opts); 330 return (error); 331} 332 333/* 334 * Merge the old mount options with the new ones passed 335 * in the MNT_UPDATE case. 336 */ 337static void 338vfs_mergeopts(struct vfsoptlist *toopts, struct vfsoptlist *opts) 339{ 340 struct vfsopt *opt, *opt2, *new; 341 342 TAILQ_FOREACH(opt, opts, link) { 343 /* 344 * Check that this option hasn't been redefined 345 * nor cancelled with a "no" mount option. 346 */ 347 opt2 = TAILQ_FIRST(toopts); 348 while (opt2 != NULL) { 349 if (strcmp(opt2->name, opt->name) == 0) 350 goto next; 351 if (strncmp(opt2->name, "no", 2) == 0 && 352 strcmp(opt2->name + 2, opt->name) == 0) { 353 vfs_freeopt(toopts, opt2); 354 goto next; 355 } 356 opt2 = TAILQ_NEXT(opt2, link); 357 } 358 /* We want this option, duplicate it. */ 359 new = malloc(sizeof(struct vfsopt), M_MOUNT, M_WAITOK); 360 new->name = malloc(strlen(opt->name) + 1, M_MOUNT, M_WAITOK); 361 strcpy(new->name, opt->name); 362 if (opt->len != 0) { 363 new->value = malloc(opt->len, M_MOUNT, M_WAITOK); 364 bcopy(opt->value, new->value, opt->len); 365 } else { 366 new->value = NULL; 367 } 368 new->len = opt->len; 369 TAILQ_INSERT_TAIL(toopts, new, link); 370next: 371 continue; 372 } 373} 374 375/* 376 * New mount API. 377 */ 378int 379nmount(td, uap) 380 struct thread *td; 381 struct nmount_args /* { 382 struct iovec *iovp; 383 unsigned int iovcnt; 384 int flags; 385 } */ *uap; 386{ 387 struct uio *auio; 388 struct iovec *iov; 389 unsigned int i; 390 int error; 391 u_int iovcnt; 392 393 iovcnt = uap->iovcnt; 394 /* 395 * Check that we have an even number of iovec's 396 * and that we have at least two options. 397 */ 398 if ((iovcnt & 1) || (iovcnt < 4)) 399 return (EINVAL); 400 error = copyinuio(uap->iovp, iovcnt, &auio); 401 if (error) 402 return (error); 403 iov = auio->uio_iov; 404 for (i = 0; i < iovcnt; i++) { 405 if (iov->iov_len > MMAXOPTIONLEN) { 406 free(auio, M_IOV); 407 return (EINVAL); 408 } 409 iov++; 410 } 411 error = vfs_donmount(td, uap->flags, auio); 412 free(auio, M_IOV); 413 return (error); 414} 415 416int 417kernel_mount(struct iovec *iovp, u_int iovcnt, int flags) 418{ 419 struct uio auio; 420 int error; 421 422 /* 423 * Check that we have an even number of iovec's 424 * and that we have at least two options. 425 */ 426 if ((iovcnt & 1) || (iovcnt < 4)) 427 return (EINVAL); 428 429 auio.uio_iov = iovp; 430 auio.uio_iovcnt = iovcnt; 431 auio.uio_segflg = UIO_SYSSPACE; 432 433 error = vfs_donmount(curthread, flags, &auio); 434 return (error); 435} 436 437int 438kernel_vmount(int flags, ...) 439{ 440 struct iovec *iovp; 441 struct uio auio; 442 va_list ap; 443 u_int iovcnt, iovlen, len; 444 const char *cp; 445 char *buf, *pos; 446 size_t n; 447 int error, i; 448 449 len = 0; 450 va_start(ap, flags); 451 for (iovcnt = 0; (cp = va_arg(ap, const char *)) != NULL; iovcnt++) 452 len += strlen(cp) + 1; 453 va_end(ap); 454 455 if (iovcnt < 4 || iovcnt & 1) 456 return (EINVAL); 457 458 iovlen = iovcnt * sizeof (struct iovec); 459 MALLOC(iovp, struct iovec *, iovlen, M_MOUNT, M_WAITOK); 460 MALLOC(buf, char *, len, M_MOUNT, M_WAITOK); 461 pos = buf; 462 va_start(ap, flags); 463 for (i = 0; i < iovcnt; i++) { 464 cp = va_arg(ap, const char *); 465 copystr(cp, pos, len - (pos - buf), &n); 466 iovp[i].iov_base = pos; 467 iovp[i].iov_len = n; 468 pos += n; 469 } 470 va_end(ap); 471 472 auio.uio_iov = iovp; 473 auio.uio_iovcnt = iovcnt; 474 auio.uio_segflg = UIO_SYSSPACE; 475 476 error = vfs_donmount(curthread, flags, &auio); 477 FREE(iovp, M_MOUNT); 478 FREE(buf, M_MOUNT); 479 return (error); 480} 481 482/* 483 * Allocate and initialize the mount point struct. 484 */ 485static int 486vfs_mount_alloc(struct vnode *vp, struct vfsconf *vfsp, 487 const char *fspath, struct thread *td, struct mount **mpp) 488{ 489 struct mount *mp; 490 491 mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK | M_ZERO); 492 TAILQ_INIT(&mp->mnt_nvnodelist); 493 mp->mnt_nvnodelistsize = 0; 494 mtx_init(&mp->mnt_mtx, "struct mount mtx", NULL, MTX_DEF); 495 lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE); 496 vfs_busy(mp, LK_NOWAIT, 0, td); 497 mp->mnt_op = vfsp->vfc_vfsops; 498 mp->mnt_vfc = vfsp; 499 vfsp->vfc_refcount++; 500 mp->mnt_stat.f_type = vfsp->vfc_typenum; 501 mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK; 502 strlcpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN); 503 mp->mnt_vnodecovered = vp; 504 mp->mnt_cred = crdup(td->td_ucred); 505 mp->mnt_stat.f_owner = td->td_ucred->cr_uid; 506 strlcpy(mp->mnt_stat.f_mntonname, fspath, MNAMELEN); 507 mp->mnt_iosize_max = DFLTPHYS; 508#ifdef MAC 509 mac_init_mount(mp); 510 mac_create_mount(td->td_ucred, mp); 511#endif 512 *mpp = mp; 513 return (0); 514} 515 516/* 517 * Destroy the mount struct previously allocated by vfs_mount_alloc(). 518 */ 519void 520vfs_mount_destroy(struct mount *mp, struct thread *td) 521{ 522 523 mp->mnt_vfc->vfc_refcount--; 524 if (!TAILQ_EMPTY(&mp->mnt_nvnodelist)) 525 panic("unmount: dangling vnode"); 526 vfs_unbusy(mp,td); 527 lockdestroy(&mp->mnt_lock); 528 mtx_destroy(&mp->mnt_mtx); 529 if (mp->mnt_kern_flag & MNTK_MWAIT) 530 wakeup(mp); 531#ifdef MAC 532 mac_destroy_mount(mp); 533#endif 534 if (mp->mnt_opt != NULL) 535 vfs_freeopts(mp->mnt_opt); 536 crfree(mp->mnt_cred); 537 free(mp, M_MOUNT); 538} 539 540static int 541vfs_donmount(struct thread *td, int fsflags, struct uio *fsoptions) 542{ 543 struct vfsoptlist *optlist; 544 char *fstype, *fspath; 545 int error, fstypelen, fspathlen; 546 547 error = vfs_buildopts(fsoptions, &optlist); 548 if (error) 549 return (error); 550 551 /* 552 * We need these two options before the others, 553 * and they are mandatory for any filesystem. 554 * Ensure they are NUL terminated as well. 555 */ 556 fstypelen = 0; 557 error = vfs_getopt(optlist, "fstype", (void **)&fstype, &fstypelen); 558 if (error || fstype[fstypelen - 1] != '\0') { 559 error = EINVAL; 560 goto bail; 561 } 562 fspathlen = 0; 563 error = vfs_getopt(optlist, "fspath", (void **)&fspath, &fspathlen); 564 if (error || fspath[fspathlen - 1] != '\0') { 565 error = EINVAL; 566 goto bail; 567 } 568 569 /* 570 * Be ultra-paranoid about making sure the type and fspath 571 * variables will fit in our mp buffers, including the 572 * terminating NUL. 573 */ 574 if (fstypelen >= MFSNAMELEN - 1 || fspathlen >= MNAMELEN - 1) { 575 error = ENAMETOOLONG; 576 goto bail; 577 } 578 579 error = vfs_domount(td, fstype, fspath, fsflags, optlist, 0); 580bail: 581 if (error) 582 vfs_freeopts(optlist); 583 return (error); 584} 585 586/* 587 * Old mount API. 588 */ 589#ifndef _SYS_SYSPROTO_H_ 590struct mount_args { 591 char *type; 592 char *path; 593 int flags; 594 caddr_t data; 595}; 596#endif 597/* ARGSUSED */ 598int 599mount(td, uap) 600 struct thread *td; 601 struct mount_args /* { 602 char *type; 603 char *path; 604 int flags; 605 caddr_t data; 606 } */ *uap; 607{ 608 char *fstype; 609 char *fspath; 610 int error; 611 612 fstype = malloc(MFSNAMELEN, M_TEMP, M_WAITOK); 613 fspath = malloc(MNAMELEN, M_TEMP, M_WAITOK); 614 615 /* 616 * vfs_mount() actually takes a kernel string for `type' and 617 * `path' now, so extract them. 618 */ 619 error = copyinstr(uap->type, fstype, MFSNAMELEN, NULL); 620 if (error == 0) 621 error = copyinstr(uap->path, fspath, MNAMELEN, NULL); 622 if (error == 0) 623 error = vfs_domount(td, fstype, fspath, uap->flags, 624 uap->data, 1); 625 free(fstype, M_TEMP); 626 free(fspath, M_TEMP); 627 return (error); 628} 629 630/* 631 * vfs_mount(): actually attempt a filesystem mount. 632 * 633 * This routine is designed to be a "generic" entry point for routines 634 * that wish to mount a filesystem. All parameters except `fsdata' are 635 * pointers into kernel space. `fsdata' is currently still a pointer 636 * into userspace. 637 */ 638int 639vfs_mount(td, fstype, fspath, fsflags, fsdata) 640 struct thread *td; 641 const char *fstype; 642 char *fspath; 643 int fsflags; 644 void *fsdata; 645{ 646 647 return (vfs_domount(td, fstype, fspath, fsflags, fsdata, 1)); 648} 649 650/* 651 * vfs_domount(): actually attempt a filesystem mount. 652 */ 653static int 654vfs_domount( 655 struct thread *td, /* Flags common to all filesystems. */ 656 const char *fstype, /* Filesystem type. */ 657 char *fspath, /* Mount path. */ 658 int fsflags, /* Flags common to all filesystems. */ 659 void *fsdata, /* Options local to the filesystem. */ 660 int compat /* Invocation from compat syscall. */ 661 ) 662{ 663 linker_file_t lf; 664 struct vnode *vp; 665 struct mount *mp; 666 struct vfsconf *vfsp; 667 int error, flag = 0, kern_flag = 0; 668 struct vattr va; 669 struct nameidata nd; 670 671 /* 672 * Be ultra-paranoid about making sure the type and fspath 673 * variables will fit in our mp buffers, including the 674 * terminating NUL. 675 */ 676 if (strlen(fstype) >= MFSNAMELEN || strlen(fspath) >= MNAMELEN) 677 return (ENAMETOOLONG); 678 679 if (jailed(td->td_ucred)) 680 return (EPERM); 681 if (usermount == 0) { 682 if ((error = suser(td)) != 0) 683 return (error); 684 } 685 686 /* 687 * Do not allow NFS export or MNT_SUIDDIR by unprivileged users. 688 */ 689 if (fsflags & (MNT_EXPORTED | MNT_SUIDDIR)) { 690 if ((error = suser(td)) != 0) 691 return (error); 692 } 693 /* 694 * Silently enforce MNT_NODEV, MNT_NOSUID and MNT_USER for 695 * unprivileged users. 696 */ 697 if (suser(td) != 0) 698 fsflags |= MNT_NODEV | MNT_NOSUID | MNT_USER; 699 /* 700 * Get vnode to be covered 701 */ 702 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, td); 703 if ((error = namei(&nd)) != 0) 704 return (error); 705 NDFREE(&nd, NDF_ONLY_PNBUF); 706 vp = nd.ni_vp; 707 if (fsflags & MNT_UPDATE) { 708 if ((vp->v_vflag & VV_ROOT) == 0) { 709 vput(vp); 710 return (EINVAL); 711 } 712 mp = vp->v_mount; 713 flag = mp->mnt_flag; 714 kern_flag = mp->mnt_kern_flag; 715 /* 716 * We only allow the filesystem to be reloaded if it 717 * is currently mounted read-only. 718 */ 719 if ((fsflags & MNT_RELOAD) && 720 ((mp->mnt_flag & MNT_RDONLY) == 0)) { 721 vput(vp); 722 return (EOPNOTSUPP); /* Needs translation */ 723 } 724 /* 725 * Only privileged root, or (if MNT_USER is set) the user that 726 * did the original mount is permitted to update it. 727 */ 728 error = vfs_suser(mp, td); 729 if (error) { 730 vput(vp); 731 return (error); 732 } 733 if (vfs_busy(mp, LK_NOWAIT, 0, td)) { 734 vput(vp); 735 return (EBUSY); 736 } 737 VI_LOCK(vp); 738 if ((vp->v_iflag & VI_MOUNT) != 0 || 739 vp->v_mountedhere != NULL) { 740 VI_UNLOCK(vp); 741 vfs_unbusy(mp, td); 742 vput(vp); 743 return (EBUSY); 744 } 745 vp->v_iflag |= VI_MOUNT; 746 VI_UNLOCK(vp); 747 mp->mnt_flag |= fsflags & 748 (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT); 749 VOP_UNLOCK(vp, 0, td); 750 if (compat == 0) { 751 mp->mnt_optnew = fsdata; 752 vfs_mergeopts(mp->mnt_optnew, mp->mnt_opt); 753 } 754 } else { 755 /* 756 * If the user is not root, ensure that they own the directory 757 * onto which we are attempting to mount. 758 */ 759 error = VOP_GETATTR(vp, &va, td->td_ucred, td); 760 if (error) { 761 vput(vp); 762 return (error); 763 } 764 if (va.va_uid != td->td_ucred->cr_uid) { 765 if ((error = suser(td)) != 0) { 766 vput(vp); 767 return (error); 768 } 769 } 770 if ((error = vinvalbuf(vp, V_SAVE, td->td_ucred, td, 0, 0)) != 0) { 771 vput(vp); 772 return (error); 773 } 774 if (vp->v_type != VDIR) { 775 vput(vp); 776 return (ENOTDIR); 777 } 778 vfsp = vfs_byname(fstype); 779 if (vfsp == NULL) { 780 /* Only load modules for root (very important!). */ 781 if ((error = suser(td)) != 0) { 782 vput(vp); 783 return (error); 784 } 785 error = securelevel_gt(td->td_ucred, 0); 786 if (error) { 787 vput(vp); 788 return (error); 789 } 790 error = linker_load_module(NULL, fstype, NULL, NULL, &lf); 791 if (error || lf == NULL) { 792 vput(vp); 793 if (lf == NULL) 794 error = ENODEV; 795 return (error); 796 } 797 lf->userrefs++; 798 /* Look up again to see if the VFS was loaded. */ 799 vfsp = vfs_byname(fstype); 800 if (vfsp == NULL) { 801 lf->userrefs--; 802 linker_file_unload(lf, LINKER_UNLOAD_FORCE); 803 vput(vp); 804 return (ENODEV); 805 } 806 } 807 VI_LOCK(vp); 808 if ((vp->v_iflag & VI_MOUNT) != 0 || 809 vp->v_mountedhere != NULL) { 810 VI_UNLOCK(vp); 811 vput(vp); 812 return (EBUSY); 813 } 814 vp->v_iflag |= VI_MOUNT; 815 VI_UNLOCK(vp); 816 817 /* 818 * Allocate and initialize the filesystem. 819 */ 820 error = vfs_mount_alloc(vp, vfsp, fspath, td, &mp); 821 if (error) { 822 vput(vp); 823 return (error); 824 } 825 VOP_UNLOCK(vp, 0, td); 826 827 /* XXXMAC: pass to vfs_mount_alloc? */ 828 if (compat == 0) 829 mp->mnt_optnew = fsdata; 830 } 831 /* 832 * Check if the fs implements the type VFS_[O]MOUNT() 833 * function we are looking for. 834 */ 835 if ((compat == 0) == (mp->mnt_op->vfs_omount != NULL)) { 836 printf("%s doesn't support the %s mount syscall\n", 837 mp->mnt_vfc->vfc_name, compat ? "old" : "new"); 838 VI_LOCK(vp); 839 vp->v_iflag &= ~VI_MOUNT; 840 VI_UNLOCK(vp); 841 if (mp->mnt_flag & MNT_UPDATE) 842 vfs_unbusy(mp, td); 843 else 844 vfs_mount_destroy(mp, td); 845 vrele(vp); 846 return (EOPNOTSUPP); 847 } 848 849 /* 850 * Set the mount level flags. 851 */ 852 if (fsflags & MNT_RDONLY) 853 mp->mnt_flag |= MNT_RDONLY; 854 else if (mp->mnt_flag & MNT_RDONLY) 855 mp->mnt_kern_flag |= MNTK_WANTRDWR; 856 mp->mnt_flag &=~ MNT_UPDATEMASK; 857 mp->mnt_flag |= fsflags & (MNT_UPDATEMASK | MNT_FORCE); 858 /* 859 * Mount the filesystem. 860 * XXX The final recipients of VFS_MOUNT just overwrite the ndp they 861 * get. No freeing of cn_pnbuf. 862 */ 863 if (compat) 864 error = VFS_OMOUNT(mp, fspath, fsdata, td); 865 else 866 error = VFS_MOUNT(mp, td); 867 if (!error) { 868 if (mp->mnt_opt != NULL) 869 vfs_freeopts(mp->mnt_opt); 870 mp->mnt_opt = mp->mnt_optnew; 871 } 872 /* 873 * Prevent external consumers of mount options from reading 874 * mnt_optnew. 875 */ 876 mp->mnt_optnew = NULL; 877 if (mp->mnt_flag & MNT_UPDATE) { 878 if (mp->mnt_kern_flag & MNTK_WANTRDWR) 879 mp->mnt_flag &= ~MNT_RDONLY; 880 mp->mnt_flag &= 881 ~(MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_SNAPSHOT); 882 mp->mnt_kern_flag &= ~MNTK_WANTRDWR; 883 if (error) { 884 mp->mnt_flag = flag; 885 mp->mnt_kern_flag = kern_flag; 886 } 887 if ((mp->mnt_flag & MNT_RDONLY) == 0) { 888 if (mp->mnt_syncer == NULL) 889 error = vfs_allocate_syncvnode(mp); 890 } else { 891 if (mp->mnt_syncer != NULL) 892 vrele(mp->mnt_syncer); 893 mp->mnt_syncer = NULL; 894 } 895 vfs_unbusy(mp, td); 896 VI_LOCK(vp); 897 vp->v_iflag &= ~VI_MOUNT; 898 VI_UNLOCK(vp); 899 vrele(vp); 900 return (error); 901 } 902 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 903 /* 904 * Put the new filesystem on the mount list after root. 905 */ 906 cache_purge(vp); 907 if (!error) { 908 struct vnode *newdp; 909 910 VI_LOCK(vp); 911 vp->v_iflag &= ~VI_MOUNT; 912 VI_UNLOCK(vp); 913 vp->v_mountedhere = mp; 914 mtx_lock(&mountlist_mtx); 915 TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list); 916 mtx_unlock(&mountlist_mtx); 917 vfs_event_signal(NULL, VQ_MOUNT, 0); 918 if (VFS_ROOT(mp, &newdp, td)) 919 panic("mount: lost mount"); 920 checkdirs(vp, newdp); 921 vput(newdp); 922 VOP_UNLOCK(vp, 0, td); 923 if ((mp->mnt_flag & MNT_RDONLY) == 0) 924 error = vfs_allocate_syncvnode(mp); 925 vfs_unbusy(mp, td); 926 if (error || (error = VFS_START(mp, 0, td)) != 0) 927 vrele(vp); 928 } else { 929 VI_LOCK(vp); 930 vp->v_iflag &= ~VI_MOUNT; 931 VI_UNLOCK(vp); 932 vfs_mount_destroy(mp, td); 933 vput(vp); 934 } 935 return (error); 936} 937 938/* 939 * Scan all active processes to see if any of them have a current 940 * or root directory of `olddp'. If so, replace them with the new 941 * mount point. 942 */ 943static void 944checkdirs(olddp, newdp) 945 struct vnode *olddp, *newdp; 946{ 947 struct filedesc *fdp; 948 struct proc *p; 949 int nrele; 950 951 if (vrefcnt(olddp) == 1) 952 return; 953 sx_slock(&allproc_lock); 954 LIST_FOREACH(p, &allproc, p_list) { 955 mtx_lock(&fdesc_mtx); 956 fdp = p->p_fd; 957 if (fdp == NULL) { 958 mtx_unlock(&fdesc_mtx); 959 continue; 960 } 961 nrele = 0; 962 FILEDESC_LOCK(fdp); 963 if (fdp->fd_cdir == olddp) { 964 VREF(newdp); 965 fdp->fd_cdir = newdp; 966 nrele++; 967 } 968 if (fdp->fd_rdir == olddp) { 969 VREF(newdp); 970 fdp->fd_rdir = newdp; 971 nrele++; 972 } 973 FILEDESC_UNLOCK(fdp); 974 mtx_unlock(&fdesc_mtx); 975 while (nrele--) 976 vrele(olddp); 977 } 978 sx_sunlock(&allproc_lock); 979 if (rootvnode == olddp) { 980 vrele(rootvnode); 981 VREF(newdp); 982 rootvnode = newdp; 983 } 984} 985 986/* 987 * Unmount a filesystem. 988 * 989 * Note: unmount takes a path to the vnode mounted on as argument, 990 * not special file (as before). 991 */ 992#ifndef _SYS_SYSPROTO_H_ 993struct unmount_args { 994 char *path; 995 int flags; 996}; 997#endif 998/* ARGSUSED */ 999int 1000unmount(td, uap) 1001 struct thread *td; 1002 register struct unmount_args /* { 1003 char *path; 1004 int flags; 1005 } */ *uap; 1006{ 1007 struct mount *mp; 1008 char *pathbuf; 1009 int error, id0, id1; 1010 1011 if (jailed(td->td_ucred)) 1012 return (EPERM); 1013 if (usermount == 0) { 1014 if ((error = suser(td)) != 0) 1015 return (error); 1016 } 1017 1018 pathbuf = malloc(MNAMELEN, M_TEMP, M_WAITOK); 1019 error = copyinstr(uap->path, pathbuf, MNAMELEN, NULL); 1020 if (error) { 1021 free(pathbuf, M_TEMP); 1022 return (error); 1023 } 1024 if (uap->flags & MNT_BYFSID) { 1025 /* Decode the filesystem ID. */ 1026 if (sscanf(pathbuf, "FSID:%d:%d", &id0, &id1) != 2) { 1027 free(pathbuf, M_TEMP); 1028 return (EINVAL); 1029 } 1030 1031 mtx_lock(&mountlist_mtx); 1032 TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) { 1033 if (mp->mnt_stat.f_fsid.val[0] == id0 && 1034 mp->mnt_stat.f_fsid.val[1] == id1) 1035 break; 1036 } 1037 mtx_unlock(&mountlist_mtx); 1038 } else { 1039 mtx_lock(&mountlist_mtx); 1040 TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) { 1041 if (strcmp(mp->mnt_stat.f_mntonname, pathbuf) == 0) 1042 break; 1043 } 1044 mtx_unlock(&mountlist_mtx); 1045 } 1046 free(pathbuf, M_TEMP); 1047 if (mp == NULL) { 1048 /* 1049 * Previously we returned ENOENT for a nonexistent path and 1050 * EINVAL for a non-mountpoint. We cannot tell these apart 1051 * now, so in the !MNT_BYFSID case return the more likely 1052 * EINVAL for compatibility. 1053 */ 1054 return ((uap->flags & MNT_BYFSID) ? ENOENT : EINVAL); 1055 } 1056 1057 /* 1058 * Only privileged root, or (if MNT_USER is set) the user that did the 1059 * original mount is permitted to unmount this filesystem. 1060 */ 1061 error = vfs_suser(mp, td); 1062 if (error) 1063 return (error); 1064 1065 /* 1066 * Don't allow unmounting the root filesystem. 1067 */ 1068 if (mp->mnt_flag & MNT_ROOTFS) 1069 return (EINVAL); 1070 return (dounmount(mp, uap->flags, td)); 1071} 1072 1073/* 1074 * Do the actual filesystem unmount. 1075 */ 1076int 1077dounmount(mp, flags, td) 1078 struct mount *mp; 1079 int flags; 1080 struct thread *td; 1081{ 1082 struct vnode *coveredvp, *fsrootvp; 1083 int error; 1084 int async_flag; 1085 1086 mtx_lock(&mountlist_mtx); 1087 if (mp->mnt_kern_flag & MNTK_UNMOUNT) { 1088 mtx_unlock(&mountlist_mtx); 1089 return (EBUSY); 1090 } 1091 mp->mnt_kern_flag |= MNTK_UNMOUNT; 1092 /* Allow filesystems to detect that a forced unmount is in progress. */ 1093 if (flags & MNT_FORCE) 1094 mp->mnt_kern_flag |= MNTK_UNMOUNTF; 1095 error = lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK | 1096 ((flags & MNT_FORCE) ? 0 : LK_NOWAIT), &mountlist_mtx, td); 1097 if (error) { 1098 mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF); 1099 if (mp->mnt_kern_flag & MNTK_MWAIT) 1100 wakeup(mp); 1101 return (error); 1102 } 1103 vn_start_write(NULL, &mp, V_WAIT); 1104 1105 if (mp->mnt_flag & MNT_EXPUBLIC) 1106 vfs_setpublicfs(NULL, NULL, NULL); 1107 1108 vfs_msync(mp, MNT_WAIT); 1109 async_flag = mp->mnt_flag & MNT_ASYNC; 1110 mp->mnt_flag &= ~MNT_ASYNC; 1111 cache_purgevfs(mp); /* remove cache entries for this file sys */ 1112 if (mp->mnt_syncer != NULL) 1113 vrele(mp->mnt_syncer); 1114 /* 1115 * For forced unmounts, move process cdir/rdir refs on the fs root 1116 * vnode to the covered vnode. For non-forced unmounts we want 1117 * such references to cause an EBUSY error. 1118 */ 1119 if ((flags & MNT_FORCE) && VFS_ROOT(mp, &fsrootvp, td) == 0) { 1120 if (mp->mnt_vnodecovered != NULL) 1121 checkdirs(fsrootvp, mp->mnt_vnodecovered); 1122 if (fsrootvp == rootvnode) { 1123 vrele(rootvnode); 1124 rootvnode = NULL; 1125 } 1126 vput(fsrootvp); 1127 } 1128 if (((mp->mnt_flag & MNT_RDONLY) || 1129 (error = VFS_SYNC(mp, MNT_WAIT, td->td_ucred, td)) == 0) || 1130 (flags & MNT_FORCE)) { 1131 error = VFS_UNMOUNT(mp, flags, td); 1132 } 1133 vn_finished_write(mp); 1134 if (error) { 1135 /* Undo cdir/rdir and rootvnode changes made above. */ 1136 if ((flags & MNT_FORCE) && VFS_ROOT(mp, &fsrootvp, td) == 0) { 1137 if (mp->mnt_vnodecovered != NULL) 1138 checkdirs(mp->mnt_vnodecovered, fsrootvp); 1139 if (rootvnode == NULL) { 1140 rootvnode = fsrootvp; 1141 vref(rootvnode); 1142 } 1143 vput(fsrootvp); 1144 } 1145 if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL) 1146 (void) vfs_allocate_syncvnode(mp); 1147 mtx_lock(&mountlist_mtx); 1148 mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF); 1149 mp->mnt_flag |= async_flag; 1150 lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, 1151 &mountlist_mtx, td); 1152 if (mp->mnt_kern_flag & MNTK_MWAIT) 1153 wakeup(mp); 1154 return (error); 1155 } 1156 mtx_lock(&mountlist_mtx); 1157 TAILQ_REMOVE(&mountlist, mp, mnt_list); 1158 if ((coveredvp = mp->mnt_vnodecovered) != NULL) 1159 coveredvp->v_mountedhere = NULL; 1160 mtx_unlock(&mountlist_mtx); 1161 vfs_event_signal(NULL, VQ_UNMOUNT, 0); 1162 vfs_mount_destroy(mp, td); 1163 if (coveredvp != NULL) 1164 vrele(coveredvp); 1165 return (0); 1166} 1167 1168/* 1169 * Lookup a filesystem type, and if found allocate and initialize 1170 * a mount structure for it. 1171 * 1172 * Devname is usually updated by mount(8) after booting. 1173 */ 1174int 1175vfs_rootmountalloc(fstypename, devname, mpp) 1176 char *fstypename; 1177 char *devname; 1178 struct mount **mpp; 1179{ 1180 struct thread *td = curthread; /* XXX */ 1181 struct vfsconf *vfsp; 1182 struct mount *mp; 1183 int error; 1184 1185 if (fstypename == NULL) 1186 return (ENODEV); 1187 vfsp = vfs_byname(fstypename); 1188 if (vfsp == NULL) 1189 return (ENODEV); 1190 error = vfs_mount_alloc(NULLVP, vfsp, "/", td, &mp); 1191 if (error) 1192 return (error); 1193 mp->mnt_flag |= MNT_RDONLY | MNT_ROOTFS; 1194 strlcpy(mp->mnt_stat.f_mntfromname, devname, MNAMELEN); 1195 *mpp = mp; 1196 return (0); 1197} 1198 1199/* 1200 * Find and mount the root filesystem 1201 */ 1202void 1203vfs_mountroot(void) 1204{ 1205 char *cp; 1206 int error, i, asked = 0; 1207 1208 1209 /* 1210 * Wait for GEOM to settle down 1211 */ 1212 DROP_GIANT(); 1213 g_waitidle(); 1214 PICKUP_GIANT(); 1215 1216 /* 1217 * We are booted with instructions to prompt for the root filesystem. 1218 */ 1219 if (boothowto & RB_ASKNAME) { 1220 if (!vfs_mountroot_ask()) 1221 return; 1222 asked = 1; 1223 } 1224 1225 /* 1226 * The root filesystem information is compiled in, and we are 1227 * booted with instructions to use it. 1228 */ 1229 if (ctrootdevname != NULL && (boothowto & RB_DFLTROOT)) { 1230 if (!vfs_mountroot_try(ctrootdevname)) 1231 return; 1232 ctrootdevname = NULL; 1233 } 1234 1235 /* 1236 * We've been given the generic "use CDROM as root" flag. This is 1237 * necessary because one media may be used in many different 1238 * devices, so we need to search for them. 1239 */ 1240 if (boothowto & RB_CDROM) { 1241 for (i = 0; cdrom_rootdevnames[i] != NULL; i++) { 1242 if (!vfs_mountroot_try(cdrom_rootdevnames[i])) 1243 return; 1244 } 1245 } 1246 1247 /* 1248 * Try to use the value read by the loader from /etc/fstab, or 1249 * supplied via some other means. This is the preferred 1250 * mechanism. 1251 */ 1252 cp = getenv("vfs.root.mountfrom"); 1253 if (cp != NULL) { 1254 error = vfs_mountroot_try(cp); 1255 freeenv(cp); 1256 if (!error) 1257 return; 1258 } 1259 1260 /* 1261 * Try values that may have been computed by code during boot 1262 */ 1263 if (!vfs_mountroot_try(rootdevnames[0])) 1264 return; 1265 if (!vfs_mountroot_try(rootdevnames[1])) 1266 return; 1267 1268 /* 1269 * If we (still) have a compiled-in default, try it. 1270 */ 1271 if (ctrootdevname != NULL) 1272 if (!vfs_mountroot_try(ctrootdevname)) 1273 return; 1274 1275 /* 1276 * Everything so far has failed, prompt on the console if we haven't 1277 * already tried that. 1278 */ 1279 if (!asked) 1280 if (!vfs_mountroot_ask()) 1281 return; 1282 panic("Root mount failed, startup aborted."); 1283} 1284 1285/* 1286 * Mount (mountfrom) as the root filesystem. 1287 */ 1288static int 1289vfs_mountroot_try(const char *mountfrom) 1290{ 1291 struct mount *mp; 1292 char *vfsname, *path; 1293 const char *devname; 1294 int error; 1295 char patt[32]; 1296 int s; 1297 1298 vfsname = NULL; 1299 path = NULL; 1300 mp = NULL; 1301 error = EINVAL; 1302 1303 if (mountfrom == NULL) 1304 return (error); /* don't complain */ 1305 1306 s = splcam(); /* Overkill, but annoying without it */ 1307 printf("Mounting root from %s\n", mountfrom); 1308 splx(s); 1309 1310 /* parse vfs name and path */ 1311 vfsname = malloc(MFSNAMELEN, M_MOUNT, M_WAITOK); 1312 path = malloc(MNAMELEN, M_MOUNT, M_WAITOK); 1313 vfsname[0] = path[0] = 0; 1314 sprintf(patt, "%%%d[a-z0-9]:%%%ds", MFSNAMELEN, MNAMELEN); 1315 if (sscanf(mountfrom, patt, vfsname, path) < 1) 1316 goto done; 1317 1318 /* allocate a root mount */ 1319 error = vfs_rootmountalloc(vfsname, path[0] != 0 ? path : ROOTNAME, 1320 &mp); 1321 if (error != 0) { 1322 printf("Can't allocate root mount for filesystem '%s': %d\n", 1323 vfsname, error); 1324 goto done; 1325 } 1326 1327 /* 1328 * do our best to set rootdev 1329 * XXX: This does not belong here! 1330 */ 1331 if (path[0] != '\0') { 1332 struct cdev *diskdev; 1333 diskdev = getdiskbyname(path); 1334 if (diskdev != NULL) 1335 rootdev = diskdev; 1336 else 1337 printf("setrootbyname failed\n"); 1338 } 1339 1340 error = VFS_OMOUNT(mp, NULL, NULL, curthread); 1341 1342done: 1343 if (vfsname != NULL) 1344 free(vfsname, M_MOUNT); 1345 if (path != NULL) 1346 free(path, M_MOUNT); 1347 if (error != 0) { 1348 if (mp != NULL) 1349 vfs_mount_destroy(mp, curthread); 1350 printf("Root mount failed: %d\n", error); 1351 } else { 1352 1353 /* register with list of mounted filesystems */ 1354 mtx_lock(&mountlist_mtx); 1355 TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list); 1356 mtx_unlock(&mountlist_mtx); 1357 1358 /* sanity check system clock against root fs timestamp */ 1359 inittodr(mp->mnt_time); 1360 vfs_unbusy(mp, curthread); 1361 error = VFS_START(mp, 0, curthread); 1362 } 1363 return (error); 1364} 1365 1366/* 1367 * Spin prompting on the console for a suitable root filesystem 1368 */ 1369static int 1370vfs_mountroot_ask(void) 1371{ 1372 char name[128]; 1373 1374 for(;;) { 1375 printf("\nManual root filesystem specification:\n"); 1376 printf(" <fstype>:<device> Mount <device> using filesystem <fstype>\n"); 1377#if defined(__i386__) || defined(__ia64__) 1378 printf(" eg. ufs:da0s1a\n"); 1379#else 1380 printf(" eg. ufs:/dev/da0a\n"); 1381#endif 1382 printf(" ? List valid disk boot devices\n"); 1383 printf(" <empty line> Abort manual input\n"); 1384 printf("\nmountroot> "); 1385 gets(name); 1386 if (name[0] == '\0') 1387 return (1); 1388 if (name[0] == '?') { 1389 printf("\nList of GEOM managed disk devices:\n "); 1390 g_dev_print(); 1391 continue; 1392 } 1393 if (!vfs_mountroot_try(name)) 1394 return (0); 1395 } 1396} 1397 1398/* 1399 * Local helper function for vfs_mountroot_ask. 1400 */ 1401static void 1402gets(char *cp) 1403{ 1404 char *lp; 1405 int c; 1406 1407 lp = cp; 1408 for (;;) { 1409 printf("%c", c = cngetc() & 0177); 1410 switch (c) { 1411 case -1: 1412 case '\n': 1413 case '\r': 1414 *lp++ = '\0'; 1415 return; 1416 case '\b': 1417 case '\177': 1418 if (lp > cp) { 1419 printf(" \b"); 1420 lp--; 1421 } 1422 continue; 1423 case '#': 1424 lp--; 1425 if (lp < cp) 1426 lp = cp; 1427 continue; 1428 case '@': 1429 case 'u' & 037: 1430 lp = cp; 1431 printf("%c", '\n'); 1432 continue; 1433 default: 1434 *lp++ = c; 1435 } 1436 } 1437} 1438 1439/* 1440 * Convert a given name to the cdev pointer of the device, which is probably 1441 * but not by definition, a disk. Mount a DEVFS (on nothing), look the name 1442 * up, extract the cdev from the vnode and unmount it again. Unfortunately 1443 * we cannot use the vnode directly (because we unmount the DEVFS again) 1444 * so the filesystems still have to do the bdevvp() stunt. 1445 */ 1446static struct cdev * 1447getdiskbyname(char *name) 1448{ 1449 char *cp = name; 1450 struct cdev *dev = NULL; 1451 struct thread *td = curthread; 1452 struct vfsconf *vfsp; 1453 struct mount *mp = NULL; 1454 struct vnode *vroot = NULL; 1455 struct nameidata nid; 1456 int error; 1457 1458 if (!bcmp(cp, "/dev/", 5)) 1459 cp += 5; 1460 1461 do { 1462 vfsp = vfs_byname("devfs"); 1463 if (vfsp == NULL) 1464 break; 1465 error = vfs_mount_alloc(NULLVP, vfsp, "/dev", td, &mp); 1466 if (error) 1467 break; 1468 mp->mnt_flag |= MNT_RDONLY; 1469 1470 error = VFS_MOUNT(mp, curthread); 1471 if (error) 1472 break; 1473 VFS_START(mp, 0, td); 1474 VFS_ROOT(mp, &vroot, td); 1475 VOP_UNLOCK(vroot, 0, td); 1476 1477 NDINIT(&nid, LOOKUP, NOCACHE|FOLLOW, 1478 UIO_SYSSPACE, cp, curthread); 1479 nid.ni_startdir = vroot; 1480 nid.ni_pathlen = strlen(cp); 1481 nid.ni_cnd.cn_cred = curthread->td_ucred; 1482 nid.ni_cnd.cn_nameptr = cp; 1483 1484 error = lookup(&nid); 1485 if (error) 1486 break; 1487 if (nid.ni_vp->v_type != VCHR) 1488 dev = NULL; 1489 else 1490 dev = nid.ni_vp->v_rdev; 1491 NDFREE(&nid, 0); 1492 } while (0); 1493 1494 if (vroot != NULL) 1495 VFS_UNMOUNT(mp, 0, td); 1496 if (mp != NULL) 1497 vfs_mount_destroy(mp, td); 1498 return (dev); 1499} 1500 1501/* Show the struct cdev *for a disk specified by name */ 1502#ifdef DDB 1503DB_SHOW_COMMAND(disk, db_getdiskbyname) 1504{ 1505 struct cdev *dev; 1506 1507 if (modif[0] == '\0') { 1508 db_error("usage: show disk/devicename"); 1509 return; 1510 } 1511 dev = getdiskbyname(modif); 1512 if (dev != NULL) 1513 db_printf("struct cdev *= %p\n", dev); 1514 else 1515 db_printf("No disk device matched.\n"); 1516} 1517#endif 1518 1519/* 1520 * Get a mount option by its name. 1521 * 1522 * Return 0 if the option was found, ENOENT otherwise. 1523 * If len is non-NULL it will be filled with the length 1524 * of the option. If buf is non-NULL, it will be filled 1525 * with the address of the option. 1526 */ 1527int 1528vfs_getopt(opts, name, buf, len) 1529 struct vfsoptlist *opts; 1530 const char *name; 1531 void **buf; 1532 int *len; 1533{ 1534 struct vfsopt *opt; 1535 1536 KASSERT(opts != NULL, ("vfs_getopt: caller passed 'opts' as NULL")); 1537 1538 TAILQ_FOREACH(opt, opts, link) { 1539 if (strcmp(name, opt->name) == 0) { 1540 if (len != NULL) 1541 *len = opt->len; 1542 if (buf != NULL) 1543 *buf = opt->value; 1544 return (0); 1545 } 1546 } 1547 return (ENOENT); 1548} 1549 1550/* 1551 * Find and copy a mount option. 1552 * 1553 * The size of the buffer has to be specified 1554 * in len, if it is not the same length as the 1555 * mount option, EINVAL is returned. 1556 * Returns ENOENT if the option is not found. 1557 */ 1558int 1559vfs_copyopt(opts, name, dest, len) 1560 struct vfsoptlist *opts; 1561 const char *name; 1562 void *dest; 1563 int len; 1564{ 1565 struct vfsopt *opt; 1566 1567 KASSERT(opts != NULL, ("vfs_copyopt: caller passed 'opts' as NULL")); 1568 1569 TAILQ_FOREACH(opt, opts, link) { 1570 if (strcmp(name, opt->name) == 0) { 1571 if (len != opt->len) 1572 return (EINVAL); 1573 bcopy(opt->value, dest, opt->len); 1574 return (0); 1575 } 1576 } 1577 return (ENOENT); 1578} 1579 1580 1581/* 1582 * This is a helper function for filesystems to traverse their 1583 * vnodes. See MNT_VNODE_FOREACH() in sys/mount.h 1584 */ 1585 1586struct vnode * 1587__mnt_vnode_next(struct vnode **nvp, struct mount *mp) 1588{ 1589 struct vnode *vp; 1590 1591 mtx_assert(&mp->mnt_mtx, MA_OWNED); 1592 vp = *nvp; 1593 /* Check if we are done */ 1594 if (vp == NULL) 1595 return (NULL); 1596 /* If our next vnode is no longer ours, start over */ 1597 if (vp->v_mount != mp) 1598 vp = TAILQ_FIRST(&mp->mnt_nvnodelist); 1599 /* Save pointer to next vnode in list */ 1600 if (vp != NULL) 1601 *nvp = TAILQ_NEXT(vp, v_nmntvnodes); 1602 else 1603 *nvp = NULL; 1604 return (vp); 1605} 1606