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