vfs_mount.c revision 243719
190075Sobrien/*-
2110611Skan * Copyright (c) 1999-2004 Poul-Henning Kamp
390075Sobrien * Copyright (c) 1999 Michael Smith
490075Sobrien * Copyright (c) 1989, 1993
590075Sobrien *	The Regents of the University of California.  All rights reserved.
690075Sobrien * (c) UNIX System Laboratories, Inc.
790075Sobrien * All or some portions of this file are derived from material licensed
890075Sobrien * to the University of California by American Telephone and Telegraph
990075Sobrien * Co. or Unix System Laboratories, Inc. and are reproduced herein with
1090075Sobrien * the permission of UNIX System Laboratories, Inc.
1190075Sobrien *
1290075Sobrien * Redistribution and use in source and binary forms, with or without
1390075Sobrien * modification, are permitted provided that the following conditions
1490075Sobrien * are met:
1590075Sobrien * 1. Redistributions of source code must retain the above copyright
1690075Sobrien *    notice, this list of conditions and the following disclaimer.
1790075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1890075Sobrien *    notice, this list of conditions and the following disclaimer in the
1990075Sobrien *    documentation and/or other materials provided with the distribution.
2090075Sobrien * 4. Neither the name of the University nor the names of its contributors
2190075Sobrien *    may be used to endorse or promote products derived from this software
2290075Sobrien *    without specific prior written permission.
2390075Sobrien *
2490075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2590075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2690075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2790075Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2890075Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2990075Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3090075Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3190075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3290075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3390075Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3490075Sobrien * SUCH DAMAGE.
3590075Sobrien */
3690075Sobrien
3790075Sobrien#include <sys/cdefs.h>
3890075Sobrien__FBSDID("$FreeBSD: head/sys/kern/vfs_mount.c 243719 2012-11-30 22:49:28Z pjd $");
3990075Sobrien
4090075Sobrien#include <sys/param.h>
4190075Sobrien#include <sys/conf.h>
4290075Sobrien#include <sys/fcntl.h>
4390075Sobrien#include <sys/jail.h>
4490075Sobrien#include <sys/kernel.h>
4590075Sobrien#include <sys/libkern.h>
4690075Sobrien#include <sys/malloc.h>
4790075Sobrien#include <sys/mount.h>
4890075Sobrien#include <sys/mutex.h>
4990075Sobrien#include <sys/namei.h>
5090075Sobrien#include <sys/priv.h>
5190075Sobrien#include <sys/proc.h>
5290075Sobrien#include <sys/filedesc.h>
5390075Sobrien#include <sys/reboot.h>
5490075Sobrien#include <sys/sbuf.h>
5590075Sobrien#include <sys/syscallsubr.h>
5690075Sobrien#include <sys/sysproto.h>
5790075Sobrien#include <sys/sx.h>
5890075Sobrien#include <sys/sysctl.h>
5990075Sobrien#include <sys/sysent.h>
6090075Sobrien#include <sys/systm.h>
6190075Sobrien#include <sys/vnode.h>
6290075Sobrien#include <vm/uma.h>
6390075Sobrien
6490075Sobrien#include <geom/geom.h>
6590075Sobrien
6690075Sobrien#include <machine/stdarg.h>
6790075Sobrien
6890075Sobrien#include <security/audit/audit.h>
6990075Sobrien#include <security/mac/mac_framework.h>
7090075Sobrien
7190075Sobrien#define	VFS_MOUNTARG_SIZE_MAX	(1024 * 64)
7290075Sobrien
7390075Sobrienstatic int	vfs_domount(struct thread *td, const char *fstype, char *fspath,
7490075Sobrien		    uint64_t fsflags, struct vfsoptlist **optlist);
7590075Sobrienstatic void	free_mntarg(struct mntarg *ma);
7690075Sobrien
7790075Sobrienstatic int	usermount = 0;
7890075SobrienSYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0,
7990075Sobrien    "Unprivileged users may mount and unmount file systems");
8090075Sobrien
8190075SobrienMALLOC_DEFINE(M_MOUNT, "mount", "vfs mount structure");
8290075Sobrienstatic uma_zone_t mount_zone;
8390075Sobrien
8490075Sobrien/* List of mounted filesystems. */
8590075Sobrienstruct mntlist mountlist = TAILQ_HEAD_INITIALIZER(mountlist);
8690075Sobrien
8790075Sobrien/* For any iteration/modification of mountlist */
8890075Sobrienstruct mtx mountlist_mtx;
8990075SobrienMTX_SYSINIT(mountlist, &mountlist_mtx, "mountlist", MTX_DEF);
9090075Sobrien
9190075Sobrien/*
9290075Sobrien * Global opts, taken by all filesystems
9390075Sobrien */
9490075Sobrienstatic const char *global_opts[] = {
9590075Sobrien	"errmsg",
9690075Sobrien	"fstype",
9790075Sobrien	"fspath",
9890075Sobrien	"ro",
9990075Sobrien	"rw",
10090075Sobrien	"nosuid",
10190075Sobrien	"noexec",
10290075Sobrien	NULL
10390075Sobrien};
10490075Sobrien
10590075Sobrienstatic int
10690075Sobrienmount_init(void *mem, int size, int flags)
10790075Sobrien{
10890075Sobrien	struct mount *mp;
10990075Sobrien
11090075Sobrien	mp = (struct mount *)mem;
11190075Sobrien	mtx_init(&mp->mnt_mtx, "struct mount mtx", NULL, MTX_DEF);
11290075Sobrien	lockinit(&mp->mnt_explock, PVFS, "explock", 0, 0);
11390075Sobrien	return (0);
11490075Sobrien}
11590075Sobrien
11690075Sobrienstatic void
11790075Sobrienmount_fini(void *mem, int size)
11890075Sobrien{
11990075Sobrien	struct mount *mp;
12090075Sobrien
12190075Sobrien	mp = (struct mount *)mem;
12290075Sobrien	lockdestroy(&mp->mnt_explock);
12390075Sobrien	mtx_destroy(&mp->mnt_mtx);
12490075Sobrien}
12590075Sobrien
12690075Sobrienstatic void
12790075Sobrienvfs_mount_init(void *dummy __unused)
12890075Sobrien{
12990075Sobrien
13090075Sobrien	mount_zone = uma_zcreate("Mountpoints", sizeof(struct mount), NULL,
13190075Sobrien	    NULL, mount_init, mount_fini, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
13290075Sobrien}
13390075SobrienSYSINIT(vfs_mount, SI_SUB_VFS, SI_ORDER_ANY, vfs_mount_init, NULL);
13490075Sobrien
13590075Sobrien/*
13690075Sobrien * ---------------------------------------------------------------------
13790075Sobrien * Functions for building and sanitizing the mount options
13890075Sobrien */
13990075Sobrien
14090075Sobrien/* Remove one mount option. */
14190075Sobrienstatic void
14290075Sobrienvfs_freeopt(struct vfsoptlist *opts, struct vfsopt *opt)
14390075Sobrien{
14490075Sobrien
14590075Sobrien	TAILQ_REMOVE(opts, opt, link);
14690075Sobrien	free(opt->name, M_MOUNT);
14790075Sobrien	if (opt->value != NULL)
14890075Sobrien		free(opt->value, M_MOUNT);
14990075Sobrien	free(opt, M_MOUNT);
15090075Sobrien}
15190075Sobrien
15290075Sobrien/* Release all resources related to the mount options. */
15390075Sobrienvoid
15490075Sobrienvfs_freeopts(struct vfsoptlist *opts)
15590075Sobrien{
15690075Sobrien	struct vfsopt *opt;
15790075Sobrien
15890075Sobrien	while (!TAILQ_EMPTY(opts)) {
15990075Sobrien		opt = TAILQ_FIRST(opts);
16090075Sobrien		vfs_freeopt(opts, opt);
16190075Sobrien	}
16290075Sobrien	free(opts, M_MOUNT);
16390075Sobrien}
16490075Sobrien
16590075Sobrienvoid
16690075Sobrienvfs_deleteopt(struct vfsoptlist *opts, const char *name)
16790075Sobrien{
16890075Sobrien	struct vfsopt *opt, *temp;
16990075Sobrien
17090075Sobrien	if (opts == NULL)
17190075Sobrien		return;
17290075Sobrien	TAILQ_FOREACH_SAFE(opt, opts, link, temp)  {
17390075Sobrien		if (strcmp(opt->name, name) == 0)
17490075Sobrien			vfs_freeopt(opts, opt);
17590075Sobrien	}
17690075Sobrien}
17790075Sobrien
17890075Sobrienstatic int
17990075Sobrienvfs_isopt_ro(const char *opt)
18090075Sobrien{
18190075Sobrien
18290075Sobrien	if (strcmp(opt, "ro") == 0 || strcmp(opt, "rdonly") == 0 ||
18390075Sobrien	    strcmp(opt, "norw") == 0)
18490075Sobrien		return (1);
18590075Sobrien	return (0);
18690075Sobrien}
18790075Sobrien
18890075Sobrienstatic int
18990075Sobrienvfs_isopt_rw(const char *opt)
19090075Sobrien{
19190075Sobrien
19290075Sobrien	if (strcmp(opt, "rw") == 0 || strcmp(opt, "noro") == 0)
19390075Sobrien		return (1);
19490075Sobrien	return (0);
19590075Sobrien}
19690075Sobrien
19790075Sobrien/*
19890075Sobrien * Check if options are equal (with or without the "no" prefix).
19990075Sobrien */
20096263Sobrienstatic int
20196263Sobrienvfs_equalopts(const char *opt1, const char *opt2)
20290075Sobrien{
20390075Sobrien	char *p;
20490075Sobrien
20590075Sobrien	/* "opt" vs. "opt" or "noopt" vs. "noopt" */
20690075Sobrien	if (strcmp(opt1, opt2) == 0)
20790075Sobrien		return (1);
20890075Sobrien	/* "noopt" vs. "opt" */
20990075Sobrien	if (strncmp(opt1, "no", 2) == 0 && strcmp(opt1 + 2, opt2) == 0)
21090075Sobrien		return (1);
21190075Sobrien	/* "opt" vs. "noopt" */
21290075Sobrien	if (strncmp(opt2, "no", 2) == 0 && strcmp(opt1, opt2 + 2) == 0)
21390075Sobrien		return (1);
21490075Sobrien	while ((p = strchr(opt1, '.')) != NULL &&
21590075Sobrien	    !strncmp(opt1, opt2, ++p - opt1)) {
21690075Sobrien		opt2 += p - opt1;
21790075Sobrien		opt1 = p;
21890075Sobrien		/* "foo.noopt" vs. "foo.opt" */
21990075Sobrien		if (strncmp(opt1, "no", 2) == 0 && strcmp(opt1 + 2, opt2) == 0)
22090075Sobrien			return (1);
22190075Sobrien		/* "foo.opt" vs. "foo.noopt" */
22290075Sobrien		if (strncmp(opt2, "no", 2) == 0 && strcmp(opt1, opt2 + 2) == 0)
22390075Sobrien			return (1);
22490075Sobrien	}
22590075Sobrien	/* "ro" / "rdonly" / "norw" / "rw" / "noro" */
22690075Sobrien	if ((vfs_isopt_ro(opt1) || vfs_isopt_rw(opt1)) &&
22790075Sobrien	    (vfs_isopt_ro(opt2) || vfs_isopt_rw(opt2)))
22890075Sobrien		return (1);
22990075Sobrien	return (0);
23090075Sobrien}
23190075Sobrien
23290075Sobrien/*
23390075Sobrien * If a mount option is specified several times,
23490075Sobrien * (with or without the "no" prefix) only keep
23590075Sobrien * the last occurence of it.
23690075Sobrien */
23790075Sobrienstatic void
23890075Sobrienvfs_sanitizeopts(struct vfsoptlist *opts)
23990075Sobrien{
24090075Sobrien	struct vfsopt *opt, *opt2, *tmp;
24190075Sobrien
24290075Sobrien	TAILQ_FOREACH_REVERSE(opt, opts, vfsoptlist, link) {
24390075Sobrien		opt2 = TAILQ_PREV(opt, vfsoptlist, link);
24490075Sobrien		while (opt2 != NULL) {
24590075Sobrien			if (vfs_equalopts(opt->name, opt2->name)) {
24690075Sobrien				tmp = TAILQ_PREV(opt2, vfsoptlist, link);
24790075Sobrien				vfs_freeopt(opts, opt2);
24890075Sobrien				opt2 = tmp;
24990075Sobrien			} else {
25090075Sobrien				opt2 = TAILQ_PREV(opt2, vfsoptlist, link);
25190075Sobrien			}
25290075Sobrien		}
25390075Sobrien	}
25490075Sobrien}
25590075Sobrien
25690075Sobrien/*
25790075Sobrien * Build a linked list of mount options from a struct uio.
25890075Sobrien */
25990075Sobrienint
26090075Sobrienvfs_buildopts(struct uio *auio, struct vfsoptlist **options)
26190075Sobrien{
26290075Sobrien	struct vfsoptlist *opts;
26390075Sobrien	struct vfsopt *opt;
26490075Sobrien	size_t memused, namelen, optlen;
26590075Sobrien	unsigned int i, iovcnt;
26690075Sobrien	int error;
26790075Sobrien
26890075Sobrien	opts = malloc(sizeof(struct vfsoptlist), M_MOUNT, M_WAITOK);
26990075Sobrien	TAILQ_INIT(opts);
27090075Sobrien	memused = 0;
27190075Sobrien	iovcnt = auio->uio_iovcnt;
27290075Sobrien	for (i = 0; i < iovcnt; i += 2) {
27390075Sobrien		namelen = auio->uio_iov[i].iov_len;
27490075Sobrien		optlen = auio->uio_iov[i + 1].iov_len;
27590075Sobrien		memused += sizeof(struct vfsopt) + optlen + namelen;
27690075Sobrien		/*
27790075Sobrien		 * Avoid consuming too much memory, and attempts to overflow
27890075Sobrien		 * memused.
27990075Sobrien		 */
28090075Sobrien		if (memused > VFS_MOUNTARG_SIZE_MAX ||
28190075Sobrien		    optlen > VFS_MOUNTARG_SIZE_MAX ||
28290075Sobrien		    namelen > VFS_MOUNTARG_SIZE_MAX) {
28390075Sobrien			error = EINVAL;
28490075Sobrien			goto bad;
28590075Sobrien		}
28690075Sobrien
28790075Sobrien		opt = malloc(sizeof(struct vfsopt), M_MOUNT, M_WAITOK);
28890075Sobrien		opt->name = malloc(namelen, M_MOUNT, M_WAITOK);
28990075Sobrien		opt->value = NULL;
29090075Sobrien		opt->len = 0;
29190075Sobrien		opt->pos = i / 2;
29290075Sobrien		opt->seen = 0;
29390075Sobrien
29490075Sobrien		/*
29590075Sobrien		 * Do this early, so jumps to "bad" will free the current
29690075Sobrien		 * option.
29790075Sobrien		 */
29890075Sobrien		TAILQ_INSERT_TAIL(opts, opt, link);
29990075Sobrien
30090075Sobrien		if (auio->uio_segflg == UIO_SYSSPACE) {
30190075Sobrien			bcopy(auio->uio_iov[i].iov_base, opt->name, namelen);
30290075Sobrien		} else {
30390075Sobrien			error = copyin(auio->uio_iov[i].iov_base, opt->name,
30490075Sobrien			    namelen);
30590075Sobrien			if (error)
30690075Sobrien				goto bad;
30790075Sobrien		}
30890075Sobrien		/* Ensure names are null-terminated strings. */
30990075Sobrien		if (namelen == 0 || opt->name[namelen - 1] != '\0') {
31090075Sobrien			error = EINVAL;
31190075Sobrien			goto bad;
31290075Sobrien		}
31390075Sobrien		if (optlen != 0) {
31490075Sobrien			opt->len = optlen;
31590075Sobrien			opt->value = malloc(optlen, M_MOUNT, M_WAITOK);
31690075Sobrien			if (auio->uio_segflg == UIO_SYSSPACE) {
31790075Sobrien				bcopy(auio->uio_iov[i + 1].iov_base, opt->value,
31890075Sobrien				    optlen);
31990075Sobrien			} else {
32090075Sobrien				error = copyin(auio->uio_iov[i + 1].iov_base,
32190075Sobrien				    opt->value, optlen);
32290075Sobrien				if (error)
32390075Sobrien					goto bad;
32490075Sobrien			}
32590075Sobrien		}
32690075Sobrien	}
32790075Sobrien	vfs_sanitizeopts(opts);
32890075Sobrien	*options = opts;
32990075Sobrien	return (0);
33090075Sobrienbad:
33190075Sobrien	vfs_freeopts(opts);
33290075Sobrien	return (error);
33390075Sobrien}
33490075Sobrien
33590075Sobrien/*
33690075Sobrien * Merge the old mount options with the new ones passed
33790075Sobrien * in the MNT_UPDATE case.
33890075Sobrien *
33990075Sobrien * XXX: This function will keep a "nofoo" option in the new
34090075Sobrien * options.  E.g, if the option's canonical name is "foo",
34190075Sobrien * "nofoo" ends up in the mount point's active options.
34290075Sobrien */
34390075Sobrienstatic void
34490075Sobrienvfs_mergeopts(struct vfsoptlist *toopts, struct vfsoptlist *oldopts)
34590075Sobrien{
34690075Sobrien	struct vfsopt *opt, *new;
34790075Sobrien
34890075Sobrien	TAILQ_FOREACH(opt, oldopts, link) {
34990075Sobrien		new = malloc(sizeof(struct vfsopt), M_MOUNT, M_WAITOK);
35090075Sobrien		new->name = strdup(opt->name, M_MOUNT);
35190075Sobrien		if (opt->len != 0) {
35290075Sobrien			new->value = malloc(opt->len, M_MOUNT, M_WAITOK);
35390075Sobrien			bcopy(opt->value, new->value, opt->len);
35490075Sobrien		} else
35590075Sobrien			new->value = NULL;
35690075Sobrien		new->len = opt->len;
35790075Sobrien		new->seen = opt->seen;
35890075Sobrien		TAILQ_INSERT_HEAD(toopts, new, link);
35990075Sobrien	}
36090075Sobrien	vfs_sanitizeopts(toopts);
36190075Sobrien}
36290075Sobrien
36390075Sobrien/*
36490075Sobrien * Mount a filesystem.
36590075Sobrien */
36690075Sobrienint
36790075Sobriensys_nmount(td, uap)
36890075Sobrien	struct thread *td;
36990075Sobrien	struct nmount_args /* {
37090075Sobrien		struct iovec *iovp;
37190075Sobrien		unsigned int iovcnt;
37290075Sobrien		int flags;
37390075Sobrien	} */ *uap;
37490075Sobrien{
37590075Sobrien	struct uio *auio;
37690075Sobrien	int error;
37790075Sobrien	u_int iovcnt;
37890075Sobrien	uint64_t flags;
37990075Sobrien
38090075Sobrien	/*
38190075Sobrien	 * Mount flags are now 64-bits. On 32-bit archtectures only
38290075Sobrien	 * 32-bits are passed in, but from here on everything handles
38390075Sobrien	 * 64-bit flags correctly.
38490075Sobrien	 */
38590075Sobrien	flags = uap->flags;
38690075Sobrien
38790075Sobrien	AUDIT_ARG_FFLAGS(flags);
38896263Sobrien	CTR4(KTR_VFS, "%s: iovp %p with iovcnt %d and flags %d", __func__,
38990075Sobrien	    uap->iovp, uap->iovcnt, flags);
39090075Sobrien
39190075Sobrien	/*
39290075Sobrien	 * Filter out MNT_ROOTFS.  We do not want clients of nmount() in
39390075Sobrien	 * userspace to set this flag, but we must filter it out if we want
39490075Sobrien	 * MNT_UPDATE on the root file system to work.
39590075Sobrien	 * MNT_ROOTFS should only be set by the kernel when mounting its
39690075Sobrien	 * root file system.
39790075Sobrien	 */
39890075Sobrien	flags &= ~MNT_ROOTFS;
39990075Sobrien
40090075Sobrien	iovcnt = uap->iovcnt;
40190075Sobrien	/*
40296263Sobrien	 * Check that we have an even number of iovec's
40396263Sobrien	 * and that we have at least two options.
40490075Sobrien	 */
40590075Sobrien	if ((iovcnt & 1) || (iovcnt < 4)) {
40690075Sobrien		CTR2(KTR_VFS, "%s: failed for invalid iovcnt %d", __func__,
40790075Sobrien		    uap->iovcnt);
40890075Sobrien		return (EINVAL);
40990075Sobrien	}
41090075Sobrien
41190075Sobrien	error = copyinuio(uap->iovp, iovcnt, &auio);
41290075Sobrien	if (error) {
41390075Sobrien		CTR2(KTR_VFS, "%s: failed for invalid uio op with %d errno",
41490075Sobrien		    __func__, error);
41590075Sobrien		return (error);
41690075Sobrien	}
41790075Sobrien	error = vfs_donmount(td, flags, auio);
41890075Sobrien
41990075Sobrien	free(auio, M_IOV);
42090075Sobrien	return (error);
42190075Sobrien}
42290075Sobrien
42390075Sobrien/*
42490075Sobrien * ---------------------------------------------------------------------
42590075Sobrien * Various utility functions
42690075Sobrien */
42790075Sobrien
42890075Sobrienvoid
42990075Sobrienvfs_ref(struct mount *mp)
43090075Sobrien{
43190075Sobrien
43290075Sobrien	CTR2(KTR_VFS, "%s: mp %p", __func__, mp);
43390075Sobrien	MNT_ILOCK(mp);
43490075Sobrien	MNT_REF(mp);
43590075Sobrien	MNT_IUNLOCK(mp);
43690075Sobrien}
43790075Sobrien
43890075Sobrienvoid
43990075Sobrienvfs_rel(struct mount *mp)
44090075Sobrien{
44190075Sobrien
44290075Sobrien	CTR2(KTR_VFS, "%s: mp %p", __func__, mp);
44390075Sobrien	MNT_ILOCK(mp);
44490075Sobrien	MNT_REL(mp);
44590075Sobrien	MNT_IUNLOCK(mp);
44690075Sobrien}
44790075Sobrien
44890075Sobrien/*
44990075Sobrien * Allocate and initialize the mount point struct.
45090075Sobrien */
45190075Sobrienstruct mount *
45290075Sobrienvfs_mount_alloc(struct vnode *vp, struct vfsconf *vfsp, const char *fspath,
45390075Sobrien    struct ucred *cred)
45490075Sobrien{
45590075Sobrien	struct mount *mp;
45690075Sobrien
45790075Sobrien	mp = uma_zalloc(mount_zone, M_WAITOK);
45890075Sobrien	bzero(&mp->mnt_startzero,
45990075Sobrien	    __rangeof(struct mount, mnt_startzero, mnt_endzero));
46090075Sobrien	TAILQ_INIT(&mp->mnt_nvnodelist);
46190075Sobrien	mp->mnt_nvnodelistsize = 0;
46290075Sobrien	TAILQ_INIT(&mp->mnt_activevnodelist);
46390075Sobrien	mp->mnt_activevnodelistsize = 0;
46490075Sobrien	mp->mnt_ref = 0;
46590075Sobrien	(void) vfs_busy(mp, MBF_NOWAIT);
46690075Sobrien	mp->mnt_op = vfsp->vfc_vfsops;
46790075Sobrien	mp->mnt_vfc = vfsp;
46890075Sobrien	vfsp->vfc_refcount++;	/* XXX Unlocked */
46990075Sobrien	mp->mnt_stat.f_type = vfsp->vfc_typenum;
47090075Sobrien	mp->mnt_gen++;
47190075Sobrien	strlcpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
47290075Sobrien	mp->mnt_vnodecovered = vp;
47390075Sobrien	mp->mnt_cred = crdup(cred);
47490075Sobrien	mp->mnt_stat.f_owner = cred->cr_uid;
47590075Sobrien	strlcpy(mp->mnt_stat.f_mntonname, fspath, MNAMELEN);
47690075Sobrien	mp->mnt_iosize_max = DFLTPHYS;
47790075Sobrien#ifdef MAC
47890075Sobrien	mac_mount_init(mp);
47990075Sobrien	mac_mount_create(cred, mp);
48090075Sobrien#endif
48190075Sobrien	arc4rand(&mp->mnt_hashseed, sizeof mp->mnt_hashseed, 0);
48290075Sobrien	TAILQ_INIT(&mp->mnt_uppers);
48390075Sobrien	return (mp);
48490075Sobrien}
48590075Sobrien
48690075Sobrien/*
48790075Sobrien * Destroy the mount struct previously allocated by vfs_mount_alloc().
48890075Sobrien */
48990075Sobrienvoid
49090075Sobrienvfs_mount_destroy(struct mount *mp)
49190075Sobrien{
49290075Sobrien
49390075Sobrien	MNT_ILOCK(mp);
49490075Sobrien	mp->mnt_kern_flag |= MNTK_REFEXPIRE;
49590075Sobrien	if (mp->mnt_kern_flag & MNTK_MWAIT) {
49690075Sobrien		mp->mnt_kern_flag &= ~MNTK_MWAIT;
49790075Sobrien		wakeup(mp);
49890075Sobrien	}
49990075Sobrien	while (mp->mnt_ref)
50090075Sobrien		msleep(mp, MNT_MTX(mp), PVFS, "mntref", 0);
50190075Sobrien	KASSERT(mp->mnt_ref == 0,
50290075Sobrien	    ("%s: invalid refcount in the drain path @ %s:%d", __func__,
50390075Sobrien	    __FILE__, __LINE__));
50490075Sobrien	if (mp->mnt_writeopcount != 0)
50590075Sobrien		panic("vfs_mount_destroy: nonzero writeopcount");
50690075Sobrien	if (mp->mnt_secondary_writes != 0)
50790075Sobrien		panic("vfs_mount_destroy: nonzero secondary_writes");
50890075Sobrien	mp->mnt_vfc->vfc_refcount--;
50990075Sobrien	if (!TAILQ_EMPTY(&mp->mnt_nvnodelist)) {
51090075Sobrien		struct vnode *vp;
51190075Sobrien
51290075Sobrien		TAILQ_FOREACH(vp, &mp->mnt_nvnodelist, v_nmntvnodes)
51390075Sobrien			vprint("", vp);
51490075Sobrien		panic("unmount: dangling vnode");
51590075Sobrien	}
51690075Sobrien	KASSERT(TAILQ_EMPTY(&mp->mnt_uppers), ("mnt_uppers"));
51790075Sobrien	if (mp->mnt_nvnodelistsize != 0)
51890075Sobrien		panic("vfs_mount_destroy: nonzero nvnodelistsize");
51990075Sobrien	if (mp->mnt_activevnodelistsize != 0)
52090075Sobrien		panic("vfs_mount_destroy: nonzero activevnodelistsize");
52190075Sobrien	if (mp->mnt_lockref != 0)
52290075Sobrien		panic("vfs_mount_destroy: nonzero lock refcount");
52390075Sobrien	MNT_IUNLOCK(mp);
52490075Sobrien#ifdef MAC
52590075Sobrien	mac_mount_destroy(mp);
52690075Sobrien#endif
52790075Sobrien	if (mp->mnt_opt != NULL)
52890075Sobrien		vfs_freeopts(mp->mnt_opt);
52990075Sobrien	crfree(mp->mnt_cred);
53090075Sobrien	uma_zfree(mount_zone, mp);
53190075Sobrien}
53290075Sobrien
53390075Sobrienint
53490075Sobrienvfs_donmount(struct thread *td, uint64_t fsflags, struct uio *fsoptions)
53590075Sobrien{
53690075Sobrien	struct vfsoptlist *optlist;
53790075Sobrien	struct vfsopt *opt, *tmp_opt;
53890075Sobrien	char *fstype, *fspath, *errmsg;
53990075Sobrien	int error, fstypelen, fspathlen, errmsg_len, errmsg_pos;
54090075Sobrien
54190075Sobrien	errmsg = fspath = NULL;
54290075Sobrien	errmsg_len = fspathlen = 0;
54390075Sobrien	errmsg_pos = -1;
54490075Sobrien
54590075Sobrien	error = vfs_buildopts(fsoptions, &optlist);
54690075Sobrien	if (error)
54790075Sobrien		return (error);
54890075Sobrien
54990075Sobrien	if (vfs_getopt(optlist, "errmsg", (void **)&errmsg, &errmsg_len) == 0)
55090075Sobrien		errmsg_pos = vfs_getopt_pos(optlist, "errmsg");
55190075Sobrien
55290075Sobrien	/*
55390075Sobrien	 * We need these two options before the others,
55490075Sobrien	 * and they are mandatory for any filesystem.
55590075Sobrien	 * Ensure they are NUL terminated as well.
55690075Sobrien	 */
55790075Sobrien	fstypelen = 0;
55890075Sobrien	error = vfs_getopt(optlist, "fstype", (void **)&fstype, &fstypelen);
55990075Sobrien	if (error || fstype[fstypelen - 1] != '\0') {
56090075Sobrien		error = EINVAL;
56190075Sobrien		if (errmsg != NULL)
56290075Sobrien			strncpy(errmsg, "Invalid fstype", errmsg_len);
56390075Sobrien		goto bail;
56490075Sobrien	}
56590075Sobrien	fspathlen = 0;
56690075Sobrien	error = vfs_getopt(optlist, "fspath", (void **)&fspath, &fspathlen);
56790075Sobrien	if (error || fspath[fspathlen - 1] != '\0') {
56890075Sobrien		error = EINVAL;
56990075Sobrien		if (errmsg != NULL)
57090075Sobrien			strncpy(errmsg, "Invalid fspath", errmsg_len);
57190075Sobrien		goto bail;
57290075Sobrien	}
57390075Sobrien
57490075Sobrien	/*
57590075Sobrien	 * We need to see if we have the "update" option
57690075Sobrien	 * before we call vfs_domount(), since vfs_domount() has special
57790075Sobrien	 * logic based on MNT_UPDATE.  This is very important
57890075Sobrien	 * when we want to update the root filesystem.
57990075Sobrien	 */
58090075Sobrien	TAILQ_FOREACH_SAFE(opt, optlist, link, tmp_opt) {
58190075Sobrien		if (strcmp(opt->name, "update") == 0) {
58290075Sobrien			fsflags |= MNT_UPDATE;
58390075Sobrien			vfs_freeopt(optlist, opt);
58490075Sobrien		}
58590075Sobrien		else if (strcmp(opt->name, "async") == 0)
58690075Sobrien			fsflags |= MNT_ASYNC;
58790075Sobrien		else if (strcmp(opt->name, "force") == 0) {
58890075Sobrien			fsflags |= MNT_FORCE;
58990075Sobrien			vfs_freeopt(optlist, opt);
59090075Sobrien		}
59190075Sobrien		else if (strcmp(opt->name, "reload") == 0) {
59290075Sobrien			fsflags |= MNT_RELOAD;
59390075Sobrien			vfs_freeopt(optlist, opt);
59490075Sobrien		}
59590075Sobrien		else if (strcmp(opt->name, "multilabel") == 0)
59690075Sobrien			fsflags |= MNT_MULTILABEL;
59790075Sobrien		else if (strcmp(opt->name, "noasync") == 0)
59890075Sobrien			fsflags &= ~MNT_ASYNC;
59990075Sobrien		else if (strcmp(opt->name, "noatime") == 0)
60090075Sobrien			fsflags |= MNT_NOATIME;
60190075Sobrien		else if (strcmp(opt->name, "atime") == 0) {
60290075Sobrien			free(opt->name, M_MOUNT);
60390075Sobrien			opt->name = strdup("nonoatime", M_MOUNT);
60490075Sobrien		}
60590075Sobrien		else if (strcmp(opt->name, "noclusterr") == 0)
60690075Sobrien			fsflags |= MNT_NOCLUSTERR;
60790075Sobrien		else if (strcmp(opt->name, "clusterr") == 0) {
60890075Sobrien			free(opt->name, M_MOUNT);
60990075Sobrien			opt->name = strdup("nonoclusterr", M_MOUNT);
61090075Sobrien		}
61190075Sobrien		else if (strcmp(opt->name, "noclusterw") == 0)
61290075Sobrien			fsflags |= MNT_NOCLUSTERW;
61390075Sobrien		else if (strcmp(opt->name, "clusterw") == 0) {
61490075Sobrien			free(opt->name, M_MOUNT);
61590075Sobrien			opt->name = strdup("nonoclusterw", M_MOUNT);
61690075Sobrien		}
61790075Sobrien		else if (strcmp(opt->name, "noexec") == 0)
61890075Sobrien			fsflags |= MNT_NOEXEC;
61990075Sobrien		else if (strcmp(opt->name, "exec") == 0) {
62090075Sobrien			free(opt->name, M_MOUNT);
62190075Sobrien			opt->name = strdup("nonoexec", M_MOUNT);
62290075Sobrien		}
62390075Sobrien		else if (strcmp(opt->name, "nosuid") == 0)
62490075Sobrien			fsflags |= MNT_NOSUID;
62590075Sobrien		else if (strcmp(opt->name, "suid") == 0) {
62690075Sobrien			free(opt->name, M_MOUNT);
62790075Sobrien			opt->name = strdup("nonosuid", M_MOUNT);
62890075Sobrien		}
62990075Sobrien		else if (strcmp(opt->name, "nosymfollow") == 0)
63090075Sobrien			fsflags |= MNT_NOSYMFOLLOW;
63190075Sobrien		else if (strcmp(opt->name, "symfollow") == 0) {
63290075Sobrien			free(opt->name, M_MOUNT);
63390075Sobrien			opt->name = strdup("nonosymfollow", M_MOUNT);
63490075Sobrien		}
63590075Sobrien		else if (strcmp(opt->name, "noro") == 0)
63690075Sobrien			fsflags &= ~MNT_RDONLY;
63790075Sobrien		else if (strcmp(opt->name, "rw") == 0)
63890075Sobrien			fsflags &= ~MNT_RDONLY;
63990075Sobrien		else if (strcmp(opt->name, "ro") == 0)
64090075Sobrien			fsflags |= MNT_RDONLY;
64190075Sobrien		else if (strcmp(opt->name, "rdonly") == 0) {
64290075Sobrien			free(opt->name, M_MOUNT);
64390075Sobrien			opt->name = strdup("ro", M_MOUNT);
64490075Sobrien			fsflags |= MNT_RDONLY;
64590075Sobrien		}
64690075Sobrien		else if (strcmp(opt->name, "suiddir") == 0)
64790075Sobrien			fsflags |= MNT_SUIDDIR;
64890075Sobrien		else if (strcmp(opt->name, "sync") == 0)
64990075Sobrien			fsflags |= MNT_SYNCHRONOUS;
65090075Sobrien		else if (strcmp(opt->name, "union") == 0)
65190075Sobrien			fsflags |= MNT_UNION;
65290075Sobrien	}
65390075Sobrien
65490075Sobrien	/*
65590075Sobrien	 * Be ultra-paranoid about making sure the type and fspath
65690075Sobrien	 * variables will fit in our mp buffers, including the
65790075Sobrien	 * terminating NUL.
65890075Sobrien	 */
65990075Sobrien	if (fstypelen >= MFSNAMELEN - 1 || fspathlen >= MNAMELEN - 1) {
66090075Sobrien		error = ENAMETOOLONG;
66190075Sobrien		goto bail;
66290075Sobrien	}
66390075Sobrien
66490075Sobrien	error = vfs_domount(td, fstype, fspath, fsflags, &optlist);
66590075Sobrienbail:
66690075Sobrien	/* copyout the errmsg */
66790075Sobrien	if (errmsg_pos != -1 && ((2 * errmsg_pos + 1) < fsoptions->uio_iovcnt)
66890075Sobrien	    && errmsg_len > 0 && errmsg != NULL) {
66990075Sobrien		if (fsoptions->uio_segflg == UIO_SYSSPACE) {
67090075Sobrien			bcopy(errmsg,
67190075Sobrien			    fsoptions->uio_iov[2 * errmsg_pos + 1].iov_base,
67290075Sobrien			    fsoptions->uio_iov[2 * errmsg_pos + 1].iov_len);
67390075Sobrien		} else {
67490075Sobrien			copyout(errmsg,
67590075Sobrien			    fsoptions->uio_iov[2 * errmsg_pos + 1].iov_base,
67690075Sobrien			    fsoptions->uio_iov[2 * errmsg_pos + 1].iov_len);
67790075Sobrien		}
67890075Sobrien	}
67990075Sobrien
68090075Sobrien	if (optlist != NULL)
68190075Sobrien		vfs_freeopts(optlist);
68290075Sobrien	return (error);
68390075Sobrien}
68490075Sobrien
68590075Sobrien/*
68690075Sobrien * Old mount API.
68790075Sobrien */
68890075Sobrien#ifndef _SYS_SYSPROTO_H_
68990075Sobrienstruct mount_args {
69090075Sobrien	char	*type;
69190075Sobrien	char	*path;
69290075Sobrien	int	flags;
69390075Sobrien	caddr_t	data;
69490075Sobrien};
69590075Sobrien#endif
69690075Sobrien/* ARGSUSED */
69790075Sobrienint
69890075Sobriensys_mount(td, uap)
69990075Sobrien	struct thread *td;
70090075Sobrien	struct mount_args /* {
70190075Sobrien		char *type;
70290075Sobrien		char *path;
70390075Sobrien		int flags;
70490075Sobrien		caddr_t data;
70590075Sobrien	} */ *uap;
70690075Sobrien{
70790075Sobrien	char *fstype;
70890075Sobrien	struct vfsconf *vfsp = NULL;
70990075Sobrien	struct mntarg *ma = NULL;
71090075Sobrien	uint64_t flags;
71190075Sobrien	int error;
71290075Sobrien
71390075Sobrien	/*
71490075Sobrien	 * Mount flags are now 64-bits. On 32-bit archtectures only
71590075Sobrien	 * 32-bits are passed in, but from here on everything handles
71690075Sobrien	 * 64-bit flags correctly.
71790075Sobrien	 */
71890075Sobrien	flags = uap->flags;
71990075Sobrien
72090075Sobrien	AUDIT_ARG_FFLAGS(flags);
72190075Sobrien
72290075Sobrien	/*
72390075Sobrien	 * Filter out MNT_ROOTFS.  We do not want clients of mount() in
72490075Sobrien	 * userspace to set this flag, but we must filter it out if we want
72590075Sobrien	 * MNT_UPDATE on the root file system to work.
72690075Sobrien	 * MNT_ROOTFS should only be set by the kernel when mounting its
72790075Sobrien	 * root file system.
72890075Sobrien	 */
72990075Sobrien	flags &= ~MNT_ROOTFS;
73090075Sobrien
73190075Sobrien	fstype = malloc(MFSNAMELEN, M_TEMP, M_WAITOK);
73290075Sobrien	error = copyinstr(uap->type, fstype, MFSNAMELEN, NULL);
73390075Sobrien	if (error) {
73490075Sobrien		free(fstype, M_TEMP);
73590075Sobrien		return (error);
73690075Sobrien	}
73790075Sobrien
73890075Sobrien	AUDIT_ARG_TEXT(fstype);
73990075Sobrien	mtx_lock(&Giant);
74090075Sobrien	vfsp = vfs_byname_kld(fstype, td, &error);
74190075Sobrien	free(fstype, M_TEMP);
74290075Sobrien	if (vfsp == NULL) {
74390075Sobrien		mtx_unlock(&Giant);
74490075Sobrien		return (ENOENT);
74590075Sobrien	}
74690075Sobrien	if (vfsp->vfc_vfsops->vfs_cmount == NULL) {
74790075Sobrien		mtx_unlock(&Giant);
74890075Sobrien		return (EOPNOTSUPP);
74990075Sobrien	}
75090075Sobrien
75190075Sobrien	ma = mount_argsu(ma, "fstype", uap->type, MNAMELEN);
75290075Sobrien	ma = mount_argsu(ma, "fspath", uap->path, MNAMELEN);
75390075Sobrien	ma = mount_argb(ma, flags & MNT_RDONLY, "noro");
75490075Sobrien	ma = mount_argb(ma, !(flags & MNT_NOSUID), "nosuid");
75590075Sobrien	ma = mount_argb(ma, !(flags & MNT_NOEXEC), "noexec");
75690075Sobrien
75790075Sobrien	error = vfsp->vfc_vfsops->vfs_cmount(ma, uap->data, flags);
75890075Sobrien	mtx_unlock(&Giant);
75990075Sobrien	return (error);
76090075Sobrien}
76190075Sobrien
76290075Sobrien/*
76390075Sobrien * vfs_domount_first(): first file system mount (not update)
76490075Sobrien */
76590075Sobrienstatic int
76690075Sobrienvfs_domount_first(
76790075Sobrien	struct thread *td,		/* Calling thread. */
76890075Sobrien	struct vfsconf *vfsp,		/* File system type. */
76990075Sobrien	char *fspath,			/* Mount path. */
77090075Sobrien	struct vnode *vp,		/* Vnode to be covered. */
77190075Sobrien	uint64_t fsflags,		/* Flags common to all filesystems. */
77290075Sobrien	struct vfsoptlist **optlist	/* Options local to the filesystem. */
773103445Skan	)
774103445Skan{
775103445Skan	struct vattr va;
776103445Skan	struct mount *mp;
777103445Skan	struct vnode *newdp;
778103445Skan	int error;
779103445Skan
780103445Skan	mtx_assert(&Giant, MA_OWNED);
781103445Skan	ASSERT_VOP_ELOCKED(vp, __func__);
782103445Skan	KASSERT((fsflags & MNT_UPDATE) == 0, ("MNT_UPDATE shouldn't be here"));
783103445Skan
784103445Skan	/*
785103445Skan	 * If the user is not root, ensure that they own the directory
786103445Skan	 * onto which we are attempting to mount.
787103445Skan	 */
788103445Skan	error = VOP_GETATTR(vp, &va, td->td_ucred);
789103445Skan	if (error == 0 && va.va_uid != td->td_ucred->cr_uid)
790103445Skan		error = priv_check_cred(td->td_ucred, PRIV_VFS_ADMIN, 0);
791103445Skan	if (error == 0)
792103445Skan		error = vinvalbuf(vp, V_SAVE, 0, 0);
793103445Skan	if (error == 0 && vp->v_type != VDIR)
794103445Skan		error = ENOTDIR;
795103445Skan	if (error == 0) {
796103445Skan		VI_LOCK(vp);
797103445Skan		if ((vp->v_iflag & VI_MOUNT) == 0 && vp->v_mountedhere == NULL)
798103445Skan			vp->v_iflag |= VI_MOUNT;
799103445Skan		else
800103445Skan			error = EBUSY;
801103445Skan		VI_UNLOCK(vp);
802103445Skan	}
803103445Skan	if (error != 0) {
804103445Skan		vput(vp);
80590075Sobrien		return (error);
80690075Sobrien	}
80790075Sobrien	VOP_UNLOCK(vp, 0);
80890075Sobrien
80990075Sobrien	/* Allocate and initialize the filesystem. */
81090075Sobrien	mp = vfs_mount_alloc(vp, vfsp, fspath, td->td_ucred);
81190075Sobrien	/* XXXMAC: pass to vfs_mount_alloc? */
81290075Sobrien	mp->mnt_optnew = *optlist;
81390075Sobrien	/* Set the mount level flags. */
81490075Sobrien	mp->mnt_flag = (fsflags & (MNT_UPDATEMASK | MNT_ROOTFS | MNT_RDONLY));
81590075Sobrien
81690075Sobrien	/*
81790075Sobrien	 * Mount the filesystem.
81890075Sobrien	 * XXX The final recipients of VFS_MOUNT just overwrite the ndp they
81990075Sobrien	 * get.  No freeing of cn_pnbuf.
82090075Sobrien	 */
82190075Sobrien	error = VFS_MOUNT(mp);
82290075Sobrien	if (error != 0) {
82390075Sobrien		vfs_unbusy(mp);
82490075Sobrien		vfs_mount_destroy(mp);
82590075Sobrien		VI_LOCK(vp);
82690075Sobrien		vp->v_iflag &= ~VI_MOUNT;
82790075Sobrien		VI_UNLOCK(vp);
82890075Sobrien		vrele(vp);
82990075Sobrien		return (error);
83090075Sobrien	}
83190075Sobrien
83290075Sobrien	if (mp->mnt_opt != NULL)
83390075Sobrien		vfs_freeopts(mp->mnt_opt);
83490075Sobrien	mp->mnt_opt = mp->mnt_optnew;
83590075Sobrien	*optlist = NULL;
83690075Sobrien	(void)VFS_STATFS(mp, &mp->mnt_stat);
83790075Sobrien
83890075Sobrien	/*
83990075Sobrien	 * Prevent external consumers of mount options from reading mnt_optnew.
84090075Sobrien	 */
84190075Sobrien	mp->mnt_optnew = NULL;
84290075Sobrien
84390075Sobrien	MNT_ILOCK(mp);
84490075Sobrien	if ((mp->mnt_flag & MNT_ASYNC) != 0 &&
84590075Sobrien	    (mp->mnt_kern_flag & MNTK_NOASYNC) == 0)
84690075Sobrien		mp->mnt_kern_flag |= MNTK_ASYNC;
84790075Sobrien	else
84890075Sobrien		mp->mnt_kern_flag &= ~MNTK_ASYNC;
84990075Sobrien	MNT_IUNLOCK(mp);
85090075Sobrien
85190075Sobrien	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
85290075Sobrien	cache_purge(vp);
85390075Sobrien	VI_LOCK(vp);
85490075Sobrien	vp->v_iflag &= ~VI_MOUNT;
85590075Sobrien	VI_UNLOCK(vp);
85690075Sobrien	vp->v_mountedhere = mp;
85790075Sobrien	/* Place the new filesystem at the end of the mount list. */
85890075Sobrien	mtx_lock(&mountlist_mtx);
85990075Sobrien	TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
86090075Sobrien	mtx_unlock(&mountlist_mtx);
86190075Sobrien	vfs_event_signal(NULL, VQ_MOUNT, 0);
86290075Sobrien	if (VFS_ROOT(mp, LK_EXCLUSIVE, &newdp))
86390075Sobrien		panic("mount: lost mount");
86490075Sobrien	VOP_UNLOCK(newdp, 0);
86590075Sobrien	VOP_UNLOCK(vp, 0);
86690075Sobrien	mountcheckdirs(vp, newdp);
86790075Sobrien	vrele(newdp);
86890075Sobrien	if ((mp->mnt_flag & MNT_RDONLY) == 0)
86990075Sobrien		vfs_allocate_syncvnode(mp);
87090075Sobrien	vfs_unbusy(mp);
87190075Sobrien	return (0);
87290075Sobrien}
87390075Sobrien
87490075Sobrien/*
87590075Sobrien * vfs_domount_update(): update of mounted file system
87690075Sobrien */
87790075Sobrienstatic int
87890075Sobrienvfs_domount_update(
87990075Sobrien	struct thread *td,		/* Calling thread. */
88090075Sobrien	struct vnode *vp,		/* Mount point vnode. */
88190075Sobrien	uint64_t fsflags,		/* Flags common to all filesystems. */
88290075Sobrien	struct vfsoptlist **optlist	/* Options local to the filesystem. */
88390075Sobrien	)
88490075Sobrien{
88590075Sobrien	struct oexport_args oexport;
88690075Sobrien	struct export_args export;
88790075Sobrien	struct mount *mp;
88890075Sobrien	int error, export_error;
88990075Sobrien	uint64_t flag;
89090075Sobrien
89190075Sobrien	mtx_assert(&Giant, MA_OWNED);
89290075Sobrien	ASSERT_VOP_ELOCKED(vp, __func__);
89390075Sobrien	KASSERT((fsflags & MNT_UPDATE) != 0, ("MNT_UPDATE should be here"));
89490075Sobrien
89590075Sobrien	if ((vp->v_vflag & VV_ROOT) == 0) {
89690075Sobrien		vput(vp);
89790075Sobrien		return (EINVAL);
89890075Sobrien	}
89990075Sobrien	mp = vp->v_mount;
90090075Sobrien	/*
90190075Sobrien	 * We only allow the filesystem to be reloaded if it
90290075Sobrien	 * is currently mounted read-only.
90390075Sobrien	 */
90490075Sobrien	flag = mp->mnt_flag;
90590075Sobrien	if ((fsflags & MNT_RELOAD) != 0 && (flag & MNT_RDONLY) == 0) {
90690075Sobrien		vput(vp);
90790075Sobrien		return (EOPNOTSUPP);	/* Needs translation */
90890075Sobrien	}
90990075Sobrien	/*
91090075Sobrien	 * Only privileged root, or (if MNT_USER is set) the user that
91190075Sobrien	 * did the original mount is permitted to update it.
91290075Sobrien	 */
91390075Sobrien	error = vfs_suser(mp, td);
91496263Sobrien	if (error != 0) {
91590075Sobrien		vput(vp);
91690075Sobrien		return (error);
91790075Sobrien	}
91890075Sobrien	if (vfs_busy(mp, MBF_NOWAIT)) {
91990075Sobrien		vput(vp);
92090075Sobrien		return (EBUSY);
92190075Sobrien	}
92290075Sobrien	VI_LOCK(vp);
92390075Sobrien	if ((vp->v_iflag & VI_MOUNT) != 0 || vp->v_mountedhere != NULL) {
92490075Sobrien		VI_UNLOCK(vp);
92590075Sobrien		vfs_unbusy(mp);
92690075Sobrien		vput(vp);
92796263Sobrien		return (EBUSY);
92890075Sobrien	}
92990075Sobrien	vp->v_iflag |= VI_MOUNT;
93090075Sobrien	VI_UNLOCK(vp);
93190075Sobrien	VOP_UNLOCK(vp, 0);
93290075Sobrien
93390075Sobrien	MNT_ILOCK(mp);
93490075Sobrien	mp->mnt_flag &= ~MNT_UPDATEMASK;
93590075Sobrien	mp->mnt_flag |= fsflags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE |
93690075Sobrien	    MNT_SNAPSHOT | MNT_ROOTFS | MNT_UPDATEMASK | MNT_RDONLY);
93790075Sobrien	if ((mp->mnt_flag & MNT_ASYNC) == 0)
93896263Sobrien		mp->mnt_kern_flag &= ~MNTK_ASYNC;
93990075Sobrien	MNT_IUNLOCK(mp);
94096263Sobrien	mp->mnt_optnew = *optlist;
94190075Sobrien	vfs_mergeopts(mp->mnt_optnew, mp->mnt_opt);
94296263Sobrien
94390075Sobrien	/*
94490075Sobrien	 * Mount the filesystem.
94590075Sobrien	 * XXX The final recipients of VFS_MOUNT just overwrite the ndp they
94690075Sobrien	 * get.  No freeing of cn_pnbuf.
94790075Sobrien	 */
94890075Sobrien	error = VFS_MOUNT(mp);
94990075Sobrien
95090075Sobrien	export_error = 0;
95196263Sobrien	if (error == 0) {
95290075Sobrien		/* Process the export option. */
95390075Sobrien		if (vfs_copyopt(mp->mnt_optnew, "export", &export,
95490075Sobrien		    sizeof(export)) == 0) {
95590075Sobrien			export_error = vfs_export(mp, &export);
95690075Sobrien		} else if (vfs_copyopt(mp->mnt_optnew, "export", &oexport,
95790075Sobrien		    sizeof(oexport)) == 0) {
95890075Sobrien			export.ex_flags = oexport.ex_flags;
95990075Sobrien			export.ex_root = oexport.ex_root;
96090075Sobrien			export.ex_anon = oexport.ex_anon;
96190075Sobrien			export.ex_addr = oexport.ex_addr;
96290075Sobrien			export.ex_addrlen = oexport.ex_addrlen;
96390075Sobrien			export.ex_mask = oexport.ex_mask;
96490075Sobrien			export.ex_masklen = oexport.ex_masklen;
96590075Sobrien			export.ex_indexfile = oexport.ex_indexfile;
96690075Sobrien			export.ex_numsecflavors = 0;
96790075Sobrien			export_error = vfs_export(mp, &export);
96890075Sobrien		}
96990075Sobrien	}
97090075Sobrien
97190075Sobrien	MNT_ILOCK(mp);
97290075Sobrien	if (error == 0) {
97390075Sobrien		mp->mnt_flag &=	~(MNT_UPDATE | MNT_RELOAD | MNT_FORCE |
97490075Sobrien		    MNT_SNAPSHOT);
97590075Sobrien	} else {
97690075Sobrien		/*
97790075Sobrien		 * If we fail, restore old mount flags. MNT_QUOTA is special,
97890075Sobrien		 * because it is not part of MNT_UPDATEMASK, but it could have
97990075Sobrien		 * changed in the meantime if quotactl(2) was called.
98090075Sobrien		 * All in all we want current value of MNT_QUOTA, not the old
98190075Sobrien		 * one.
98296263Sobrien		 */
98390075Sobrien		mp->mnt_flag = (mp->mnt_flag & MNT_QUOTA) | (flag & ~MNT_QUOTA);
98496263Sobrien	}
98596263Sobrien	if ((mp->mnt_flag & MNT_ASYNC) != 0 &&
98690075Sobrien	    (mp->mnt_kern_flag & MNTK_NOASYNC) == 0)
98790075Sobrien		mp->mnt_kern_flag |= MNTK_ASYNC;
98890075Sobrien	else
98990075Sobrien		mp->mnt_kern_flag &= ~MNTK_ASYNC;
99090075Sobrien	MNT_IUNLOCK(mp);
99190075Sobrien
99290075Sobrien	if (error != 0)
99390075Sobrien		goto end;
99490075Sobrien
99590075Sobrien	if (mp->mnt_opt != NULL)
99690075Sobrien		vfs_freeopts(mp->mnt_opt);
99790075Sobrien	mp->mnt_opt = mp->mnt_optnew;
99890075Sobrien	*optlist = NULL;
99990075Sobrien	(void)VFS_STATFS(mp, &mp->mnt_stat);
100090075Sobrien	/*
100190075Sobrien	 * Prevent external consumers of mount options from reading
100290075Sobrien	 * mnt_optnew.
100390075Sobrien	 */
100490075Sobrien	mp->mnt_optnew = NULL;
100590075Sobrien
100690075Sobrien	if ((mp->mnt_flag & MNT_RDONLY) == 0)
100790075Sobrien		vfs_allocate_syncvnode(mp);
100890075Sobrien	else
100990075Sobrien		vfs_deallocate_syncvnode(mp);
101090075Sobrienend:
101190075Sobrien	vfs_unbusy(mp);
101290075Sobrien	VI_LOCK(vp);
101390075Sobrien	vp->v_iflag &= ~VI_MOUNT;
101490075Sobrien	VI_UNLOCK(vp);
101590075Sobrien	vrele(vp);
101690075Sobrien	return (error != 0 ? error : export_error);
101790075Sobrien}
101890075Sobrien
101990075Sobrien/*
102090075Sobrien * vfs_domount(): actually attempt a filesystem mount.
102190075Sobrien */
102290075Sobrienstatic int
102390075Sobrienvfs_domount(
102490075Sobrien	struct thread *td,		/* Calling thread. */
102590075Sobrien	const char *fstype,		/* Filesystem type. */
102690075Sobrien	char *fspath,			/* Mount path. */
102790075Sobrien	uint64_t fsflags,		/* Flags common to all filesystems. */
102890075Sobrien	struct vfsoptlist **optlist	/* Options local to the filesystem. */
102990075Sobrien	)
103090075Sobrien{
103190075Sobrien	struct vfsconf *vfsp;
103290075Sobrien	struct nameidata nd;
103390075Sobrien	struct vnode *vp;
103490075Sobrien	char *pathbuf;
103590075Sobrien	int error;
103690075Sobrien
103790075Sobrien	/*
103890075Sobrien	 * Be ultra-paranoid about making sure the type and fspath
103996263Sobrien	 * variables will fit in our mp buffers, including the
104090075Sobrien	 * terminating NUL.
104196263Sobrien	 */
104290075Sobrien	if (strlen(fstype) >= MFSNAMELEN || strlen(fspath) >= MNAMELEN)
104390075Sobrien		return (ENAMETOOLONG);
104490075Sobrien
104590075Sobrien	if (jailed(td->td_ucred) || usermount == 0) {
104690075Sobrien		if ((error = priv_check(td, PRIV_VFS_MOUNT)) != 0)
104790075Sobrien			return (error);
104890075Sobrien	}
104990075Sobrien
105090075Sobrien	/*
105190075Sobrien	 * Do not allow NFS export or MNT_SUIDDIR by unprivileged users.
105290075Sobrien	 */
105390075Sobrien	if (fsflags & MNT_EXPORTED) {
105490075Sobrien		error = priv_check(td, PRIV_VFS_MOUNT_EXPORTED);
105590075Sobrien		if (error)
105690075Sobrien			return (error);
105790075Sobrien	}
105890075Sobrien	if (fsflags & MNT_SUIDDIR) {
105990075Sobrien		error = priv_check(td, PRIV_VFS_MOUNT_SUIDDIR);
106090075Sobrien		if (error)
106190075Sobrien			return (error);
106290075Sobrien	}
106390075Sobrien	/*
106490075Sobrien	 * Silently enforce MNT_NOSUID and MNT_USER for unprivileged users.
106590075Sobrien	 */
106690075Sobrien	if ((fsflags & (MNT_NOSUID | MNT_USER)) != (MNT_NOSUID | MNT_USER)) {
106790075Sobrien		if (priv_check(td, PRIV_VFS_MOUNT_NONUSER) != 0)
106890075Sobrien			fsflags |= MNT_NOSUID | MNT_USER;
106990075Sobrien	}
107090075Sobrien
107190075Sobrien	/* Load KLDs before we lock the covered vnode to avoid reversals. */
107290075Sobrien	vfsp = NULL;
107390075Sobrien	if ((fsflags & MNT_UPDATE) == 0) {
107490075Sobrien		/* Don't try to load KLDs if we're mounting the root. */
107590075Sobrien		if (fsflags & MNT_ROOTFS)
107690075Sobrien			vfsp = vfs_byname(fstype);
107790075Sobrien		else
107890075Sobrien			vfsp = vfs_byname_kld(fstype, td, &error);
107990075Sobrien		if (vfsp == NULL)
108090075Sobrien			return (ENODEV);
108190075Sobrien		if (jailed(td->td_ucred) && !(vfsp->vfc_flags & VFCF_JAIL))
108290075Sobrien			return (EPERM);
108390075Sobrien	}
108490075Sobrien
108590075Sobrien	/*
108696263Sobrien	 * Get vnode to be covered or mount point's vnode in case of MNT_UPDATE.
108790075Sobrien	 */
108890075Sobrien	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1,
108990075Sobrien	    UIO_SYSSPACE, fspath, td);
109096263Sobrien	error = namei(&nd);
109190075Sobrien	if (error != 0)
109290075Sobrien		return (error);
109390075Sobrien	mtx_lock(&Giant);
109490075Sobrien	NDFREE(&nd, NDF_ONLY_PNBUF);
109590075Sobrien	vp = nd.ni_vp;
109690075Sobrien	if ((fsflags & MNT_UPDATE) == 0) {
109790075Sobrien		pathbuf = malloc(MNAMELEN, M_TEMP, M_WAITOK);
109890075Sobrien		strcpy(pathbuf, fspath);
109990075Sobrien		error = vn_path_to_global_path(td, vp, pathbuf, MNAMELEN);
110090075Sobrien		/* debug.disablefullpath == 1 results in ENODEV */
110190075Sobrien		if (error == 0 || error == ENODEV) {
110290075Sobrien			error = vfs_domount_first(td, vfsp, pathbuf, vp,
110396263Sobrien			    fsflags, optlist);
110490075Sobrien		}
110596263Sobrien		free(pathbuf, M_TEMP);
110690075Sobrien	} else
110790075Sobrien		error = vfs_domount_update(td, vp, fsflags, optlist);
110890075Sobrien	mtx_unlock(&Giant);
110990075Sobrien
111090075Sobrien	ASSERT_VI_UNLOCKED(vp, __func__);
111190075Sobrien	ASSERT_VOP_UNLOCKED(vp, __func__);
111290075Sobrien
111390075Sobrien	return (error);
111490075Sobrien}
111590075Sobrien
111690075Sobrien/*
111790075Sobrien * Unmount a filesystem.
111896263Sobrien *
111990075Sobrien * Note: unmount takes a path to the vnode mounted on as argument, not
112096263Sobrien * special file (as before).
112190075Sobrien */
112290075Sobrien#ifndef _SYS_SYSPROTO_H_
112390075Sobrienstruct unmount_args {
112490075Sobrien	char	*path;
112590075Sobrien	int	flags;
112690075Sobrien};
112790075Sobrien#endif
112890075Sobrien/* ARGSUSED */
112990075Sobrienint
113090075Sobriensys_unmount(td, uap)
113190075Sobrien	struct thread *td;
113290075Sobrien	register struct unmount_args /* {
113396263Sobrien		char *path;
113490075Sobrien		int flags;
113596263Sobrien	} */ *uap;
113690075Sobrien{
113790075Sobrien	struct nameidata nd;
113890075Sobrien	struct mount *mp;
113990075Sobrien	char *pathbuf;
114090075Sobrien	int error, id0, id1;
114196263Sobrien
114290075Sobrien	AUDIT_ARG_VALUE(uap->flags);
114390075Sobrien	if (jailed(td->td_ucred) || usermount == 0) {
114490075Sobrien		error = priv_check(td, PRIV_VFS_UNMOUNT);
114590075Sobrien		if (error)
114690075Sobrien			return (error);
114790075Sobrien	}
114896263Sobrien
114990075Sobrien	pathbuf = malloc(MNAMELEN, M_TEMP, M_WAITOK);
115090075Sobrien	error = copyinstr(uap->path, pathbuf, MNAMELEN, NULL);
115196263Sobrien	if (error) {
115290075Sobrien		free(pathbuf, M_TEMP);
115390075Sobrien		return (error);
115490075Sobrien	}
115590075Sobrien	mtx_lock(&Giant);
115690075Sobrien	if (uap->flags & MNT_BYFSID) {
115790075Sobrien		AUDIT_ARG_TEXT(pathbuf);
115890075Sobrien		/* Decode the filesystem ID. */
115990075Sobrien		if (sscanf(pathbuf, "FSID:%d:%d", &id0, &id1) != 2) {
116090075Sobrien			mtx_unlock(&Giant);
116190075Sobrien			free(pathbuf, M_TEMP);
116290075Sobrien			return (EINVAL);
116390075Sobrien		}
116490075Sobrien
116590075Sobrien		mtx_lock(&mountlist_mtx);
116690075Sobrien		TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) {
116790075Sobrien			if (mp->mnt_stat.f_fsid.val[0] == id0 &&
116890075Sobrien			    mp->mnt_stat.f_fsid.val[1] == id1)
116990075Sobrien				break;
117090075Sobrien		}
117190075Sobrien		mtx_unlock(&mountlist_mtx);
117290075Sobrien	} else {
117390075Sobrien		/*
117490075Sobrien		 * Try to find global path for path argument.
117590075Sobrien		 */
117690075Sobrien		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1,
117790075Sobrien		    UIO_SYSSPACE, pathbuf, td);
117890075Sobrien		if (namei(&nd) == 0) {
117990075Sobrien			NDFREE(&nd, NDF_ONLY_PNBUF);
118090075Sobrien			error = vn_path_to_global_path(td, nd.ni_vp, pathbuf,
118190075Sobrien			    MNAMELEN);
118290075Sobrien			if (error == 0 || error == ENODEV)
118390075Sobrien				vput(nd.ni_vp);
118490075Sobrien		}
118590075Sobrien		mtx_lock(&mountlist_mtx);
118690075Sobrien		TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) {
118790075Sobrien			if (strcmp(mp->mnt_stat.f_mntonname, pathbuf) == 0)
118890075Sobrien				break;
118990075Sobrien		}
119090075Sobrien		mtx_unlock(&mountlist_mtx);
119190075Sobrien	}
119290075Sobrien	free(pathbuf, M_TEMP);
119390075Sobrien	if (mp == NULL) {
119490075Sobrien		/*
119590075Sobrien		 * Previously we returned ENOENT for a nonexistent path and
119690075Sobrien		 * EINVAL for a non-mountpoint.  We cannot tell these apart
119790075Sobrien		 * now, so in the !MNT_BYFSID case return the more likely
119890075Sobrien		 * EINVAL for compatibility.
119990075Sobrien		 */
120090075Sobrien		mtx_unlock(&Giant);
120190075Sobrien		return ((uap->flags & MNT_BYFSID) ? ENOENT : EINVAL);
120290075Sobrien	}
120390075Sobrien
120490075Sobrien	/*
120590075Sobrien	 * Don't allow unmounting the root filesystem.
120690075Sobrien	 */
120790075Sobrien	if (mp->mnt_flag & MNT_ROOTFS) {
120890075Sobrien		mtx_unlock(&Giant);
120990075Sobrien		return (EINVAL);
121090075Sobrien	}
121190075Sobrien	error = dounmount(mp, uap->flags, td);
121290075Sobrien	mtx_unlock(&Giant);
121390075Sobrien	return (error);
121490075Sobrien}
121590075Sobrien
121690075Sobrien/*
121790075Sobrien * Do the actual filesystem unmount.
121890075Sobrien */
121990075Sobrienint
122090075Sobriendounmount(mp, flags, td)
122190075Sobrien	struct mount *mp;
122290075Sobrien	int flags;
122390075Sobrien	struct thread *td;
122490075Sobrien{
122590075Sobrien	struct vnode *coveredvp, *fsrootvp;
122690075Sobrien	int error;
122790075Sobrien	uint64_t async_flag;
122890075Sobrien	int mnt_gen_r;
122990075Sobrien
123090075Sobrien	mtx_assert(&Giant, MA_OWNED);
123196263Sobrien
123290075Sobrien	if ((coveredvp = mp->mnt_vnodecovered) != NULL) {
123390075Sobrien		mnt_gen_r = mp->mnt_gen;
123490075Sobrien		VI_LOCK(coveredvp);
123590075Sobrien		vholdl(coveredvp);
123696263Sobrien		vn_lock(coveredvp, LK_EXCLUSIVE | LK_INTERLOCK | LK_RETRY);
123796263Sobrien		vdrop(coveredvp);
123896263Sobrien		/*
123996263Sobrien		 * Check for mp being unmounted while waiting for the
124096263Sobrien		 * covered vnode lock.
124196263Sobrien		 */
124296263Sobrien		if (coveredvp->v_mountedhere != mp ||
124390075Sobrien		    coveredvp->v_mountedhere->mnt_gen != mnt_gen_r) {
124490075Sobrien			VOP_UNLOCK(coveredvp, 0);
124590075Sobrien			return (EBUSY);
124690075Sobrien		}
124790075Sobrien	}
124890075Sobrien	/*
124990075Sobrien	 * Only privileged root, or (if MNT_USER is set) the user that did the
125090075Sobrien	 * original mount is permitted to unmount this filesystem.
125190075Sobrien	 */
125290075Sobrien	error = vfs_suser(mp, td);
125396263Sobrien	if (error) {
125496263Sobrien		if (coveredvp)
125596263Sobrien			VOP_UNLOCK(coveredvp, 0);
125696263Sobrien		return (error);
125790075Sobrien	}
125896263Sobrien
125996263Sobrien	MNT_ILOCK(mp);
126096263Sobrien	if ((mp->mnt_kern_flag & MNTK_UNMOUNT) != 0 ||
126196263Sobrien	    !TAILQ_EMPTY(&mp->mnt_uppers)) {
126296263Sobrien		MNT_IUNLOCK(mp);
126390075Sobrien		if (coveredvp)
126490075Sobrien			VOP_UNLOCK(coveredvp, 0);
126596263Sobrien		return (EBUSY);
126696263Sobrien	}
126796263Sobrien	mp->mnt_kern_flag |= MNTK_UNMOUNT | MNTK_NOINSMNTQ;
126896263Sobrien	/* Allow filesystems to detect that a forced unmount is in progress. */
126996263Sobrien	if (flags & MNT_FORCE)
127090075Sobrien		mp->mnt_kern_flag |= MNTK_UNMOUNTF;
127190075Sobrien	error = 0;
127290075Sobrien	if (mp->mnt_lockref) {
127396263Sobrien		mp->mnt_kern_flag |= MNTK_DRAINING;
127496263Sobrien		error = msleep(&mp->mnt_lockref, MNT_MTX(mp), PVFS,
127596263Sobrien		    "mount drain", 0);
127696263Sobrien	}
127796263Sobrien	MNT_IUNLOCK(mp);
127896263Sobrien	KASSERT(mp->mnt_lockref == 0,
127996263Sobrien	    ("%s: invalid lock refcount in the drain path @ %s:%d",
128096263Sobrien	    __func__, __FILE__, __LINE__));
128196263Sobrien	KASSERT(error == 0,
128296263Sobrien	    ("%s: invalid return value for msleep in the drain path @ %s:%d",
128396263Sobrien	    __func__, __FILE__, __LINE__));
128496263Sobrien	vn_start_write(NULL, &mp, V_WAIT);
128596263Sobrien
128696263Sobrien	if (mp->mnt_flag & MNT_EXPUBLIC)
128796263Sobrien		vfs_setpublicfs(NULL, NULL, NULL);
128896263Sobrien
128996263Sobrien	vfs_msync(mp, MNT_WAIT);
129096263Sobrien	MNT_ILOCK(mp);
129196263Sobrien	async_flag = mp->mnt_flag & MNT_ASYNC;
129296263Sobrien	mp->mnt_flag &= ~MNT_ASYNC;
129396263Sobrien	mp->mnt_kern_flag &= ~MNTK_ASYNC;
129496263Sobrien	MNT_IUNLOCK(mp);
129596263Sobrien	cache_purgevfs(mp);	/* remove cache entries for this file sys */
129696263Sobrien	vfs_deallocate_syncvnode(mp);
129796263Sobrien	/*
129890075Sobrien	 * For forced unmounts, move process cdir/rdir refs on the fs root
129990075Sobrien	 * vnode to the covered vnode.  For non-forced unmounts we want
130090075Sobrien	 * such references to cause an EBUSY error.
130190075Sobrien	 */
130290075Sobrien	if ((flags & MNT_FORCE) &&
130390075Sobrien	    VFS_ROOT(mp, LK_EXCLUSIVE, &fsrootvp) == 0) {
130490075Sobrien		if (mp->mnt_vnodecovered != NULL)
130590075Sobrien			mountcheckdirs(fsrootvp, mp->mnt_vnodecovered);
130690075Sobrien		if (fsrootvp == rootvnode) {
130790075Sobrien			vrele(rootvnode);
130890075Sobrien			rootvnode = NULL;
130990075Sobrien		}
131090075Sobrien		vput(fsrootvp);
131190075Sobrien	}
131290075Sobrien	if (((mp->mnt_flag & MNT_RDONLY) ||
131390075Sobrien	     (error = VFS_SYNC(mp, MNT_WAIT)) == 0) || (flags & MNT_FORCE) != 0)
131490075Sobrien		error = VFS_UNMOUNT(mp, flags);
131590075Sobrien	vn_finished_write(mp);
131690075Sobrien	/*
131790075Sobrien	 * If we failed to flush the dirty blocks for this mount point,
131890075Sobrien	 * undo all the cdir/rdir and rootvnode changes we made above.
131990075Sobrien	 * Unless we failed to do so because the device is reporting that
132090075Sobrien	 * it doesn't exist anymore.
1321110611Skan	 */
1322110611Skan	if (error && error != ENXIO) {
1323110611Skan		if ((flags & MNT_FORCE) &&
1324110611Skan		    VFS_ROOT(mp, LK_EXCLUSIVE, &fsrootvp) == 0) {
1325110611Skan			if (mp->mnt_vnodecovered != NULL)
1326110611Skan				mountcheckdirs(mp->mnt_vnodecovered, fsrootvp);
1327110611Skan			if (rootvnode == NULL) {
1328110611Skan				rootvnode = fsrootvp;
1329110611Skan				vref(rootvnode);
1330110611Skan			}
1331110611Skan			vput(fsrootvp);
1332110611Skan		}
1333110611Skan		MNT_ILOCK(mp);
1334110611Skan		mp->mnt_kern_flag &= ~MNTK_NOINSMNTQ;
1335110611Skan		if ((mp->mnt_flag & MNT_RDONLY) == 0) {
133690075Sobrien			MNT_IUNLOCK(mp);
133790075Sobrien			vfs_allocate_syncvnode(mp);
133890075Sobrien			MNT_ILOCK(mp);
133990075Sobrien		}
134090075Sobrien		mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF);
134190075Sobrien		mp->mnt_flag |= async_flag;
134290075Sobrien		if ((mp->mnt_flag & MNT_ASYNC) != 0 &&
134390075Sobrien		    (mp->mnt_kern_flag & MNTK_NOASYNC) == 0)
134490075Sobrien			mp->mnt_kern_flag |= MNTK_ASYNC;
134590075Sobrien		if (mp->mnt_kern_flag & MNTK_MWAIT) {
134690075Sobrien			mp->mnt_kern_flag &= ~MNTK_MWAIT;
134790075Sobrien			wakeup(mp);
134890075Sobrien		}
134990075Sobrien		MNT_IUNLOCK(mp);
135090075Sobrien		if (coveredvp)
135190075Sobrien			VOP_UNLOCK(coveredvp, 0);
135290075Sobrien		return (error);
135390075Sobrien	}
135490075Sobrien	mtx_lock(&mountlist_mtx);
135590075Sobrien	TAILQ_REMOVE(&mountlist, mp, mnt_list);
135690075Sobrien	mtx_unlock(&mountlist_mtx);
135790075Sobrien	if (coveredvp != NULL) {
135890075Sobrien		coveredvp->v_mountedhere = NULL;
135990075Sobrien		vput(coveredvp);
136090075Sobrien	}
136190075Sobrien	vfs_event_signal(NULL, VQ_UNMOUNT, 0);
136290075Sobrien	vfs_mount_destroy(mp);
136390075Sobrien	return (0);
136490075Sobrien}
136590075Sobrien
136690075Sobrien/*
136790075Sobrien * Report errors during filesystem mounting.
136890075Sobrien */
136990075Sobrienvoid
137090075Sobrienvfs_mount_error(struct mount *mp, const char *fmt, ...)
137190075Sobrien{
137290075Sobrien	struct vfsoptlist *moptlist = mp->mnt_optnew;
137390075Sobrien	va_list ap;
137490075Sobrien	int error, len;
137590075Sobrien	char *errmsg;
137690075Sobrien
137790075Sobrien	error = vfs_getopt(moptlist, "errmsg", (void **)&errmsg, &len);
137890075Sobrien	if (error || errmsg == NULL || len <= 0)
137990075Sobrien		return;
138090075Sobrien
138190075Sobrien	va_start(ap, fmt);
138290075Sobrien	vsnprintf(errmsg, (size_t)len, fmt, ap);
138390075Sobrien	va_end(ap);
138490075Sobrien}
138590075Sobrien
138690075Sobrienvoid
138790075Sobrienvfs_opterror(struct vfsoptlist *opts, const char *fmt, ...)
138890075Sobrien{
138990075Sobrien	va_list ap;
139090075Sobrien	int error, len;
139196263Sobrien	char *errmsg;
139290075Sobrien
139390075Sobrien	error = vfs_getopt(opts, "errmsg", (void **)&errmsg, &len);
139490075Sobrien	if (error || errmsg == NULL || len <= 0)
139590075Sobrien		return;
139690075Sobrien
139790075Sobrien	va_start(ap, fmt);
139890075Sobrien	vsnprintf(errmsg, (size_t)len, fmt, ap);
139990075Sobrien	va_end(ap);
140090075Sobrien}
140196263Sobrien
140290075Sobrien/*
140390075Sobrien * ---------------------------------------------------------------------
140490075Sobrien * Functions for querying mount options/arguments from filesystems.
140590075Sobrien */
140690075Sobrien
140790075Sobrien/*
140890075Sobrien * Check that no unknown options are given
140990075Sobrien */
141090075Sobrienint
141196263Sobrienvfs_filteropt(struct vfsoptlist *opts, const char **legal)
141290075Sobrien{
141390075Sobrien	struct vfsopt *opt;
141490075Sobrien	char errmsg[255];
141590075Sobrien	const char **t, *p, *q;
141690075Sobrien	int ret = 0;
141790075Sobrien
141890075Sobrien	TAILQ_FOREACH(opt, opts, link) {
141990075Sobrien		p = opt->name;
142090075Sobrien		q = NULL;
142190075Sobrien		if (p[0] == 'n' && p[1] == 'o')
142290075Sobrien			q = p + 2;
142390075Sobrien		for(t = global_opts; *t != NULL; t++) {
142490075Sobrien			if (strcmp(*t, p) == 0)
142596263Sobrien				break;
142690075Sobrien			if (q != NULL) {
142790075Sobrien				if (strcmp(*t, q) == 0)
142890075Sobrien					break;
142990075Sobrien			}
143090075Sobrien		}
143190075Sobrien		if (*t != NULL)
143290075Sobrien			continue;
143390075Sobrien		for(t = legal; *t != NULL; t++) {
143490075Sobrien			if (strcmp(*t, p) == 0)
143590075Sobrien				break;
143690075Sobrien			if (q != NULL) {
143796263Sobrien				if (strcmp(*t, q) == 0)
143890075Sobrien					break;
143990075Sobrien			}
144090075Sobrien		}
144190075Sobrien		if (*t != NULL)
144290075Sobrien			continue;
144390075Sobrien		snprintf(errmsg, sizeof(errmsg),
144490075Sobrien		    "mount option <%s> is unknown", p);
144590075Sobrien		ret = EINVAL;
144690075Sobrien	}
144790075Sobrien	if (ret != 0) {
144890075Sobrien		TAILQ_FOREACH(opt, opts, link) {
144990075Sobrien			if (strcmp(opt->name, "errmsg") == 0) {
145090075Sobrien				strncpy((char *)opt->value, errmsg, opt->len);
145190075Sobrien				break;
145290075Sobrien			}
145396263Sobrien		}
145490075Sobrien		if (opt == NULL)
145590075Sobrien			printf("%s\n", errmsg);
145690075Sobrien	}
1457110611Skan	return (ret);
145890075Sobrien}
145990075Sobrien
146090075Sobrien/*
146190075Sobrien * Get a mount option by its name.
146290075Sobrien *
146390075Sobrien * Return 0 if the option was found, ENOENT otherwise.
146490075Sobrien * If len is non-NULL it will be filled with the length
146590075Sobrien * of the option. If buf is non-NULL, it will be filled
146690075Sobrien * with the address of the option.
146790075Sobrien */
146890075Sobrienint
146990075Sobrienvfs_getopt(opts, name, buf, len)
147090075Sobrien	struct vfsoptlist *opts;
147190075Sobrien	const char *name;
147290075Sobrien	void **buf;
147390075Sobrien	int *len;
147490075Sobrien{
147590075Sobrien	struct vfsopt *opt;
147690075Sobrien
147790075Sobrien	KASSERT(opts != NULL, ("vfs_getopt: caller passed 'opts' as NULL"));
147890075Sobrien
147990075Sobrien	TAILQ_FOREACH(opt, opts, link) {
148090075Sobrien		if (strcmp(name, opt->name) == 0) {
148190075Sobrien			opt->seen = 1;
148290075Sobrien			if (len != NULL)
148390075Sobrien				*len = opt->len;
148490075Sobrien			if (buf != NULL)
148590075Sobrien				*buf = opt->value;
148690075Sobrien			return (0);
148790075Sobrien		}
148890075Sobrien	}
148990075Sobrien	return (ENOENT);
149090075Sobrien}
149190075Sobrien
149290075Sobrienint
149390075Sobrienvfs_getopt_pos(struct vfsoptlist *opts, const char *name)
149490075Sobrien{
149590075Sobrien	struct vfsopt *opt;
149690075Sobrien
149790075Sobrien	if (opts == NULL)
149890075Sobrien		return (-1);
149990075Sobrien
150090075Sobrien	TAILQ_FOREACH(opt, opts, link) {
150190075Sobrien		if (strcmp(name, opt->name) == 0) {
150290075Sobrien			opt->seen = 1;
150390075Sobrien			return (opt->pos);
150490075Sobrien		}
150590075Sobrien	}
150690075Sobrien	return (-1);
150790075Sobrien}
150890075Sobrien
150990075Sobrienint
151090075Sobrienvfs_getopt_size(struct vfsoptlist *opts, const char *name, off_t *value)
151190075Sobrien{
151290075Sobrien	char *opt_value, *vtp;
151390075Sobrien	quad_t iv;
151490075Sobrien	int error, opt_len;
151590075Sobrien
151690075Sobrien	error = vfs_getopt(opts, name, (void **)&opt_value, &opt_len);
151790075Sobrien	if (error != 0)
151890075Sobrien		return (error);
151990075Sobrien	if (opt_len == 0 || opt_value == NULL)
152090075Sobrien		return (EINVAL);
152190075Sobrien	if (opt_value[0] == '\0' || opt_value[opt_len - 1] != '\0')
152290075Sobrien		return (EINVAL);
152390075Sobrien	iv = strtoq(opt_value, &vtp, 0);
152490075Sobrien	if (vtp == opt_value || (vtp[0] != '\0' && vtp[1] != '\0'))
152590075Sobrien		return (EINVAL);
152690075Sobrien	if (iv < 0)
152790075Sobrien		return (EINVAL);
152890075Sobrien	switch (vtp[0]) {
152990075Sobrien	case 't':
153090075Sobrien	case 'T':
153190075Sobrien		iv *= 1024;
153290075Sobrien	case 'g':
153390075Sobrien	case 'G':
153490075Sobrien		iv *= 1024;
153590075Sobrien	case 'm':
153690075Sobrien	case 'M':
153790075Sobrien		iv *= 1024;
153890075Sobrien	case 'k':
153990075Sobrien	case 'K':
154090075Sobrien		iv *= 1024;
154190075Sobrien	case '\0':
154290075Sobrien		break;
154390075Sobrien	default:
154490075Sobrien		return (EINVAL);
154590075Sobrien	}
154690075Sobrien	*value = iv;
154790075Sobrien
154890075Sobrien	return (0);
154990075Sobrien}
155090075Sobrien
155190075Sobrienchar *
155290075Sobrienvfs_getopts(struct vfsoptlist *opts, const char *name, int *error)
155390075Sobrien{
155490075Sobrien	struct vfsopt *opt;
155590075Sobrien
155690075Sobrien	*error = 0;
155790075Sobrien	TAILQ_FOREACH(opt, opts, link) {
155890075Sobrien		if (strcmp(name, opt->name) != 0)
155990075Sobrien			continue;
156090075Sobrien		opt->seen = 1;
156190075Sobrien		if (opt->len == 0 ||
1562		    ((char *)opt->value)[opt->len - 1] != '\0') {
1563			*error = EINVAL;
1564			return (NULL);
1565		}
1566		return (opt->value);
1567	}
1568	*error = ENOENT;
1569	return (NULL);
1570}
1571
1572int
1573vfs_flagopt(struct vfsoptlist *opts, const char *name, uint64_t *w,
1574	uint64_t val)
1575{
1576	struct vfsopt *opt;
1577
1578	TAILQ_FOREACH(opt, opts, link) {
1579		if (strcmp(name, opt->name) == 0) {
1580			opt->seen = 1;
1581			if (w != NULL)
1582				*w |= val;
1583			return (1);
1584		}
1585	}
1586	if (w != NULL)
1587		*w &= ~val;
1588	return (0);
1589}
1590
1591int
1592vfs_scanopt(struct vfsoptlist *opts, const char *name, const char *fmt, ...)
1593{
1594	va_list ap;
1595	struct vfsopt *opt;
1596	int ret;
1597
1598	KASSERT(opts != NULL, ("vfs_getopt: caller passed 'opts' as NULL"));
1599
1600	TAILQ_FOREACH(opt, opts, link) {
1601		if (strcmp(name, opt->name) != 0)
1602			continue;
1603		opt->seen = 1;
1604		if (opt->len == 0 || opt->value == NULL)
1605			return (0);
1606		if (((char *)opt->value)[opt->len - 1] != '\0')
1607			return (0);
1608		va_start(ap, fmt);
1609		ret = vsscanf(opt->value, fmt, ap);
1610		va_end(ap);
1611		return (ret);
1612	}
1613	return (0);
1614}
1615
1616int
1617vfs_setopt(struct vfsoptlist *opts, const char *name, void *value, int len)
1618{
1619	struct vfsopt *opt;
1620
1621	TAILQ_FOREACH(opt, opts, link) {
1622		if (strcmp(name, opt->name) != 0)
1623			continue;
1624		opt->seen = 1;
1625		if (opt->value == NULL)
1626			opt->len = len;
1627		else {
1628			if (opt->len != len)
1629				return (EINVAL);
1630			bcopy(value, opt->value, len);
1631		}
1632		return (0);
1633	}
1634	return (ENOENT);
1635}
1636
1637int
1638vfs_setopt_part(struct vfsoptlist *opts, const char *name, void *value, int len)
1639{
1640	struct vfsopt *opt;
1641
1642	TAILQ_FOREACH(opt, opts, link) {
1643		if (strcmp(name, opt->name) != 0)
1644			continue;
1645		opt->seen = 1;
1646		if (opt->value == NULL)
1647			opt->len = len;
1648		else {
1649			if (opt->len < len)
1650				return (EINVAL);
1651			opt->len = len;
1652			bcopy(value, opt->value, len);
1653		}
1654		return (0);
1655	}
1656	return (ENOENT);
1657}
1658
1659int
1660vfs_setopts(struct vfsoptlist *opts, const char *name, const char *value)
1661{
1662	struct vfsopt *opt;
1663
1664	TAILQ_FOREACH(opt, opts, link) {
1665		if (strcmp(name, opt->name) != 0)
1666			continue;
1667		opt->seen = 1;
1668		if (opt->value == NULL)
1669			opt->len = strlen(value) + 1;
1670		else if (strlcpy(opt->value, value, opt->len) >= opt->len)
1671			return (EINVAL);
1672		return (0);
1673	}
1674	return (ENOENT);
1675}
1676
1677/*
1678 * Find and copy a mount option.
1679 *
1680 * The size of the buffer has to be specified
1681 * in len, if it is not the same length as the
1682 * mount option, EINVAL is returned.
1683 * Returns ENOENT if the option is not found.
1684 */
1685int
1686vfs_copyopt(opts, name, dest, len)
1687	struct vfsoptlist *opts;
1688	const char *name;
1689	void *dest;
1690	int len;
1691{
1692	struct vfsopt *opt;
1693
1694	KASSERT(opts != NULL, ("vfs_copyopt: caller passed 'opts' as NULL"));
1695
1696	TAILQ_FOREACH(opt, opts, link) {
1697		if (strcmp(name, opt->name) == 0) {
1698			opt->seen = 1;
1699			if (len != opt->len)
1700				return (EINVAL);
1701			bcopy(opt->value, dest, opt->len);
1702			return (0);
1703		}
1704	}
1705	return (ENOENT);
1706}
1707
1708/*
1709 * These are helper functions for filesystems to traverse all
1710 * their vnodes.  See MNT_VNODE_FOREACH() in sys/mount.h.
1711 *
1712 * This interface has been deprecated in favor of MNT_VNODE_FOREACH_ALL.
1713 */
1714
1715MALLOC_DECLARE(M_VNODE_MARKER);
1716
1717struct vnode *
1718__mnt_vnode_next(struct vnode **mvp, struct mount *mp)
1719{
1720	struct vnode *vp;
1721
1722	mtx_assert(MNT_MTX(mp), MA_OWNED);
1723
1724	KASSERT((*mvp)->v_mount == mp, ("marker vnode mount list mismatch"));
1725	if (should_yield()) {
1726		MNT_IUNLOCK(mp);
1727		kern_yield(PRI_UNCHANGED);
1728		MNT_ILOCK(mp);
1729	}
1730	vp = TAILQ_NEXT(*mvp, v_nmntvnodes);
1731	while (vp != NULL && vp->v_type == VMARKER)
1732		vp = TAILQ_NEXT(vp, v_nmntvnodes);
1733
1734	/* Check if we are done */
1735	if (vp == NULL) {
1736		__mnt_vnode_markerfree(mvp, mp);
1737		return (NULL);
1738	}
1739	TAILQ_REMOVE(&mp->mnt_nvnodelist, *mvp, v_nmntvnodes);
1740	TAILQ_INSERT_AFTER(&mp->mnt_nvnodelist, vp, *mvp, v_nmntvnodes);
1741	return (vp);
1742}
1743
1744struct vnode *
1745__mnt_vnode_first(struct vnode **mvp, struct mount *mp)
1746{
1747	struct vnode *vp;
1748
1749	mtx_assert(MNT_MTX(mp), MA_OWNED);
1750
1751	vp = TAILQ_FIRST(&mp->mnt_nvnodelist);
1752	while (vp != NULL && vp->v_type == VMARKER)
1753		vp = TAILQ_NEXT(vp, v_nmntvnodes);
1754
1755	/* Check if we are done */
1756	if (vp == NULL) {
1757		*mvp = NULL;
1758		return (NULL);
1759	}
1760	MNT_REF(mp);
1761	MNT_IUNLOCK(mp);
1762	*mvp = (struct vnode *) malloc(sizeof(struct vnode),
1763				       M_VNODE_MARKER,
1764				       M_WAITOK | M_ZERO);
1765	MNT_ILOCK(mp);
1766	(*mvp)->v_type = VMARKER;
1767
1768	vp = TAILQ_FIRST(&mp->mnt_nvnodelist);
1769	while (vp != NULL && vp->v_type == VMARKER)
1770		vp = TAILQ_NEXT(vp, v_nmntvnodes);
1771
1772	/* Check if we are done */
1773	if (vp == NULL) {
1774		MNT_IUNLOCK(mp);
1775		free(*mvp, M_VNODE_MARKER);
1776		MNT_ILOCK(mp);
1777		*mvp = NULL;
1778		MNT_REL(mp);
1779		return (NULL);
1780	}
1781	(*mvp)->v_mount = mp;
1782	TAILQ_INSERT_AFTER(&mp->mnt_nvnodelist, vp, *mvp, v_nmntvnodes);
1783	return (vp);
1784}
1785
1786
1787void
1788__mnt_vnode_markerfree(struct vnode **mvp, struct mount *mp)
1789{
1790
1791	if (*mvp == NULL)
1792		return;
1793
1794	mtx_assert(MNT_MTX(mp), MA_OWNED);
1795
1796	KASSERT((*mvp)->v_mount == mp, ("marker vnode mount list mismatch"));
1797	TAILQ_REMOVE(&mp->mnt_nvnodelist, *mvp, v_nmntvnodes);
1798	MNT_IUNLOCK(mp);
1799	free(*mvp, M_VNODE_MARKER);
1800	MNT_ILOCK(mp);
1801	*mvp = NULL;
1802	MNT_REL(mp);
1803}
1804
1805int
1806__vfs_statfs(struct mount *mp, struct statfs *sbp)
1807{
1808	int error;
1809
1810	error = mp->mnt_op->vfs_statfs(mp, &mp->mnt_stat);
1811	if (sbp != &mp->mnt_stat)
1812		*sbp = mp->mnt_stat;
1813	return (error);
1814}
1815
1816void
1817vfs_mountedfrom(struct mount *mp, const char *from)
1818{
1819
1820	bzero(mp->mnt_stat.f_mntfromname, sizeof mp->mnt_stat.f_mntfromname);
1821	strlcpy(mp->mnt_stat.f_mntfromname, from,
1822	    sizeof mp->mnt_stat.f_mntfromname);
1823}
1824
1825/*
1826 * ---------------------------------------------------------------------
1827 * This is the api for building mount args and mounting filesystems from
1828 * inside the kernel.
1829 *
1830 * The API works by accumulation of individual args.  First error is
1831 * latched.
1832 *
1833 * XXX: should be documented in new manpage kernel_mount(9)
1834 */
1835
1836/* A memory allocation which must be freed when we are done */
1837struct mntaarg {
1838	SLIST_ENTRY(mntaarg)	next;
1839};
1840
1841/* The header for the mount arguments */
1842struct mntarg {
1843	struct iovec *v;
1844	int len;
1845	int error;
1846	SLIST_HEAD(, mntaarg)	list;
1847};
1848
1849/*
1850 * Add a boolean argument.
1851 *
1852 * flag is the boolean value.
1853 * name must start with "no".
1854 */
1855struct mntarg *
1856mount_argb(struct mntarg *ma, int flag, const char *name)
1857{
1858
1859	KASSERT(name[0] == 'n' && name[1] == 'o',
1860	    ("mount_argb(...,%s): name must start with 'no'", name));
1861
1862	return (mount_arg(ma, name + (flag ? 2 : 0), NULL, 0));
1863}
1864
1865/*
1866 * Add an argument printf style
1867 */
1868struct mntarg *
1869mount_argf(struct mntarg *ma, const char *name, const char *fmt, ...)
1870{
1871	va_list ap;
1872	struct mntaarg *maa;
1873	struct sbuf *sb;
1874	int len;
1875
1876	if (ma == NULL) {
1877		ma = malloc(sizeof *ma, M_MOUNT, M_WAITOK | M_ZERO);
1878		SLIST_INIT(&ma->list);
1879	}
1880	if (ma->error)
1881		return (ma);
1882
1883	ma->v = realloc(ma->v, sizeof *ma->v * (ma->len + 2),
1884	    M_MOUNT, M_WAITOK);
1885	ma->v[ma->len].iov_base = (void *)(uintptr_t)name;
1886	ma->v[ma->len].iov_len = strlen(name) + 1;
1887	ma->len++;
1888
1889	sb = sbuf_new_auto();
1890	va_start(ap, fmt);
1891	sbuf_vprintf(sb, fmt, ap);
1892	va_end(ap);
1893	sbuf_finish(sb);
1894	len = sbuf_len(sb) + 1;
1895	maa = malloc(sizeof *maa + len, M_MOUNT, M_WAITOK | M_ZERO);
1896	SLIST_INSERT_HEAD(&ma->list, maa, next);
1897	bcopy(sbuf_data(sb), maa + 1, len);
1898	sbuf_delete(sb);
1899
1900	ma->v[ma->len].iov_base = maa + 1;
1901	ma->v[ma->len].iov_len = len;
1902	ma->len++;
1903
1904	return (ma);
1905}
1906
1907/*
1908 * Add an argument which is a userland string.
1909 */
1910struct mntarg *
1911mount_argsu(struct mntarg *ma, const char *name, const void *val, int len)
1912{
1913	struct mntaarg *maa;
1914	char *tbuf;
1915
1916	if (val == NULL)
1917		return (ma);
1918	if (ma == NULL) {
1919		ma = malloc(sizeof *ma, M_MOUNT, M_WAITOK | M_ZERO);
1920		SLIST_INIT(&ma->list);
1921	}
1922	if (ma->error)
1923		return (ma);
1924	maa = malloc(sizeof *maa + len, M_MOUNT, M_WAITOK | M_ZERO);
1925	SLIST_INSERT_HEAD(&ma->list, maa, next);
1926	tbuf = (void *)(maa + 1);
1927	ma->error = copyinstr(val, tbuf, len, NULL);
1928	return (mount_arg(ma, name, tbuf, -1));
1929}
1930
1931/*
1932 * Plain argument.
1933 *
1934 * If length is -1, treat value as a C string.
1935 */
1936struct mntarg *
1937mount_arg(struct mntarg *ma, const char *name, const void *val, int len)
1938{
1939
1940	if (ma == NULL) {
1941		ma = malloc(sizeof *ma, M_MOUNT, M_WAITOK | M_ZERO);
1942		SLIST_INIT(&ma->list);
1943	}
1944	if (ma->error)
1945		return (ma);
1946
1947	ma->v = realloc(ma->v, sizeof *ma->v * (ma->len + 2),
1948	    M_MOUNT, M_WAITOK);
1949	ma->v[ma->len].iov_base = (void *)(uintptr_t)name;
1950	ma->v[ma->len].iov_len = strlen(name) + 1;
1951	ma->len++;
1952
1953	ma->v[ma->len].iov_base = (void *)(uintptr_t)val;
1954	if (len < 0)
1955		ma->v[ma->len].iov_len = strlen(val) + 1;
1956	else
1957		ma->v[ma->len].iov_len = len;
1958	ma->len++;
1959	return (ma);
1960}
1961
1962/*
1963 * Free a mntarg structure
1964 */
1965static void
1966free_mntarg(struct mntarg *ma)
1967{
1968	struct mntaarg *maa;
1969
1970	while (!SLIST_EMPTY(&ma->list)) {
1971		maa = SLIST_FIRST(&ma->list);
1972		SLIST_REMOVE_HEAD(&ma->list, next);
1973		free(maa, M_MOUNT);
1974	}
1975	free(ma->v, M_MOUNT);
1976	free(ma, M_MOUNT);
1977}
1978
1979/*
1980 * Mount a filesystem
1981 */
1982int
1983kernel_mount(struct mntarg *ma, uint64_t flags)
1984{
1985	struct uio auio;
1986	int error;
1987
1988	KASSERT(ma != NULL, ("kernel_mount NULL ma"));
1989	KASSERT(ma->v != NULL, ("kernel_mount NULL ma->v"));
1990	KASSERT(!(ma->len & 1), ("kernel_mount odd ma->len (%d)", ma->len));
1991
1992	auio.uio_iov = ma->v;
1993	auio.uio_iovcnt = ma->len;
1994	auio.uio_segflg = UIO_SYSSPACE;
1995
1996	error = ma->error;
1997	if (!error)
1998		error = vfs_donmount(curthread, flags, &auio);
1999	free_mntarg(ma);
2000	return (error);
2001}
2002
2003/*
2004 * A printflike function to mount a filesystem.
2005 */
2006int
2007kernel_vmount(int flags, ...)
2008{
2009	struct mntarg *ma = NULL;
2010	va_list ap;
2011	const char *cp;
2012	const void *vp;
2013	int error;
2014
2015	va_start(ap, flags);
2016	for (;;) {
2017		cp = va_arg(ap, const char *);
2018		if (cp == NULL)
2019			break;
2020		vp = va_arg(ap, const void *);
2021		ma = mount_arg(ma, cp, vp, (vp != NULL ? -1 : 0));
2022	}
2023	va_end(ap);
2024
2025	error = kernel_mount(ma, flags);
2026	return (error);
2027}
2028
2029void
2030vfs_oexport_conv(const struct oexport_args *oexp, struct export_args *exp)
2031{
2032
2033	bcopy(oexp, exp, sizeof(*oexp));
2034	exp->ex_numsecflavors = 0;
2035}
2036