summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_extattr.c
diff options
context:
space:
mode:
authormux <mux@FreeBSD.org>2002-07-02 17:09:22 +0000
committermux <mux@FreeBSD.org>2002-07-02 17:09:22 +0000
commiteb5a0f4a7e3bc12038c158f02c57a11ec098b5a8 (patch)
tree24cc092d22964f80698c7a1f3bb3547b24e81294 /sys/kern/vfs_extattr.c
parent86ce3862f7dc4893fb2bc2f87a6a96c042172036 (diff)
downloadFreeBSD-src-eb5a0f4a7e3bc12038c158f02c57a11ec098b5a8.zip
FreeBSD-src-eb5a0f4a7e3bc12038c158f02c57a11ec098b5a8.tar.gz
Move every code related to mount(2) in a new file, vfs_mount.c.
The file vfs_conf.c which was dealing with root mounting has been repo-copied into vfs_mount.c to preserve history. This makes nmount related development easier, and help reducing the size of vfs_syscalls.c, which is still an enormous file. Reviewed by: rwatson Repo-copy by: peter
Diffstat (limited to 'sys/kern/vfs_extattr.c')
-rw-r--r--sys/kern/vfs_extattr.c1042
1 files changed, 0 insertions, 1042 deletions
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c
index 8fcb651..17da270 100644
--- a/sys/kern/vfs_extattr.c
+++ b/sys/kern/vfs_extattr.c
@@ -76,7 +76,6 @@
#include <vm/uma.h>
static int change_dir(struct nameidata *ndp, struct thread *td);
-static void checkdirs(struct vnode *olddp, struct vnode *newdp);
static int chroot_refuse_vdir_fds(struct filedesc *fdp);
static int getutimes(const struct timeval *, struct timespec *);
static int setfown(struct thread *td, struct vnode *, uid_t, gid_t);
@@ -86,1051 +85,10 @@ static int setutimes(struct thread *td, struct vnode *,
const struct timespec *, int);
static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
struct thread *td);
-static int vfs_nmount(struct thread *td, int, struct uio *);
-
-static int usermount = 0; /* if 1, non-root can mount fs. */
int (*union_dircheckp)(struct thread *td, struct vnode **, struct file *);
int (*softdep_fsync_hook)(struct vnode *);
-SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0, "");
-
-/*
- * Virtual File System System Calls
- */
-
-#ifndef _SYS_SYSPROTO_H_
-struct nmount_args {
- struct iovec *iovp;
- unsigned int iovcnt;
- int flags;
-};
-#endif
-/* ARGSUSED */
-int
-nmount(td, uap)
- struct thread *td;
- struct nmount_args /* {
- syscallarg(struct iovec *) iovp;
- syscallarg(unsigned int) iovcnt;
- syscallarg(int) flags;
- } */ *uap;
-{
- struct uio auio;
- struct iovec *iov, *needfree;
- struct iovec aiov[UIO_SMALLIOV];
- unsigned int i;
- int error;
- u_int iovlen, iovcnt;
-
- iovcnt = SCARG(uap, iovcnt);
- iovlen = iovcnt * sizeof (struct iovec);
- /*
- * Check that we have an even number of iovec's
- * and that we have at least two options.
- */
- if ((iovcnt & 1) || (iovcnt < 4) || (iovcnt > UIO_MAXIOV))
- return (EINVAL);
-
- if (iovcnt > UIO_SMALLIOV) {
- MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
- needfree = iov;
- } else {
- iov = aiov;
- needfree = NULL;
- }
- auio.uio_iov = iov;
- auio.uio_iovcnt = iovcnt;
- auio.uio_segflg = UIO_USERSPACE;
- if ((error = copyin(uap->iovp, iov, iovlen)))
- goto finish;
-
- for (i = 0; i < iovcnt; i++) {
- if (iov->iov_len > MMAXOPTIONLEN) {
- error = EINVAL;
- goto finish;
- }
- iov++;
- }
- error = vfs_nmount(td, SCARG(uap, flags), &auio);
-finish:
- if (needfree != NULL)
- free(needfree, M_TEMP);
- return (error);
-}
-
-/*
- * Release all resources related to the
- * mount options.
- */
-void
-vfs_freeopts(struct vfsoptlist *opts)
-{
- struct vfsopt *opt;
-
- while (!TAILQ_EMPTY(opts)) {
- opt = TAILQ_FIRST(opts);
- TAILQ_REMOVE(opts, opt, link);
- free(opt->name, M_MOUNT);
- free(opt->value, M_MOUNT);
- free(opt, M_MOUNT);
- }
- free(opts, M_MOUNT);
-}
-
-int
-kernel_mount(iovp, iovcnt, flags)
- struct iovec *iovp;
- unsigned int iovcnt;
- int flags;
-{
- struct uio auio;
- int error;
-
- /*
- * Check that we have an even number of iovec's
- * and that we have at least two options.
- */
- if ((iovcnt & 1) || (iovcnt < 4))
- return (EINVAL);
-
- auio.uio_iov = iovp;
- auio.uio_iovcnt = iovcnt;
- auio.uio_segflg = UIO_SYSSPACE;
-
- error = vfs_nmount(curthread, flags, &auio);
- return (error);
-}
-
-int
-kernel_vmount(int flags, ...)
-{
- struct iovec *iovp;
- struct uio auio;
- va_list ap;
- unsigned int iovcnt, iovlen, len;
- const char *cp;
- char *buf, *pos;
- size_t n;
- int error, i;
-
- len = 0;
- va_start(ap, flags);
- for (iovcnt = 0; (cp = va_arg(ap, const char *)) != NULL; iovcnt++)
- len += strlen(cp) + 1;
- va_end(ap);
-
- if (iovcnt < 4 || iovcnt & 1)
- return (EINVAL);
-
- iovlen = iovcnt * sizeof (struct iovec);
- MALLOC(iovp, struct iovec *, iovlen, M_MOUNT, M_WAITOK);
- MALLOC(buf, char *, len, M_MOUNT, M_WAITOK);
- pos = buf;
- va_start(ap, flags);
- for (i = 0; i < iovcnt; i++) {
- cp = va_arg(ap, const char *);
- copystr(cp, pos, len - (pos - buf), &n);
- iovp[i].iov_base = pos;
- iovp[i].iov_len = n;
- pos += n;
- }
- va_end(ap);
-
- auio.uio_iov = iovp;
- auio.uio_iovcnt = iovcnt;
- auio.uio_segflg = UIO_SYSSPACE;
-
- error = vfs_nmount(curthread, flags, &auio);
- FREE(iovp, M_MOUNT);
- FREE(buf, M_MOUNT);
- return (error);
-}
-
-/*
- * vfs_nmount(): actually attempt a filesystem mount.
- */
-static int
-vfs_nmount(td, fsflags, fsoptions)
- struct thread *td;
- int fsflags; /* Flags common to all filesystems. */
- struct uio *fsoptions; /* Options local to the filesystem. */
-{
- linker_file_t lf;
- struct vnode *vp;
- struct mount *mp;
- struct vfsconf *vfsp;
- struct vfsoptlist *optlist;
- char *fstype, *fspath;
- int error, flag = 0, kern_flag = 0;
- int fstypelen, fspathlen;
- struct vattr va;
- struct nameidata nd;
-
- error = vfs_buildopts(fsoptions, &optlist);
- if (error)
- return (error);
-
- /*
- * We need these two options before the others,
- * and they are mandatory for any filesystem.
- * Ensure they are NUL terminated as well.
- */
- fstypelen = 0;
- error = vfs_getopt(optlist, "fstype", (void **)&fstype, &fstypelen);
- if (error || fstype[fstypelen - 1] != '\0') {
- error = EINVAL;
- goto bad;
- }
- fspathlen = 0;
- error = vfs_getopt(optlist, "fspath", (void **)&fspath, &fspathlen);
- if (error || fspath[fspathlen - 1] != '\0') {
- error = EINVAL;
- goto bad;
- }
-
- /*
- * Be ultra-paranoid about making sure the type and fspath
- * variables will fit in our mp buffers, including the
- * terminating NUL.
- */
- if (fstypelen >= MFSNAMELEN - 1 || fspathlen >= MNAMELEN - 1) {
- error = ENAMETOOLONG;
- goto bad;
- }
-
- if (usermount == 0) {
- error = suser(td);
- if (error)
- goto bad;
- }
- /*
- * Do not allow NFS export by non-root users.
- */
- if (fsflags & MNT_EXPORTED) {
- error = suser(td);
- if (error)
- goto bad;
- }
- /*
- * Silently enforce MNT_NOSUID and MNT_NODEV for non-root users.
- */
- if (suser(td))
- fsflags |= MNT_NOSUID | MNT_NODEV;
- /*
- * Get vnode to be covered
- */
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, td);
- if ((error = namei(&nd)) != 0)
- goto bad;
- NDFREE(&nd, NDF_ONLY_PNBUF);
- vp = nd.ni_vp;
- if (fsflags & MNT_UPDATE) {
- if ((vp->v_flag & VROOT) == 0) {
- vput(vp);
- error = EINVAL;
- goto bad;
- }
- mp = vp->v_mount;
- flag = mp->mnt_flag;
- kern_flag = mp->mnt_kern_flag;
- /*
- * We only allow the filesystem to be reloaded if it
- * is currently mounted read-only.
- */
- if ((fsflags & MNT_RELOAD) &&
- ((mp->mnt_flag & MNT_RDONLY) == 0)) {
- vput(vp);
- error = EOPNOTSUPP; /* Needs translation */
- goto bad;
- }
- /*
- * Only root, or the user that did the original mount is
- * permitted to update it.
- */
- if (mp->mnt_stat.f_owner != td->td_ucred->cr_uid) {
- error = suser(td);
- if (error) {
- vput(vp);
- goto bad;
- }
- }
- if (vfs_busy(mp, LK_NOWAIT, 0, td)) {
- vput(vp);
- error = EBUSY;
- goto bad;
- }
- mtx_lock(&vp->v_interlock);
- if ((vp->v_flag & VMOUNT) != 0 || vp->v_mountedhere != NULL) {
- mtx_unlock(&vp->v_interlock);
- vfs_unbusy(mp, td);
- vput(vp);
- error = EBUSY;
- goto bad;
- }
- vp->v_flag |= VMOUNT;
- mtx_unlock(&vp->v_interlock);
- mp->mnt_flag |= fsflags &
- (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT);
- VOP_UNLOCK(vp, 0, td);
- goto update;
- }
- /*
- * If the user is not root, ensure that they own the directory
- * onto which we are attempting to mount.
- */
- error = VOP_GETATTR(vp, &va, td->td_ucred, td);
- if (error) {
- vput(vp);
- goto bad;
- }
- if (va.va_uid != td->td_ucred->cr_uid) {
- error = suser(td);
- if (error) {
- vput(vp);
- goto bad;
- }
- }
- if ((error = vinvalbuf(vp, V_SAVE, td->td_ucred, td, 0, 0)) != 0) {
- vput(vp);
- goto bad;
- }
- if (vp->v_type != VDIR) {
- vput(vp);
- error = ENOTDIR;
- goto bad;
- }
- for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
- if (!strcmp(vfsp->vfc_name, fstype))
- break;
- if (vfsp == NULL) {
- /* Only load modules for root (very important!). */
- error = suser(td);
- if (error) {
- vput(vp);
- goto bad;
- }
- error = securelevel_gt(td->td_ucred, 0);
- if (error) {
- vput(vp);
- goto bad;
- }
- error = linker_load_file(fstype, &lf);
- if (error || lf == NULL) {
- vput(vp);
- if (lf == NULL)
- error = ENODEV;
- goto bad;
- }
- lf->userrefs++;
- /* Look up again to see if the VFS was loaded. */
- for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
- if (!strcmp(vfsp->vfc_name, fstype))
- break;
- if (vfsp == NULL) {
- lf->userrefs--;
- linker_file_unload(lf);
- vput(vp);
- error = ENODEV;
- goto bad;
- }
- }
- mtx_lock(&vp->v_interlock);
- if ((vp->v_flag & VMOUNT) != 0 ||
- vp->v_mountedhere != NULL) {
- mtx_unlock(&vp->v_interlock);
- vput(vp);
- error = EBUSY;
- goto bad;
- }
- vp->v_flag |= VMOUNT;
- mtx_unlock(&vp->v_interlock);
-
- /*
- * Allocate and initialize the filesystem.
- */
- mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK | M_ZERO);
- TAILQ_INIT(&mp->mnt_nvnodelist);
- TAILQ_INIT(&mp->mnt_reservedvnlist);
- lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE);
- (void)vfs_busy(mp, LK_NOWAIT, 0, td);
- mp->mnt_op = vfsp->vfc_vfsops;
- mp->mnt_vfc = vfsp;
- vfsp->vfc_refcount++;
- mp->mnt_stat.f_type = vfsp->vfc_typenum;
- mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
- strncpy(mp->mnt_stat.f_fstypename, fstype, MFSNAMELEN);
- mp->mnt_vnodecovered = vp;
- mp->mnt_stat.f_owner = td->td_ucred->cr_uid;
- strncpy(mp->mnt_stat.f_mntonname, fspath, MNAMELEN);
- mp->mnt_iosize_max = DFLTPHYS;
- VOP_UNLOCK(vp, 0, td);
-
-update:
- mp->mnt_optnew = optlist;
- /*
- * Check if the fs implements the new VFS_NMOUNT()
- * function, since the new system call was used.
- */
- if (mp->mnt_op->vfs_mount != NULL) {
- printf("%s doesn't support the new mount syscall\n",
- mp->mnt_vfc->vfc_name);
- mtx_lock(&vp->v_interlock);
- vp->v_flag &= ~VMOUNT;
- mtx_unlock(&vp->v_interlock);
- if (mp->mnt_flag & MNT_UPDATE)
- vfs_unbusy(mp, td);
- else {
- mp->mnt_vfc->vfc_refcount--;
- vfs_unbusy(mp, td);
- free(mp, M_MOUNT);
- }
- vrele(vp);
- error = EOPNOTSUPP;
- goto bad;
- }
-
- /*
- * Set the mount level flags.
- */
- if (fsflags & MNT_RDONLY)
- mp->mnt_flag |= MNT_RDONLY;
- else if (mp->mnt_flag & MNT_RDONLY)
- mp->mnt_kern_flag |= MNTK_WANTRDWR;
- mp->mnt_flag &=~ MNT_UPDATEMASK;
- mp->mnt_flag |= fsflags & (MNT_UPDATEMASK | MNT_FORCE);
- /*
- * Mount the filesystem.
- * XXX The final recipients of VFS_MOUNT just overwrite the ndp they
- * get. No freeing of cn_pnbuf.
- */
- error = VFS_NMOUNT(mp, &nd, td);
- if (!error) {
- if (mp->mnt_opt != NULL)
- vfs_freeopts(mp->mnt_opt);
- mp->mnt_opt = mp->mnt_optnew;
- }
- /*
- * Prevent external consumers of mount
- * options to read mnt_optnew.
- */
- mp->mnt_optnew = NULL;
- if (mp->mnt_flag & MNT_UPDATE) {
- if (mp->mnt_kern_flag & MNTK_WANTRDWR)
- mp->mnt_flag &= ~MNT_RDONLY;
- mp->mnt_flag &=~
- (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_SNAPSHOT);
- mp->mnt_kern_flag &=~ MNTK_WANTRDWR;
- if (error) {
- mp->mnt_flag = flag;
- mp->mnt_kern_flag = kern_flag;
- }
- if ((mp->mnt_flag & MNT_RDONLY) == 0) {
- if (mp->mnt_syncer == NULL)
- error = vfs_allocate_syncvnode(mp);
- } else {
- if (mp->mnt_syncer != NULL)
- vrele(mp->mnt_syncer);
- mp->mnt_syncer = NULL;
- }
- vfs_unbusy(mp, td);
- mtx_lock(&vp->v_interlock);
- vp->v_flag &= ~VMOUNT;
- mtx_unlock(&vp->v_interlock);
- vrele(vp);
- return (error);
- }
- vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
- /*
- * Put the new filesystem on the mount list after root.
- */
- cache_purge(vp);
- if (!error) {
- struct vnode *newdp;
-
- mtx_lock(&vp->v_interlock);
- vp->v_flag &= ~VMOUNT;
- vp->v_mountedhere = mp;
- mtx_unlock(&vp->v_interlock);
- mtx_lock(&mountlist_mtx);
- TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
- mtx_unlock(&mountlist_mtx);
- if (VFS_ROOT(mp, &newdp))
- panic("mount: lost mount");
- checkdirs(vp, newdp);
- vput(newdp);
- VOP_UNLOCK(vp, 0, td);
- if ((mp->mnt_flag & MNT_RDONLY) == 0)
- error = vfs_allocate_syncvnode(mp);
- vfs_unbusy(mp, td);
- if ((error = VFS_START(mp, 0, td)) != 0) {
- vrele(vp);
- goto bad;
- }
- } else {
- mtx_lock(&vp->v_interlock);
- vp->v_flag &= ~VMOUNT;
- mtx_unlock(&vp->v_interlock);
- mp->mnt_vfc->vfc_refcount--;
- vfs_unbusy(mp, td);
- free(mp, M_MOUNT);
- vput(vp);
- goto bad;
- }
- return (0);
-bad:
- vfs_freeopts(optlist);
- return (error);
-}
-
-/*
- * Old Mount API.
- */
-#ifndef _SYS_SYSPROTO_H_
-struct mount_args {
- char *type;
- char *path;
- int flags;
- caddr_t data;
-};
-#endif
-/* ARGSUSED */
-int
-mount(td, uap)
- struct thread *td;
- struct mount_args /* {
- syscallarg(char *) type;
- syscallarg(char *) path;
- syscallarg(int) flags;
- syscallarg(caddr_t) data;
- } */ *uap;
-{
- char *fstype;
- char *fspath;
- int error;
-
- fstype = malloc(MFSNAMELEN, M_TEMP, M_WAITOK);
- fspath = malloc(MNAMELEN, M_TEMP, M_WAITOK);
-
- /*
- * vfs_mount() actually takes a kernel string for `type' and
- * `path' now, so extract them.
- */
- error = copyinstr(SCARG(uap, type), fstype, MFSNAMELEN, NULL);
- if (error)
- goto finish;
- error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL);
- if (error)
- goto finish;
- error = vfs_mount(td, fstype, fspath, SCARG(uap, flags),
- SCARG(uap, data));
-finish:
- free(fstype, M_TEMP);
- free(fspath, M_TEMP);
- return (error);
-}
-
-/*
- * vfs_mount(): actually attempt a filesystem mount.
- *
- * This routine is designed to be a "generic" entry point for routines
- * that wish to mount a filesystem. All parameters except `fsdata' are
- * pointers into kernel space. `fsdata' is currently still a pointer
- * into userspace.
- */
-int
-vfs_mount(td, fstype, fspath, fsflags, fsdata)
- struct thread *td;
- const char *fstype;
- char *fspath;
- int fsflags;
- void *fsdata;
-{
- linker_file_t lf;
- struct vnode *vp;
- struct mount *mp;
- struct vfsconf *vfsp;
- int error, flag = 0, kern_flag = 0;
- struct vattr va;
- struct nameidata nd;
-
- /*
- * Be ultra-paranoid about making sure the type and fspath
- * variables will fit in our mp buffers, including the
- * terminating NUL.
- */
- if (strlen(fstype) >= MFSNAMELEN || strlen(fspath) >= MNAMELEN)
- return (ENAMETOOLONG);
-
- if (usermount == 0) {
- error = suser(td);
- if (error)
- return (error);
- }
- /*
- * Do not allow NFS export by non-root users.
- */
- if (fsflags & MNT_EXPORTED) {
- error = suser(td);
- if (error)
- return (error);
- }
- /*
- * Silently enforce MNT_NOSUID and MNT_NODEV for non-root users.
- */
- if (suser(td))
- fsflags |= MNT_NOSUID | MNT_NODEV;
- /*
- * Get vnode to be covered
- */
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, td);
- if ((error = namei(&nd)) != 0)
- return (error);
- NDFREE(&nd, NDF_ONLY_PNBUF);
- vp = nd.ni_vp;
- if (fsflags & MNT_UPDATE) {
- if ((vp->v_flag & VROOT) == 0) {
- vput(vp);
- return (EINVAL);
- }
- mp = vp->v_mount;
- flag = mp->mnt_flag;
- kern_flag = mp->mnt_kern_flag;
- /*
- * We only allow the filesystem to be reloaded if it
- * is currently mounted read-only.
- */
- if ((fsflags & MNT_RELOAD) &&
- ((mp->mnt_flag & MNT_RDONLY) == 0)) {
- vput(vp);
- return (EOPNOTSUPP); /* Needs translation */
- }
- /*
- * Only root, or the user that did the original mount is
- * permitted to update it.
- */
- if (mp->mnt_stat.f_owner != td->td_ucred->cr_uid) {
- error = suser(td);
- if (error) {
- vput(vp);
- return (error);
- }
- }
- if (vfs_busy(mp, LK_NOWAIT, 0, td)) {
- vput(vp);
- return (EBUSY);
- }
- mtx_lock(&vp->v_interlock);
- if ((vp->v_flag & VMOUNT) != 0 || vp->v_mountedhere != NULL) {
- mtx_unlock(&vp->v_interlock);
- vfs_unbusy(mp, td);
- vput(vp);
- return (EBUSY);
- }
- vp->v_flag |= VMOUNT;
- mtx_unlock(&vp->v_interlock);
- mp->mnt_flag |= fsflags &
- (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT);
- VOP_UNLOCK(vp, 0, td);
- goto update;
- }
- /*
- * If the user is not root, ensure that they own the directory
- * onto which we are attempting to mount.
- */
- error = VOP_GETATTR(vp, &va, td->td_ucred, td);
- if (error) {
- vput(vp);
- return (error);
- }
- if (va.va_uid != td->td_ucred->cr_uid) {
- error = suser(td);
- if (error) {
- vput(vp);
- return (error);
- }
- }
- if ((error = vinvalbuf(vp, V_SAVE, td->td_ucred, td, 0, 0)) != 0) {
- vput(vp);
- return (error);
- }
- if (vp->v_type != VDIR) {
- vput(vp);
- return (ENOTDIR);
- }
- for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
- if (!strcmp(vfsp->vfc_name, fstype))
- break;
- if (vfsp == NULL) {
- /* Only load modules for root (very important!). */
- error = suser(td);
- if (error) {
- vput(vp);
- return (error);
- }
- error = securelevel_gt(td->td_ucred, 0);
- if (error) {
- vput(vp);
- return (error);
- }
- error = linker_load_file(fstype, &lf);
- if (error || lf == NULL) {
- vput(vp);
- if (lf == NULL)
- error = ENODEV;
- return (error);
- }
- lf->userrefs++;
- /* Look up again to see if the VFS was loaded. */
- for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
- if (!strcmp(vfsp->vfc_name, fstype))
- break;
- if (vfsp == NULL) {
- lf->userrefs--;
- linker_file_unload(lf);
- vput(vp);
- return (ENODEV);
- }
- }
- mtx_lock(&vp->v_interlock);
- if ((vp->v_flag & VMOUNT) != 0 ||
- vp->v_mountedhere != NULL) {
- mtx_unlock(&vp->v_interlock);
- vput(vp);
- return (EBUSY);
- }
- vp->v_flag |= VMOUNT;
- mtx_unlock(&vp->v_interlock);
-
- /*
- * Allocate and initialize the filesystem.
- */
- mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK | M_ZERO);
- TAILQ_INIT(&mp->mnt_nvnodelist);
- TAILQ_INIT(&mp->mnt_reservedvnlist);
- lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE);
- (void)vfs_busy(mp, LK_NOWAIT, 0, td);
- mp->mnt_op = vfsp->vfc_vfsops;
- mp->mnt_vfc = vfsp;
- vfsp->vfc_refcount++;
- mp->mnt_stat.f_type = vfsp->vfc_typenum;
- mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
- strncpy(mp->mnt_stat.f_fstypename, fstype, MFSNAMELEN);
- mp->mnt_vnodecovered = vp;
- mp->mnt_stat.f_owner = td->td_ucred->cr_uid;
- strncpy(mp->mnt_stat.f_mntonname, fspath, MNAMELEN);
- mp->mnt_iosize_max = DFLTPHYS;
- VOP_UNLOCK(vp, 0, td);
-update:
- /*
- * Check if the fs implements the old VFS_MOUNT()
- * function, since the old system call was used.
- */
- if (mp->mnt_op->vfs_mount == NULL) {
- printf("%s doesn't support the old mount syscall\n",
- mp->mnt_vfc->vfc_name);
- mtx_lock(&vp->v_interlock);
- vp->v_flag &= ~VMOUNT;
- mtx_unlock(&vp->v_interlock);
- if (mp->mnt_flag & MNT_UPDATE)
- vfs_unbusy(mp, td);
- else {
- mp->mnt_vfc->vfc_refcount--;
- vfs_unbusy(mp, td);
- free(mp, M_MOUNT);
- }
- vrele(vp);
- return (EOPNOTSUPP);
- }
-
- /*
- * Set the mount level flags.
- */
- if (fsflags & MNT_RDONLY)
- mp->mnt_flag |= MNT_RDONLY;
- else if (mp->mnt_flag & MNT_RDONLY)
- mp->mnt_kern_flag |= MNTK_WANTRDWR;
- mp->mnt_flag &=~ MNT_UPDATEMASK;
- mp->mnt_flag |= fsflags & (MNT_UPDATEMASK | MNT_FORCE);
- /*
- * Mount the filesystem.
- * XXX The final recipients of VFS_MOUNT just overwrite the ndp they
- * get. No freeing of cn_pnbuf.
- */
- error = VFS_MOUNT(mp, fspath, fsdata, &nd, td);
- if (mp->mnt_flag & MNT_UPDATE) {
- if (mp->mnt_kern_flag & MNTK_WANTRDWR)
- mp->mnt_flag &= ~MNT_RDONLY;
- mp->mnt_flag &=~
- (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_SNAPSHOT);
- mp->mnt_kern_flag &=~ MNTK_WANTRDWR;
- if (error) {
- mp->mnt_flag = flag;
- mp->mnt_kern_flag = kern_flag;
- }
- if ((mp->mnt_flag & MNT_RDONLY) == 0) {
- if (mp->mnt_syncer == NULL)
- error = vfs_allocate_syncvnode(mp);
- } else {
- if (mp->mnt_syncer != NULL)
- vrele(mp->mnt_syncer);
- mp->mnt_syncer = NULL;
- }
- vfs_unbusy(mp, td);
- mtx_lock(&vp->v_interlock);
- vp->v_flag &= ~VMOUNT;
- mtx_unlock(&vp->v_interlock);
- vrele(vp);
- return (error);
- }
- vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
- /*
- * Put the new filesystem on the mount list after root.
- */
- cache_purge(vp);
- if (!error) {
- struct vnode *newdp;
-
- mtx_lock(&vp->v_interlock);
- vp->v_flag &= ~VMOUNT;
- vp->v_mountedhere = mp;
- mtx_unlock(&vp->v_interlock);
- mtx_lock(&mountlist_mtx);
- TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
- mtx_unlock(&mountlist_mtx);
- if (VFS_ROOT(mp, &newdp))
- panic("mount: lost mount");
- checkdirs(vp, newdp);
- vput(newdp);
- VOP_UNLOCK(vp, 0, td);
- if ((mp->mnt_flag & MNT_RDONLY) == 0)
- error = vfs_allocate_syncvnode(mp);
- vfs_unbusy(mp, td);
- if ((error = VFS_START(mp, 0, td)) != 0)
- vrele(vp);
- } else {
- mtx_lock(&vp->v_interlock);
- vp->v_flag &= ~VMOUNT;
- mtx_unlock(&vp->v_interlock);
- mp->mnt_vfc->vfc_refcount--;
- vfs_unbusy(mp, td);
- free(mp, M_MOUNT);
- vput(vp);
- }
- return (error);
-}
-
-/*
- * Scan all active processes to see if any of them have a current
- * or root directory of `olddp'. If so, replace them with the new
- * mount point.
- */
-static void
-checkdirs(olddp, newdp)
- struct vnode *olddp, *newdp;
-{
- struct filedesc *fdp;
- struct proc *p;
- int nrele;
-
- if (olddp->v_usecount == 1)
- return;
- sx_slock(&allproc_lock);
- LIST_FOREACH(p, &allproc, p_list) {
- PROC_LOCK(p);
- fdp = p->p_fd;
- if (fdp == NULL) {
- PROC_UNLOCK(p);
- continue;
- }
- nrele = 0;
- FILEDESC_LOCK(fdp);
- if (fdp->fd_cdir == olddp) {
- VREF(newdp);
- fdp->fd_cdir = newdp;
- nrele++;
- }
- if (fdp->fd_rdir == olddp) {
- VREF(newdp);
- fdp->fd_rdir = newdp;
- nrele++;
- }
- FILEDESC_UNLOCK(fdp);
- PROC_UNLOCK(p);
- while (nrele--)
- vrele(olddp);
- }
- sx_sunlock(&allproc_lock);
- if (rootvnode == olddp) {
- vrele(rootvnode);
- VREF(newdp);
- rootvnode = newdp;
- }
-}
-
-/*
- * Unmount a filesystem.
- *
- * Note: unmount takes a path to the vnode mounted on as argument,
- * not special file (as before).
- */
-#ifndef _SYS_SYSPROTO_H_
-struct unmount_args {
- char *path;
- int flags;
-};
-#endif
-/* ARGSUSED */
-int
-unmount(td, uap)
- struct thread *td;
- register struct unmount_args /* {
- syscallarg(char *) path;
- syscallarg(int) flags;
- } */ *uap;
-{
- register struct vnode *vp;
- struct mount *mp;
- int error;
- struct nameidata nd;
-
- NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
- SCARG(uap, path), td);
- if ((error = namei(&nd)) != 0)
- return (error);
- vp = nd.ni_vp;
- NDFREE(&nd, NDF_ONLY_PNBUF);
- mp = vp->v_mount;
-
- /*
- * Only root, or the user that did the original mount is
- * permitted to unmount this filesystem.
- */
- if (mp->mnt_stat.f_owner != td->td_ucred->cr_uid) {
- error = suser(td);
- if (error) {
- vput(vp);
- return (error);
- }
- }
-
- /*
- * Don't allow unmounting the root filesystem.
- */
- if (mp->mnt_flag & MNT_ROOTFS) {
- vput(vp);
- return (EINVAL);
- }
-
- /*
- * Must be the root of the filesystem
- */
- if ((vp->v_flag & VROOT) == 0) {
- vput(vp);
- return (EINVAL);
- }
- vput(vp);
- return (dounmount(mp, SCARG(uap, flags), td));
-}
-
-/*
- * Do the actual filesystem unmount.
- */
-int
-dounmount(mp, flags, td)
- struct mount *mp;
- int flags;
- struct thread *td;
-{
- struct vnode *coveredvp, *fsrootvp;
- int error;
- int async_flag;
-
- mtx_lock(&mountlist_mtx);
- if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
- mtx_unlock(&mountlist_mtx);
- return (EBUSY);
- }
- mp->mnt_kern_flag |= MNTK_UNMOUNT;
- /* Allow filesystems to detect that a forced unmount is in progress. */
- if (flags & MNT_FORCE)
- mp->mnt_kern_flag |= MNTK_UNMOUNTF;
- error = lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK |
- ((flags & MNT_FORCE) ? 0 : LK_NOWAIT), &mountlist_mtx, td);
- if (error) {
- mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF);
- if (mp->mnt_kern_flag & MNTK_MWAIT)
- wakeup(mp);
- return (error);
- }
- vn_start_write(NULL, &mp, V_WAIT);
-
- if (mp->mnt_flag & MNT_EXPUBLIC)
- vfs_setpublicfs(NULL, NULL, NULL);
-
- vfs_msync(mp, MNT_WAIT);
- async_flag = mp->mnt_flag & MNT_ASYNC;
- mp->mnt_flag &=~ MNT_ASYNC;
- cache_purgevfs(mp); /* remove cache entries for this file sys */
- if (mp->mnt_syncer != NULL)
- vrele(mp->mnt_syncer);
- /* Move process cdir/rdir refs on fs root to underlying vnode. */
- if (VFS_ROOT(mp, &fsrootvp) == 0) {
- if (mp->mnt_vnodecovered != NULL)
- checkdirs(fsrootvp, mp->mnt_vnodecovered);
- if (fsrootvp == rootvnode) {
- vrele(rootvnode);
- rootvnode = NULL;
- }
- vput(fsrootvp);
- }
- if (((mp->mnt_flag & MNT_RDONLY) ||
- (error = VFS_SYNC(mp, MNT_WAIT, td->td_ucred, td)) == 0) ||
- (flags & MNT_FORCE)) {
- error = VFS_UNMOUNT(mp, flags, td);
- }
- vn_finished_write(mp);
- if (error) {
- /* Undo cdir/rdir and rootvnode changes made above. */
- if (VFS_ROOT(mp, &fsrootvp) == 0) {
- if (mp->mnt_vnodecovered != NULL)
- checkdirs(mp->mnt_vnodecovered, fsrootvp);
- if (rootvnode == NULL) {
- rootvnode = fsrootvp;
- vref(rootvnode);
- }
- vput(fsrootvp);
- }
- if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL)
- (void) vfs_allocate_syncvnode(mp);
- mtx_lock(&mountlist_mtx);
- mp->mnt_kern_flag &= ~(MNTK_UNMOUNT | MNTK_UNMOUNTF);
- mp->mnt_flag |= async_flag;
- lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK,
- &mountlist_mtx, td);
- if (mp->mnt_kern_flag & MNTK_MWAIT)
- wakeup(mp);
- return (error);
- }
- mtx_lock(&mountlist_mtx);
- TAILQ_REMOVE(&mountlist, mp, mnt_list);
- if ((coveredvp = mp->mnt_vnodecovered) != NULL)
- coveredvp->v_mountedhere = NULL;
- mp->mnt_vfc->vfc_refcount--;
- if (!TAILQ_EMPTY(&mp->mnt_nvnodelist))
- panic("unmount: dangling vnode");
- lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_mtx, td);
- lockdestroy(&mp->mnt_lock);
- if (coveredvp != NULL)
- vrele(coveredvp);
- if (mp->mnt_kern_flag & MNTK_MWAIT)
- wakeup(mp);
- if (mp->mnt_op->vfs_mount == NULL)
- vfs_freeopts(mp->mnt_opt);
- free(mp, M_MOUNT);
- return (0);
-}
-
/*
* Sync each mounted filesystem.
*/
OpenPOWER on IntegriCloud