null_vfsops.c revision 240285
11830SN/A/*- 22224Sctornqvi * Copyright (c) 1992, 1993, 1995 31830SN/A * The Regents of the University of California. All rights reserved. 41830SN/A * 51830SN/A * This code is derived from software donated to Berkeley by 61830SN/A * Jan-Simon Pendry. 71830SN/A * 81830SN/A * Redistribution and use in source and binary forms, with or without 91830SN/A * modification, are permitted provided that the following conditions 101830SN/A * are met: 111830SN/A * 1. Redistributions of source code must retain the above copyright 121830SN/A * notice, this list of conditions and the following disclaimer. 131830SN/A * 2. Redistributions in binary form must reproduce the above copyright 141830SN/A * notice, this list of conditions and the following disclaimer in the 151830SN/A * documentation and/or other materials provided with the distribution. 161830SN/A * 4. Neither the name of the University nor the names of its contributors 171830SN/A * may be used to endorse or promote products derived from this software 181830SN/A * without specific prior written permission. 191830SN/A * 201830SN/A * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211830SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221830SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231830SN/A * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241830SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251830SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261830SN/A * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271830SN/A * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281830SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291830SN/A * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301830SN/A * SUCH DAMAGE. 311830SN/A * 321830SN/A * @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94 331830SN/A * 341830SN/A * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 351830SN/A * $FreeBSD: head/sys/fs/nullfs/null_vfsops.c 240285 2012-09-09 19:20:23Z kib $ 361830SN/A */ 371830SN/A 381830SN/A/* 391830SN/A * Null Layer 401830SN/A * (See null_vnops.c for a description of what this does.) 411830SN/A */ 421830SN/A 431830SN/A#include <sys/param.h> 441830SN/A#include <sys/systm.h> 451830SN/A#include <sys/fcntl.h> 461830SN/A#include <sys/kernel.h> 471830SN/A#include <sys/lock.h> 481830SN/A#include <sys/malloc.h> 491830SN/A#include <sys/mount.h> 501830SN/A#include <sys/namei.h> 511830SN/A#include <sys/proc.h> 521830SN/A#include <sys/vnode.h> 531830SN/A#include <sys/jail.h> 541830SN/A 551830SN/A#include <fs/nullfs/null.h> 561830SN/A 571830SN/Astatic MALLOC_DEFINE(M_NULLFSMNT, "nullfs_mount", "NULLFS mount structure"); 581830SN/A 591830SN/Astatic vfs_fhtovp_t nullfs_fhtovp; 601830SN/Astatic vfs_mount_t nullfs_mount; 611830SN/Astatic vfs_quotactl_t nullfs_quotactl; 621830SN/Astatic vfs_root_t nullfs_root; 631830SN/Astatic vfs_sync_t nullfs_sync; 641830SN/Astatic vfs_statfs_t nullfs_statfs; 651830SN/Astatic vfs_unmount_t nullfs_unmount; 661830SN/Astatic vfs_vget_t nullfs_vget; 671830SN/Astatic vfs_extattrctl_t nullfs_extattrctl; 681830SN/Astatic vfs_reclaim_lowervp_t nullfs_reclaim_lowervp; 691830SN/A 701830SN/A/* 711830SN/A * Mount null layer 721830SN/A */ 731830SN/Astatic int 741830SN/Anullfs_mount(struct mount *mp) 751830SN/A{ 761830SN/A int error = 0; 771830SN/A struct vnode *lowerrootvp, *vp; 781830SN/A struct vnode *nullm_rootvp; 791830SN/A struct null_mount *xmp; 801830SN/A struct thread *td = curthread; 811830SN/A char *target; 821830SN/A int isvnunlocked = 0, len; 831830SN/A struct nameidata nd, *ndp = &nd; 841830SN/A 851830SN/A NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp); 861830SN/A 871830SN/A if (!prison_allow(td->td_ucred, PR_ALLOW_MOUNT_NULLFS)) 881830SN/A return (EPERM); 891830SN/A 901830SN/A if (mp->mnt_flag & MNT_ROOTFS) 911830SN/A return (EOPNOTSUPP); 921830SN/A /* 931830SN/A * Update is a no-op 941830SN/A */ 951830SN/A if (mp->mnt_flag & MNT_UPDATE) { 961830SN/A /* 971830SN/A * Only support update mounts for NFS export. 981830SN/A */ 991830SN/A if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) 1001830SN/A return (0); 1011830SN/A else 1021830SN/A return (EOPNOTSUPP); 1031830SN/A } 1041830SN/A 1051830SN/A /* 1061830SN/A * Get argument 1071830SN/A */ 1081830SN/A error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len); 1091830SN/A if (error || target[len - 1] != '\0') 1101830SN/A return (EINVAL); 1111830SN/A 1121830SN/A /* 1131830SN/A * Unlock lower node to avoid possible deadlock. 1141830SN/A */ 1151830SN/A if ((mp->mnt_vnodecovered->v_op == &null_vnodeops) && 1161830SN/A VOP_ISLOCKED(mp->mnt_vnodecovered) == LK_EXCLUSIVE) { 1171830SN/A VOP_UNLOCK(mp->mnt_vnodecovered, 0); 1181830SN/A isvnunlocked = 1; 1191830SN/A } 1201830SN/A /* 1211830SN/A * Find lower node 1221830SN/A */ 1231830SN/A NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target, curthread); 1241830SN/A error = namei(ndp); 1251830SN/A 1261830SN/A /* 1271830SN/A * Re-lock vnode. 1281830SN/A * XXXKIB This is deadlock-prone as well. 1291830SN/A */ 1301830SN/A if (isvnunlocked) 1311830SN/A vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY); 1321830SN/A 1331830SN/A if (error) 1341830SN/A return (error); 1351830SN/A NDFREE(ndp, NDF_ONLY_PNBUF); 1361830SN/A 1371830SN/A /* 1381830SN/A * Sanity check on lower vnode 1391830SN/A */ 1401830SN/A lowerrootvp = ndp->ni_vp; 1411830SN/A 1421830SN/A /* 1431830SN/A * Check multi null mount to avoid `lock against myself' panic. 1441830SN/A */ 1451830SN/A if (lowerrootvp == VTONULL(mp->mnt_vnodecovered)->null_lowervp) { 1461830SN/A NULLFSDEBUG("nullfs_mount: multi null mount?\n"); 1471830SN/A vput(lowerrootvp); 1481830SN/A return (EDEADLK); 1491830SN/A } 1501830SN/A 1511830SN/A xmp = (struct null_mount *) malloc(sizeof(struct null_mount), 1521830SN/A M_NULLFSMNT, M_WAITOK); 1531830SN/A 1541830SN/A /* 1551830SN/A * Save reference to underlying FS 1561830SN/A */ 1571830SN/A xmp->nullm_vfs = lowerrootvp->v_mount; 1581830SN/A 1591830SN/A /* 1601830SN/A * Save reference. Each mount also holds 1611830SN/A * a reference on the root vnode. 1621830SN/A */ 1631830SN/A error = null_nodeget(mp, lowerrootvp, &vp); 1641830SN/A /* 1651830SN/A * Make sure the node alias worked 1661830SN/A */ 1671830SN/A if (error) { 1681830SN/A free(xmp, M_NULLFSMNT); 1691830SN/A return (error); 1701830SN/A } 1711830SN/A 1721830SN/A /* 1731830SN/A * Keep a held reference to the root vnode. 1741830SN/A * It is vrele'd in nullfs_unmount. 1751830SN/A */ 1761830SN/A nullm_rootvp = vp; 1771830SN/A nullm_rootvp->v_vflag |= VV_ROOT; 1781830SN/A xmp->nullm_rootvp = nullm_rootvp; 1791830SN/A 1801830SN/A /* 1811830SN/A * Unlock the node (either the lower or the alias) 1821830SN/A */ 1831830SN/A VOP_UNLOCK(vp, 0); 1841830SN/A 1851830SN/A if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) { 1861830SN/A MNT_ILOCK(mp); 1871830SN/A mp->mnt_flag |= MNT_LOCAL; 1881830SN/A MNT_IUNLOCK(mp); 1891830SN/A } 1901830SN/A MNT_ILOCK(mp); 1911830SN/A mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & 1921830SN/A (MNTK_MPSAFE | MNTK_SHARED_WRITES | MNTK_LOOKUP_SHARED | 1931830SN/A MNTK_EXTENDED_SHARED); 1941830SN/A mp->mnt_kern_flag |= MNTK_LOOKUP_EXCL_DOTDOT; 1951830SN/A MNT_IUNLOCK(mp); 1961830SN/A mp->mnt_data = xmp; 1971830SN/A vfs_getnewfsid(mp); 1981830SN/A MNT_ILOCK(xmp->nullm_vfs); 1991830SN/A TAILQ_INSERT_TAIL(&xmp->nullm_vfs->mnt_uppers, mp, mnt_upper_link); 2001830SN/A MNT_IUNLOCK(xmp->nullm_vfs); 2011830SN/A 2021830SN/A vfs_mountedfrom(mp, target); 2031830SN/A 2041830SN/A NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n", 2051830SN/A mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 2061830SN/A return (0); 2071830SN/A} 2081830SN/A 2091830SN/A/* 2101830SN/A * Free reference to null layer 2111830SN/A */ 2121830SN/Astatic int 2131830SN/Anullfs_unmount(mp, mntflags) 2141830SN/A struct mount *mp; 2151830SN/A int mntflags; 2161830SN/A{ 2171830SN/A struct null_mount *mntdata; 2181830SN/A struct mount *ump; 2191830SN/A int error, flags; 2201830SN/A 2211830SN/A NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp); 2221830SN/A 2231830SN/A if (mntflags & MNT_FORCE) 2241830SN/A flags = FORCECLOSE; 2251830SN/A else 2261830SN/A flags = 0; 2271830SN/A 2281830SN/A /* There is 1 extra root vnode reference (nullm_rootvp). */ 2291830SN/A error = vflush(mp, 1, flags, curthread); 2301830SN/A if (error) 2311830SN/A return (error); 2321830SN/A 2331830SN/A /* 2341830SN/A * Finally, throw away the null_mount structure 2351830SN/A */ 2361830SN/A mntdata = mp->mnt_data; 2371830SN/A ump = mntdata->nullm_vfs; 2381830SN/A MNT_ILOCK(ump); 2391830SN/A while ((ump->mnt_kern_flag & MNTK_VGONE_UPPER) != 0) { 2401830SN/A ump->mnt_kern_flag |= MNTK_VGONE_WAITER; 2411830SN/A msleep(&ump->mnt_uppers, &ump->mnt_mtx, 0, "vgnupw", 0); 2421830SN/A } 2431830SN/A TAILQ_REMOVE(&ump->mnt_uppers, mp, mnt_upper_link); 2441830SN/A MNT_IUNLOCK(ump); 2451830SN/A mp->mnt_data = NULL; 2461830SN/A free(mntdata, M_NULLFSMNT); 2471830SN/A return (0); 2481830SN/A} 2491830SN/A 2501830SN/Astatic int 2511830SN/Anullfs_root(mp, flags, vpp) 2521830SN/A struct mount *mp; 2531830SN/A int flags; 2541830SN/A struct vnode **vpp; 2551830SN/A{ 2561830SN/A struct vnode *vp; 2571830SN/A 2581830SN/A NULLFSDEBUG("nullfs_root(mp = %p, vp = %p->%p)\n", (void *)mp, 2591830SN/A (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 2601830SN/A (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 2611830SN/A 2621830SN/A /* 2631830SN/A * Return locked reference to root. 2641830SN/A */ 2651830SN/A vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 2661830SN/A VREF(vp); 2671830SN/A 2681830SN/A ASSERT_VOP_UNLOCKED(vp, "root vnode is locked"); 2691830SN/A vn_lock(vp, flags | LK_RETRY); 2701830SN/A *vpp = vp; 2711830SN/A return 0; 2721830SN/A} 2731830SN/A 2741830SN/Astatic int 2751830SN/Anullfs_quotactl(mp, cmd, uid, arg) 2761830SN/A struct mount *mp; 2771830SN/A int cmd; 2781830SN/A uid_t uid; 2791830SN/A void *arg; 2801830SN/A{ 2811830SN/A return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg); 2821830SN/A} 2831830SN/A 2841830SN/Astatic int 2851830SN/Anullfs_statfs(mp, sbp) 2861830SN/A struct mount *mp; 2871830SN/A struct statfs *sbp; 2881830SN/A{ 2891830SN/A int error; 2901830SN/A struct statfs mstat; 2911830SN/A 2921830SN/A NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp, 2931830SN/A (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 2941830SN/A (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 2951830SN/A 2961830SN/A bzero(&mstat, sizeof(mstat)); 2971830SN/A 2981830SN/A error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat); 2991830SN/A if (error) 3001830SN/A return (error); 3011830SN/A 3021830SN/A /* now copy across the "interesting" information and fake the rest */ 3031830SN/A sbp->f_type = mstat.f_type; 3041830SN/A sbp->f_flags = mstat.f_flags; 3051830SN/A sbp->f_bsize = mstat.f_bsize; 3061830SN/A sbp->f_iosize = mstat.f_iosize; 3071830SN/A sbp->f_blocks = mstat.f_blocks; 3081830SN/A sbp->f_bfree = mstat.f_bfree; 3091830SN/A sbp->f_bavail = mstat.f_bavail; 3101830SN/A sbp->f_files = mstat.f_files; 3111830SN/A sbp->f_ffree = mstat.f_ffree; 3121830SN/A return (0); 3131830SN/A} 3141830SN/A 3151830SN/Astatic int 3161830SN/Anullfs_sync(mp, waitfor) 3171830SN/A struct mount *mp; 3181830SN/A int waitfor; 3191830SN/A{ 3201830SN/A /* 3211830SN/A * XXX - Assumes no data cached at null layer. 3221830SN/A */ 3231830SN/A return (0); 3241830SN/A} 3251830SN/A 3261830SN/Astatic int 3271830SN/Anullfs_vget(mp, ino, flags, vpp) 3281830SN/A struct mount *mp; 3291830SN/A ino_t ino; 3301830SN/A int flags; 3311830SN/A struct vnode **vpp; 3321830SN/A{ 3331830SN/A int error; 3341830SN/A 3351830SN/A KASSERT((flags & LK_TYPE_MASK) != 0, 3361830SN/A ("nullfs_vget: no lock requested")); 3371830SN/A 3381830SN/A error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, flags, vpp); 3391830SN/A if (error != 0) 3401830SN/A return (error); 3411830SN/A return (null_nodeget(mp, *vpp, vpp)); 3421830SN/A} 3431830SN/A 3441830SN/Astatic int 3451830SN/Anullfs_fhtovp(mp, fidp, flags, vpp) 3461830SN/A struct mount *mp; 3471830SN/A struct fid *fidp; 3481830SN/A int flags; 3491830SN/A struct vnode **vpp; 3501830SN/A{ 3511830SN/A int error; 3521830SN/A 3531830SN/A error = VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, flags, 3541830SN/A vpp); 3551830SN/A if (error != 0) 3561830SN/A return (error); 3571830SN/A return (null_nodeget(mp, *vpp, vpp)); 3581830SN/A} 3591830SN/A 3601830SN/Astatic int 3611830SN/Anullfs_extattrctl(mp, cmd, filename_vp, namespace, attrname) 3621830SN/A struct mount *mp; 3631830SN/A int cmd; 3641830SN/A struct vnode *filename_vp; 3651830SN/A int namespace; 3661830SN/A const char *attrname; 3671830SN/A{ 3681830SN/A 3691830SN/A return (VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, 3701830SN/A filename_vp, namespace, attrname)); 3711830SN/A} 3721830SN/A 3731830SN/Astatic void 3741830SN/Anullfs_reclaim_lowervp(struct mount *mp, struct vnode *lowervp) 3751830SN/A{ 3761830SN/A struct vnode *vp; 3771830SN/A 3781830SN/A vp = null_hashget(mp, lowervp); 3791830SN/A if (vp == NULL) 3801830SN/A return; 3811830SN/A vgone(vp); 3821830SN/A vn_lock(lowervp, LK_EXCLUSIVE | LK_RETRY); 3831830SN/A} 3841830SN/A 3851830SN/Astatic struct vfsops null_vfsops = { 3861830SN/A .vfs_extattrctl = nullfs_extattrctl, 3871830SN/A .vfs_fhtovp = nullfs_fhtovp, 3881830SN/A .vfs_init = nullfs_init, 3891830SN/A .vfs_mount = nullfs_mount, 3901830SN/A .vfs_quotactl = nullfs_quotactl, 3911830SN/A .vfs_root = nullfs_root, 3921830SN/A .vfs_statfs = nullfs_statfs, 3931830SN/A .vfs_sync = nullfs_sync, 3941830SN/A .vfs_uninit = nullfs_uninit, 3951830SN/A .vfs_unmount = nullfs_unmount, 3961830SN/A .vfs_vget = nullfs_vget, 3971830SN/A .vfs_reclaim_lowervp = nullfs_reclaim_lowervp, 3981830SN/A}; 3991830SN/A 4001830SN/AVFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK | VFCF_JAIL); 4011830SN/A