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