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