diff --git a/sys/fs/devfs/devfs_vfsops.c b/sys/fs/devfs/devfs_vfsops.c index a81a63ebf27a..dbc29fbe4d78 100644 --- a/sys/fs/devfs/devfs_vfsops.c +++ b/sys/fs/devfs/devfs_vfsops.c @@ -1,246 +1,246 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 1992, 1993, 1995 * The Regents of the University of California. All rights reserved. * Copyright (c) 2000 * Poul-Henning Kamp. All rights reserved. * * This code is derived from software donated to Berkeley by * Jan-Simon Pendry. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)kernfs_vfsops.c 8.10 (Berkeley) 5/14/95 * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36 */ #include #include #include #include #include #include #include #include #include #include #include #include static struct unrhdr *devfs_unr; MALLOC_DEFINE(M_DEVFS, "DEVFS", "DEVFS data"); static vfs_mount_t devfs_mount; static vfs_unmount_t devfs_unmount; static vfs_root_t devfs_root; static vfs_statfs_t devfs_statfs; static const char *devfs_opts[] = { "from", "export", "ruleset", NULL }; /* * Mount the filesystem */ static int devfs_mount(struct mount *mp) { int error; struct devfs_mount *fmp; struct vnode *rvp; struct thread *td = curthread; int injail, rsnum; if (devfs_unr == NULL) devfs_unr = new_unrhdr(0, INT_MAX, NULL); error = 0; if (mp->mnt_flag & MNT_ROOTFS) return (EOPNOTSUPP); rsnum = 0; injail = jailed(td->td_ucred); if (mp->mnt_optnew != NULL) { if (vfs_filteropt(mp->mnt_optnew, devfs_opts)) return (EINVAL); if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) return (EOPNOTSUPP); if (vfs_getopt(mp->mnt_optnew, "ruleset", NULL, NULL) == 0 && (vfs_scanopt(mp->mnt_optnew, "ruleset", "%d", &rsnum) != 1 || rsnum < 0 || rsnum > 65535)) { vfs_mount_error(mp, "%s", "invalid ruleset specification"); return (EINVAL); } if (injail && rsnum != 0 && rsnum != td->td_ucred->cr_prison->pr_devfs_rsnum) return (EPERM); } /* jails enforce their ruleset */ if (injail) rsnum = td->td_ucred->cr_prison->pr_devfs_rsnum; if (mp->mnt_flag & MNT_UPDATE) { if (rsnum != 0) { fmp = mp->mnt_data; if (fmp != NULL) { sx_xlock(&fmp->dm_lock); devfs_ruleset_set((devfs_rsnum)rsnum, fmp); devfs_ruleset_apply(fmp); sx_xunlock(&fmp->dm_lock); } } return (0); } fmp = malloc(sizeof *fmp, M_DEVFS, M_WAITOK | M_ZERO); fmp->dm_idx = alloc_unr(devfs_unr); sx_init(&fmp->dm_lock, "devfsmount"); fmp->dm_holdcnt = 1; MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED | MNTK_NOMSYNC; #ifdef MAC mp->mnt_flag |= MNT_MULTILABEL; #endif MNT_IUNLOCK(mp); fmp->dm_mount = mp; mp->mnt_data = (void *) fmp; vfs_getnewfsid(mp); fmp->dm_rootdir = devfs_vmkdir(fmp, NULL, 0, NULL, DEVFS_ROOTINO); error = devfs_root(mp, LK_EXCLUSIVE, &rvp); if (error) { sx_destroy(&fmp->dm_lock); free_unr(devfs_unr, fmp->dm_idx); free(fmp, M_DEVFS); return (error); } if (rsnum != 0) { sx_xlock(&fmp->dm_lock); devfs_ruleset_set((devfs_rsnum)rsnum, fmp); sx_xunlock(&fmp->dm_lock); } VOP_UNLOCK(rvp); vfs_cache_root_set(mp, rvp); vfs_mountedfrom(mp, "devfs"); return (0); } void devfs_unmount_final(struct devfs_mount *fmp) { sx_destroy(&fmp->dm_lock); free(fmp, M_DEVFS); } static int devfs_unmount(struct mount *mp, int mntflags) { int error; int flags = 0; struct devfs_mount *fmp; int hold; u_int idx; fmp = VFSTODEVFS(mp); KASSERT(fmp->dm_mount != NULL, ("devfs_unmount unmounted devfs_mount")); if (mntflags & MNT_FORCE) flags |= FORCECLOSE; /* There is 1 extra root vnode reference from devfs_mount(). */ error = vflush(mp, 1, flags, curthread); if (error) return (error); sx_xlock(&fmp->dm_lock); devfs_cleanup(fmp); devfs_rules_cleanup(fmp); fmp->dm_mount = NULL; hold = --fmp->dm_holdcnt; mp->mnt_data = NULL; idx = fmp->dm_idx; sx_xunlock(&fmp->dm_lock); free_unr(devfs_unr, idx); if (hold == 0) devfs_unmount_final(fmp); return 0; } /* Return locked reference to root. */ static int devfs_root(struct mount *mp, int flags, struct vnode **vpp) { int error; struct vnode *vp; struct devfs_mount *dmp; dmp = VFSTODEVFS(mp); sx_xlock(&dmp->dm_lock); error = devfs_allocv(dmp->dm_rootdir, mp, LK_EXCLUSIVE, &vp); if (error) return (error); vp->v_vflag |= VV_ROOT; *vpp = vp; return (0); } static int devfs_statfs(struct mount *mp, struct statfs *sbp) { - sbp->f_flags = 0; + sbp->f_flags = mp->mnt_flag & MNT_IGNORE; sbp->f_bsize = DEV_BSIZE; sbp->f_iosize = DEV_BSIZE; sbp->f_blocks = 2; /* 1K to keep df happy */ sbp->f_bfree = 2; sbp->f_bavail = 2; sbp->f_files = 0; sbp->f_ffree = 0; return (0); } static struct vfsops devfs_vfsops = { .vfs_mount = devfs_mount, .vfs_root = vfs_cache_root, .vfs_cachedroot = devfs_root, .vfs_statfs = devfs_statfs, .vfs_unmount = devfs_unmount, }; VFS_SET(devfs_vfsops, devfs, VFCF_SYNTHETIC | VFCF_JAIL); diff --git a/sys/fs/fdescfs/fdesc_vfsops.c b/sys/fs/fdescfs/fdesc_vfsops.c index 309134798374..30924580dece 100644 --- a/sys/fs/fdescfs/fdesc_vfsops.c +++ b/sys/fs/fdescfs/fdesc_vfsops.c @@ -1,243 +1,243 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1992, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software donated to Berkeley by * Jan-Simon Pendry. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)fdesc_vfsops.c 8.4 (Berkeley) 1/21/94 */ /* * /dev/fd Filesystem */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static MALLOC_DEFINE(M_FDESCMNT, "fdesc_mount", "FDESC mount structure"); static vfs_cmount_t fdesc_cmount; static vfs_mount_t fdesc_mount; static vfs_unmount_t fdesc_unmount; static vfs_statfs_t fdesc_statfs; static vfs_root_t fdesc_root; /* * Compatibility shim for old mount(2) system call. */ int fdesc_cmount(struct mntarg *ma, void *data, uint64_t flags) { return kernel_mount(ma, flags); } /* * Mount the per-process file descriptors (/dev/fd) */ static int fdesc_mount(struct mount *mp) { struct fdescmount *fmp; struct vnode *rvp; int error; /* * Update is a no-op */ if (mp->mnt_flag & (MNT_UPDATE | MNT_ROOTFS)) return (EOPNOTSUPP); fmp = malloc(sizeof(struct fdescmount), M_FDESCMNT, M_WAITOK); /* * We need to initialize a few bits of our local mount point struct to * avoid confusion in allocvp. */ mp->mnt_data = fmp; fmp->flags = 0; if (vfs_getopt(mp->mnt_optnew, "linrdlnk", NULL, NULL) == 0) fmp->flags |= FMNT_LINRDLNKF; if (vfs_getopt(mp->mnt_optnew, "rdlnk", NULL, NULL) == 0) fmp->flags |= FMNT_RDLNKF; if (vfs_getopt(mp->mnt_optnew, "nodup", NULL, NULL) == 0) fmp->flags |= FMNT_NODUP; error = fdesc_allocvp(Froot, -1, FD_ROOT, mp, &rvp); if (error) { free(fmp, M_FDESCMNT); mp->mnt_data = NULL; return (error); } VN_LOCK_ASHARE(rvp); rvp->v_type = VDIR; rvp->v_vflag |= VV_ROOT; fmp->f_root = rvp; VOP_UNLOCK(rvp); MNT_ILOCK(mp); /* XXX -- don't mark as local to work around fts() problems */ /*mp->mnt_flag |= MNT_LOCAL;*/ /* * Enable shared locking so that there is no contention on the root * vnode. Note only root vnode enables shared locking for itself, * so this end up being a nop for the rest. */ mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED; MNT_IUNLOCK(mp); vfs_getnewfsid(mp); vfs_mountedfrom(mp, "fdescfs"); return (0); } static int fdesc_unmount(struct mount *mp, int mntflags) { struct fdescmount *fmp; int error, flags; flags = 0; fmp = mp->mnt_data; if (mntflags & MNT_FORCE) { /* The hash mutex protects the private mount flags. */ mtx_lock(&fdesc_hashmtx); fmp->flags |= FMNT_UNMOUNTF; mtx_unlock(&fdesc_hashmtx); flags |= FORCECLOSE; } /* * Clear out buffer cache. I don't think we * ever get anything cached at this level at the * moment, but who knows... * * There is 1 extra root vnode reference corresponding * to f_root. */ if ((error = vflush(mp, 1, flags, curthread)) != 0) return (error); /* * Finally, throw away the fdescmount structure. */ mp->mnt_data = NULL; free(fmp, M_FDESCMNT); return (0); } static int fdesc_root(struct mount *mp, int flags, struct vnode **vpp) { struct vnode *vp; /* * Return locked reference to root. */ vp = VFSTOFDESC(mp)->f_root; vget(vp, flags | LK_RETRY); *vpp = vp; return (0); } static int fdesc_statfs(struct mount *mp, struct statfs *sbp) { struct thread *td; struct filedesc *fdp; int lim; int i; int last; int freefd; uint64_t limit; td = curthread; /* * Compute number of free file descriptors. * [ Strange results will ensue if the open file * limit is ever reduced below the current number * of open files... ] */ lim = lim_cur(td, RLIMIT_NOFILE); fdp = td->td_proc->p_fd; FILEDESC_SLOCK(fdp); limit = racct_get_limit(td->td_proc, RACCT_NOFILE); if (lim > limit) lim = limit; last = min(fdp->fd_nfiles, lim); freefd = 0; for (i = fdp->fd_freefile; i < last; i++) if (fdp->fd_ofiles[i].fde_file == NULL) freefd++; /* * Adjust for the fact that the fdesc array may not * have been fully allocated yet. */ if (fdp->fd_nfiles < lim) freefd += (lim - fdp->fd_nfiles); FILEDESC_SUNLOCK(fdp); - sbp->f_flags = 0; + sbp->f_flags = mp->mnt_flag & MNT_IGNORE; sbp->f_bsize = DEV_BSIZE; sbp->f_iosize = DEV_BSIZE; sbp->f_blocks = 2; /* 1K to keep df happy */ sbp->f_bfree = 2; sbp->f_bavail = 2; sbp->f_files = lim + 1; /* Allow for "." */ sbp->f_ffree = freefd; /* See comments above */ return (0); } static struct vfsops fdesc_vfsops = { .vfs_cmount = fdesc_cmount, .vfs_init = fdesc_init, .vfs_mount = fdesc_mount, .vfs_root = fdesc_root, .vfs_statfs = fdesc_statfs, .vfs_uninit = fdesc_uninit, .vfs_unmount = fdesc_unmount, }; VFS_SET(fdesc_vfsops, fdescfs, VFCF_SYNTHETIC | VFCF_JAIL); diff --git a/sys/fs/nullfs/null_vfsops.c b/sys/fs/nullfs/null_vfsops.c index 6acff89189f5..4b2954d5bea1 100644 --- a/sys/fs/nullfs/null_vfsops.c +++ b/sys/fs/nullfs/null_vfsops.c @@ -1,490 +1,490 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1992, 1993, 1995 * The Regents of the University of California. All rights reserved. * * This code is derived from software donated to Berkeley by * Jan-Simon Pendry. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94 * * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 */ /* * Null Layer * (See null_vnops.c for a description of what this does.) */ #include #include #include #include #include #include #include #include #include #include #include #include static MALLOC_DEFINE(M_NULLFSMNT, "nullfs_mount", "NULLFS mount structure"); static vfs_fhtovp_t nullfs_fhtovp; static vfs_mount_t nullfs_mount; static vfs_quotactl_t nullfs_quotactl; static vfs_root_t nullfs_root; static vfs_sync_t nullfs_sync; static vfs_statfs_t nullfs_statfs; static vfs_unmount_t nullfs_unmount; static vfs_vget_t nullfs_vget; static vfs_extattrctl_t nullfs_extattrctl; /* * Mount null layer */ static int nullfs_mount(struct mount *mp) { struct vnode *lowerrootvp; struct vnode *nullm_rootvp; struct null_mount *xmp; struct null_node *nn; struct nameidata nd, *ndp; char *target; int error, len; bool isvnunlocked; NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp); if (mp->mnt_flag & MNT_ROOTFS) return (EOPNOTSUPP); /* * Update is a no-op */ if (mp->mnt_flag & MNT_UPDATE) { /* * Only support update mounts for NFS export. */ if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) return (0); else return (EOPNOTSUPP); } /* * Get argument */ error = vfs_getopt(mp->mnt_optnew, "from", (void **)&target, &len); if (error != 0) error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len); if (error || target[len - 1] != '\0') return (EINVAL); /* * Unlock lower node to avoid possible deadlock. */ if (mp->mnt_vnodecovered->v_op == &null_vnodeops && VOP_ISLOCKED(mp->mnt_vnodecovered) == LK_EXCLUSIVE) { VOP_UNLOCK(mp->mnt_vnodecovered); isvnunlocked = true; } else { isvnunlocked = false; } /* * Find lower node */ ndp = &nd; NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target); error = namei(ndp); /* * Re-lock vnode. * XXXKIB This is deadlock-prone as well. */ if (isvnunlocked) vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY); if (error) return (error); NDFREE_PNBUF(ndp); /* * Sanity check on lower vnode */ lowerrootvp = ndp->ni_vp; /* * Check multi null mount to avoid `lock against myself' panic. */ if (mp->mnt_vnodecovered->v_op == &null_vnodeops) { nn = VTONULL(mp->mnt_vnodecovered); if (nn == NULL || lowerrootvp == nn->null_lowervp) { NULLFSDEBUG("nullfs_mount: multi null mount?\n"); vput(lowerrootvp); return (EDEADLK); } } /* * Lower vnode must be the same type as the covered vnode - we * don't allow mounting directories to files or vice versa. */ if ((lowerrootvp->v_type != VDIR && lowerrootvp->v_type != VREG) || lowerrootvp->v_type != mp->mnt_vnodecovered->v_type) { NULLFSDEBUG("nullfs_mount: target must be same type as fspath"); vput(lowerrootvp); return (EINVAL); } xmp = (struct null_mount *) malloc(sizeof(struct null_mount), M_NULLFSMNT, M_WAITOK | M_ZERO); /* * Save pointer to underlying FS and the reference to the * lower root vnode. */ xmp->nullm_vfs = vfs_register_upper_from_vp(lowerrootvp, mp, &xmp->upper_node); if (xmp->nullm_vfs == NULL) { vput(lowerrootvp); free(xmp, M_NULLFSMNT); return (ENOENT); } vref(lowerrootvp); xmp->nullm_lowerrootvp = lowerrootvp; mp->mnt_data = xmp; /* * Make sure the node alias worked. */ error = null_nodeget(mp, lowerrootvp, &nullm_rootvp); if (error != 0) { vfs_unregister_upper(xmp->nullm_vfs, &xmp->upper_node); vrele(lowerrootvp); free(xmp, M_NULLFSMNT); return (error); } if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) { MNT_ILOCK(mp); mp->mnt_flag |= MNT_LOCAL; MNT_IUNLOCK(mp); } xmp->nullm_flags |= NULLM_CACHE; if (vfs_getopt(mp->mnt_optnew, "nocache", NULL, NULL) == 0 || (xmp->nullm_vfs->mnt_kern_flag & MNTK_NULL_NOCACHE) != 0) xmp->nullm_flags &= ~NULLM_CACHE; if ((xmp->nullm_flags & NULLM_CACHE) != 0) { vfs_register_for_notification(xmp->nullm_vfs, mp, &xmp->notify_node); } if (lowerrootvp == mp->mnt_vnodecovered) { vn_lock(lowerrootvp, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE); lowerrootvp->v_vflag |= VV_CROSSLOCK; VOP_UNLOCK(lowerrootvp); } MNT_ILOCK(mp); if ((xmp->nullm_flags & NULLM_CACHE) != 0) { mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & (MNTK_SHARED_WRITES | MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED); } mp->mnt_kern_flag |= MNTK_NOMSYNC | MNTK_UNLOCKED_INSMNTQUE; mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & (MNTK_USES_BCACHE | MNTK_NO_IOPF | MNTK_UNMAPPED_BUFS); MNT_IUNLOCK(mp); vfs_getnewfsid(mp); vfs_mountedfrom(mp, target); vput(nullm_rootvp); NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n", mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); return (0); } /* * Free reference to null layer */ static int nullfs_unmount(struct mount *mp, int mntflags) { struct null_mount *mntdata; int error, flags; NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp); if (mntflags & MNT_FORCE) flags = FORCECLOSE; else flags = 0; for (;;) { /* There is 1 extra root vnode reference (nullm_rootvp). */ error = vflush(mp, 0, flags, curthread); if (error) return (error); MNT_ILOCK(mp); if (mp->mnt_nvnodelistsize == 0) { MNT_IUNLOCK(mp); break; } MNT_IUNLOCK(mp); if ((mntflags & MNT_FORCE) == 0) return (EBUSY); } /* * Finally, throw away the null_mount structure */ mntdata = mp->mnt_data; if ((mntdata->nullm_flags & NULLM_CACHE) != 0) { vfs_unregister_for_notification(mntdata->nullm_vfs, &mntdata->notify_node); } if (mntdata->nullm_lowerrootvp == mp->mnt_vnodecovered) { vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE); mp->mnt_vnodecovered->v_vflag &= ~VV_CROSSLOCK; VOP_UNLOCK(mp->mnt_vnodecovered); } vfs_unregister_upper(mntdata->nullm_vfs, &mntdata->upper_node); vrele(mntdata->nullm_lowerrootvp); mp->mnt_data = NULL; free(mntdata, M_NULLFSMNT); return (0); } static int nullfs_root(struct mount *mp, int flags, struct vnode **vpp) { struct vnode *vp; struct null_mount *mntdata; int error; mntdata = MOUNTTONULLMOUNT(mp); NULLFSDEBUG("nullfs_root(mp = %p, vp = %p)\n", mp, mntdata->nullm_lowerrootvp); error = vget(mntdata->nullm_lowerrootvp, flags); if (error == 0) { error = null_nodeget(mp, mntdata->nullm_lowerrootvp, &vp); if (error == 0) { *vpp = vp; } } return (error); } static int nullfs_quotactl(struct mount *mp, int cmd, uid_t uid, void *arg, bool *mp_busy) { struct mount *lowermp; struct null_mount *mntdata; int error; bool unbusy; mntdata = MOUNTTONULLMOUNT(mp); lowermp = atomic_load_ptr(&mntdata->nullm_vfs); KASSERT(*mp_busy == true, ("upper mount not busy")); /* * See comment in sys_quotactl() for an explanation of why the * lower mount needs to be busied by the caller of VFS_QUOTACTL() * but may be unbusied by the implementation. We must unbusy * the upper mount for the same reason; otherwise a namei lookup * issued by the VFS_QUOTACTL() implementation could traverse the * upper mount and deadlock. */ vfs_unbusy(mp); *mp_busy = false; unbusy = true; error = vfs_busy(lowermp, 0); if (error == 0) error = VFS_QUOTACTL(lowermp, cmd, uid, arg, &unbusy); if (unbusy) vfs_unbusy(lowermp); return (error); } static int nullfs_statfs(struct mount *mp, struct statfs *sbp) { int error; struct statfs *mstat; NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp, (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); mstat = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK | M_ZERO); error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, mstat); if (error) { free(mstat, M_STATFS); return (error); } /* now copy across the "interesting" information and fake the rest */ sbp->f_type = mstat->f_type; sbp->f_flags = (sbp->f_flags & (MNT_RDONLY | MNT_NOEXEC | MNT_NOSUID | - MNT_UNION | MNT_NOSYMFOLLOW | MNT_AUTOMOUNTED)) | + MNT_UNION | MNT_NOSYMFOLLOW | MNT_AUTOMOUNTED | MNT_IGNORE)) | (mstat->f_flags & ~(MNT_ROOTFS | MNT_AUTOMOUNTED)); sbp->f_bsize = mstat->f_bsize; sbp->f_iosize = mstat->f_iosize; sbp->f_blocks = mstat->f_blocks; sbp->f_bfree = mstat->f_bfree; sbp->f_bavail = mstat->f_bavail; sbp->f_files = mstat->f_files; sbp->f_ffree = mstat->f_ffree; free(mstat, M_STATFS); return (0); } static int nullfs_sync(struct mount *mp, int waitfor) { /* * XXX - Assumes no data cached at null layer. */ return (0); } static int nullfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) { int error; KASSERT((flags & LK_TYPE_MASK) != 0, ("nullfs_vget: no lock requested")); error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, flags, vpp); if (error != 0) return (error); return (null_nodeget(mp, *vpp, vpp)); } static int nullfs_fhtovp(struct mount *mp, struct fid *fidp, int flags, struct vnode **vpp) { int error; error = VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, flags, vpp); if (error != 0) return (error); return (null_nodeget(mp, *vpp, vpp)); } static int nullfs_extattrctl(struct mount *mp, int cmd, struct vnode *filename_vp, int namespace, const char *attrname) { return (VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, filename_vp, namespace, attrname)); } static void nullfs_reclaim_lowervp(struct mount *mp, struct vnode *lowervp) { struct vnode *vp; vp = null_hashget(mp, lowervp); if (vp == NULL) return; VTONULL(vp)->null_flags |= NULLV_NOUNLOCK; vgone(vp); vput(vp); } static void nullfs_unlink_lowervp(struct mount *mp, struct vnode *lowervp) { struct vnode *vp; struct null_node *xp; vp = null_hashget(mp, lowervp); if (vp == NULL) return; xp = VTONULL(vp); xp->null_flags |= NULLV_DROP | NULLV_NOUNLOCK; vhold(vp); vunref(vp); if (vp->v_usecount == 0) { /* * If vunref() dropped the last use reference on the * nullfs vnode, it must be reclaimed, and its lock * was split from the lower vnode lock. Need to do * extra unlock before allowing the final vdrop() to * free the vnode. */ KASSERT(VN_IS_DOOMED(vp), ("not reclaimed nullfs vnode %p", vp)); VOP_UNLOCK(vp); } else { /* * Otherwise, the nullfs vnode still shares the lock * with the lower vnode, and must not be unlocked. * Also clear the NULLV_NOUNLOCK, the flag is not * relevant for future reclamations. */ ASSERT_VOP_ELOCKED(vp, "unlink_lowervp"); KASSERT(!VN_IS_DOOMED(vp), ("reclaimed nullfs vnode %p", vp)); xp->null_flags &= ~NULLV_NOUNLOCK; } vdrop(vp); } static struct vfsops null_vfsops = { .vfs_extattrctl = nullfs_extattrctl, .vfs_fhtovp = nullfs_fhtovp, .vfs_init = nullfs_init, .vfs_mount = nullfs_mount, .vfs_quotactl = nullfs_quotactl, .vfs_root = nullfs_root, .vfs_statfs = nullfs_statfs, .vfs_sync = nullfs_sync, .vfs_uninit = nullfs_uninit, .vfs_unmount = nullfs_unmount, .vfs_vget = nullfs_vget, .vfs_reclaim_lowervp = nullfs_reclaim_lowervp, .vfs_unlink_lowervp = nullfs_unlink_lowervp, }; VFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK | VFCF_JAIL | VFCF_FILEMOUNT);