null_vfsops.c revision 176559
119370Spst/*- 219370Spst * Copyright (c) 1992, 1993, 1995 319370Spst * The Regents of the University of California. All rights reserved. 419370Spst * 519370Spst * This code is derived from software donated to Berkeley by 619370Spst * Jan-Simon Pendry. 719370Spst * 819370Spst * Redistribution and use in source and binary forms, with or without 919370Spst * modification, are permitted provided that the following conditions 1019370Spst * are met: 1119370Spst * 1. Redistributions of source code must retain the above copyright 1219370Spst * notice, this list of conditions and the following disclaimer. 1319370Spst * 2. Redistributions in binary form must reproduce the above copyright 1419370Spst * notice, this list of conditions and the following disclaimer in the 1546283Sdfr * documentation and/or other materials provided with the distribution. 1646283Sdfr * 4. Neither the name of the University nor the names of its contributors 1746283Sdfr * may be used to endorse or promote products derived from this software 1819370Spst * without specific prior written permission. 1946283Sdfr * 2046283Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2146283Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2219370Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2319370Spst * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2419370Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2546283Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2646283Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2746283Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2819370Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2919370Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3019370Spst * SUCH DAMAGE. 3119370Spst * 3219370Spst * @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94 3319370Spst * 3419370Spst * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 3519370Spst * $FreeBSD: head/sys/fs/nullfs/null_vfsops.c 176559 2008-02-25 18:45:57Z attilio $ 3619370Spst */ 3746283Sdfr 3819370Spst/* 3946283Sdfr * Null Layer 4019370Spst * (See null_vnops.c for a description of what this does.) 4119370Spst */ 4246283Sdfr 4346283Sdfr#include <sys/param.h> 4446283Sdfr#include <sys/systm.h> 4546283Sdfr#include <sys/kernel.h> 4619370Spst#include <sys/lock.h> 4719370Spst#include <sys/malloc.h> 4819370Spst#include <sys/mount.h> 4946283Sdfr#include <sys/namei.h> 5019370Spst#include <sys/proc.h> 5146283Sdfr#include <sys/vnode.h> 5219370Spst 5319370Spst#include <fs/nullfs/null.h> 5419370Spst 5519370Spststatic MALLOC_DEFINE(M_NULLFSMNT, "nullfs_mount", "NULLFS mount structure"); 5619370Spst 5719370Spststatic vfs_fhtovp_t nullfs_fhtovp; 5846283Sdfrstatic vfs_mount_t nullfs_mount; 5919370Spststatic vfs_quotactl_t nullfs_quotactl; 6019370Spststatic vfs_root_t nullfs_root; 6119370Spststatic vfs_sync_t nullfs_sync; 6219370Spststatic vfs_statfs_t nullfs_statfs; 6319370Spststatic vfs_unmount_t nullfs_unmount; 6419370Spststatic vfs_vget_t nullfs_vget; 6519370Spststatic vfs_extattrctl_t nullfs_extattrctl; 6619370Spst 6719370Spst/* 6819370Spst * Mount null layer 6919370Spst */ 7019370Spststatic int 7146283Sdfrnullfs_mount(struct mount *mp, struct thread *td) 7246283Sdfr{ 7346283Sdfr int error = 0; 7419370Spst struct vnode *lowerrootvp, *vp; 7519370Spst struct vnode *nullm_rootvp; 7646283Sdfr struct null_mount *xmp; 7746283Sdfr char *target; 7846283Sdfr int isvnunlocked = 0, len; 7946283Sdfr struct nameidata nd, *ndp = &nd; 8046283Sdfr 8146283Sdfr NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp); 8246283Sdfr 8346283Sdfr if (mp->mnt_flag & MNT_ROOTFS) 8446283Sdfr return (EOPNOTSUPP); 8546283Sdfr /* 8646283Sdfr * Update is a no-op 8746283Sdfr */ 8846283Sdfr if (mp->mnt_flag & MNT_UPDATE) { 8946283Sdfr /* 9019370Spst * Only support update mounts for NFS export. 9119370Spst */ 9246283Sdfr if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) 9319370Spst return (0); 9446283Sdfr else 9519370Spst return (EOPNOTSUPP); 9646283Sdfr } 9746283Sdfr 9846283Sdfr /* 9946283Sdfr * Get argument 10019370Spst */ 10146283Sdfr error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len); 10246283Sdfr if (error || target[len - 1] != '\0') 10346283Sdfr return (EINVAL); 10419370Spst 10546283Sdfr /* 10646283Sdfr * Unlock lower node to avoid deadlock. 10719370Spst * (XXX) VOP_ISLOCKED is needed? 10846283Sdfr */ 10946283Sdfr if ((mp->mnt_vnodecovered->v_op == &null_vnodeops) && 11046283Sdfr VOP_ISLOCKED(mp->mnt_vnodecovered)) { 11146283Sdfr VOP_UNLOCK(mp->mnt_vnodecovered, 0); 11219370Spst isvnunlocked = 1; 11346283Sdfr } 11446283Sdfr /* 11546283Sdfr * Find lower node 11646283Sdfr */ 11746283Sdfr NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, 11819370Spst UIO_SYSSPACE, target, td); 11946283Sdfr error = namei(ndp); 12046283Sdfr /* 12146283Sdfr * Re-lock vnode. 12219370Spst */ 12346283Sdfr if (isvnunlocked && !VOP_ISLOCKED(mp->mnt_vnodecovered)) 12446283Sdfr vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY); 12519370Spst 12619370Spst if (error) 12746283Sdfr return (error); 12819370Spst NDFREE(ndp, NDF_ONLY_PNBUF); 12946283Sdfr 13019370Spst /* 13146283Sdfr * Sanity check on lower vnode 13246283Sdfr */ 13319370Spst lowerrootvp = ndp->ni_vp; 13446283Sdfr 13546283Sdfr /* 13619370Spst * Check multi null mount to avoid `lock against myself' panic. 13746283Sdfr */ 13846283Sdfr if (lowerrootvp == VTONULL(mp->mnt_vnodecovered)->null_lowervp) { 13946283Sdfr NULLFSDEBUG("nullfs_mount: multi null mount?\n"); 14019370Spst vput(lowerrootvp); 14146283Sdfr return (EDEADLK); 14246283Sdfr } 14319370Spst 14446283Sdfr xmp = (struct null_mount *) malloc(sizeof(struct null_mount), 14546283Sdfr M_NULLFSMNT, M_WAITOK); /* XXX */ 14646283Sdfr 14746283Sdfr /* 14846283Sdfr * Save reference to underlying FS 14946283Sdfr */ 15019370Spst xmp->nullm_vfs = lowerrootvp->v_mount; 15146283Sdfr 15219370Spst /* 15346283Sdfr * Save reference. Each mount also holds 15446283Sdfr * a reference on the root vnode. 15546283Sdfr */ 15619370Spst error = null_nodeget(mp, lowerrootvp, &vp); 15746283Sdfr /* 15819370Spst * Make sure the node alias worked 15946283Sdfr */ 16046283Sdfr if (error) { 16146283Sdfr VOP_UNLOCK(vp, 0); 16246283Sdfr vrele(lowerrootvp); 16319370Spst free(xmp, M_NULLFSMNT); /* XXX */ 16446283Sdfr return (error); 16546283Sdfr } 16646283Sdfr 16746283Sdfr /* 16846283Sdfr * Keep a held reference to the root vnode. 16946283Sdfr * It is vrele'd in nullfs_unmount. 17046283Sdfr */ 17146283Sdfr nullm_rootvp = vp; 17219370Spst nullm_rootvp->v_vflag |= VV_ROOT; 17319370Spst xmp->nullm_rootvp = nullm_rootvp; 17446283Sdfr 17546283Sdfr /* 17619370Spst * Unlock the node (either the lower or the alias) 17719370Spst */ 17819370Spst VOP_UNLOCK(vp, 0); 17919370Spst 18019370Spst if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) { 18119370Spst MNT_ILOCK(mp); 18219370Spst mp->mnt_flag |= MNT_LOCAL; 18319370Spst MNT_IUNLOCK(mp); 18419370Spst } 18519370Spst MNT_ILOCK(mp); 18619370Spst mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & MNTK_MPSAFE; 18719370Spst MNT_IUNLOCK(mp); 18819370Spst mp->mnt_data = xmp; 18919370Spst vfs_getnewfsid(mp); 19046283Sdfr 19146283Sdfr vfs_mountedfrom(mp, target); 19219370Spst 19346283Sdfr NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n", 19446283Sdfr mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 19546283Sdfr return (0); 19646283Sdfr} 19719370Spst 19846283Sdfr/* 19946283Sdfr * Free reference to null layer 20019370Spst */ 20119370Spststatic int 20246283Sdfrnullfs_unmount(mp, mntflags, td) 20319370Spst struct mount *mp; 20446283Sdfr int mntflags; 20519370Spst struct thread *td; 20646283Sdfr{ 20746283Sdfr void *mntdata; 20846283Sdfr int error; 20946283Sdfr int flags = 0; 21019370Spst 21146283Sdfr NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp); 21219370Spst 21346283Sdfr if (mntflags & MNT_FORCE) 21446283Sdfr flags |= FORCECLOSE; 21519370Spst 21646283Sdfr /* There is 1 extra root vnode reference (nullm_rootvp). */ 21746283Sdfr error = vflush(mp, 1, flags, td); 21846283Sdfr if (error) 21919370Spst return (error); 22019370Spst 22146283Sdfr /* 22219370Spst * Finally, throw away the null_mount structure 22319370Spst */ 22446283Sdfr mntdata = mp->mnt_data; 22546283Sdfr mp->mnt_data = 0; 22646283Sdfr free(mntdata, M_NULLFSMNT); 22746283Sdfr return 0; 22846283Sdfr} 22946283Sdfr 23019370Spststatic int 23146283Sdfrnullfs_root(mp, flags, vpp, td) 23246283Sdfr struct mount *mp; 23346283Sdfr int flags; 23446283Sdfr struct vnode **vpp; 23519370Spst struct thread *td; 23646283Sdfr{ 23719370Spst struct vnode *vp; 23846283Sdfr 23946283Sdfr NULLFSDEBUG("nullfs_root(mp = %p, vp = %p->%p)\n", (void *)mp, 24046283Sdfr (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 24119370Spst (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 24246283Sdfr 24346283Sdfr /* 24419370Spst * Return locked reference to root. 24546283Sdfr */ 24646283Sdfr vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 24746283Sdfr VREF(vp); 24846283Sdfr 24946283Sdfr#ifdef NULLFS_DEBUG 25046283Sdfr if (VOP_ISLOCKED(vp)) 25146283Sdfr panic("root vnode is locked.\n"); 25246283Sdfr#endif 25346283Sdfr vn_lock(vp, flags | LK_RETRY); 25446283Sdfr *vpp = vp; 25546283Sdfr return 0; 25646283Sdfr} 25746283Sdfr 25819370Spststatic int 25946283Sdfrnullfs_quotactl(mp, cmd, uid, arg, td) 26046283Sdfr struct mount *mp; 26146283Sdfr int cmd; 26219370Spst uid_t uid; 26346283Sdfr void *arg; 26446283Sdfr struct thread *td; 26546283Sdfr{ 26646283Sdfr return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, td); 26746283Sdfr} 26846283Sdfr 26919370Spststatic int 27046283Sdfrnullfs_statfs(mp, sbp, td) 27146283Sdfr struct mount *mp; 27246283Sdfr struct statfs *sbp; 27346283Sdfr struct thread *td; 27419370Spst{ 27546283Sdfr int error; 27646283Sdfr struct statfs mstat; 27746283Sdfr 27846283Sdfr NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp, 27946283Sdfr (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 28046283Sdfr (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 28146283Sdfr 28246283Sdfr bzero(&mstat, sizeof(mstat)); 28346283Sdfr 28446283Sdfr error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, td); 28519370Spst if (error) 28646283Sdfr return (error); 28746283Sdfr 28819370Spst /* now copy across the "interesting" information and fake the rest */ 28946283Sdfr sbp->f_type = mstat.f_type; 29046283Sdfr sbp->f_flags = mstat.f_flags; 29119370Spst sbp->f_bsize = mstat.f_bsize; 29246283Sdfr sbp->f_iosize = mstat.f_iosize; 29319370Spst sbp->f_blocks = mstat.f_blocks; 29446283Sdfr sbp->f_bfree = mstat.f_bfree; 29519370Spst sbp->f_bavail = mstat.f_bavail; 29646283Sdfr sbp->f_files = mstat.f_files; 29719370Spst sbp->f_ffree = mstat.f_ffree; 29846283Sdfr return (0); 29919370Spst} 30046283Sdfr 30119370Spststatic int 30246283Sdfrnullfs_sync(mp, waitfor, td) 30346283Sdfr struct mount *mp; 30446283Sdfr int waitfor; 30546283Sdfr struct thread *td; 30619370Spst{ 30746283Sdfr /* 30846283Sdfr * XXX - Assumes no data cached at null layer. 30946283Sdfr */ 31046283Sdfr return (0); 31146283Sdfr} 31246283Sdfr 31319370Spststatic int 31446283Sdfrnullfs_vget(mp, ino, flags, vpp) 31519370Spst struct mount *mp; 31646283Sdfr ino_t ino; 31719370Spst int flags; 31846283Sdfr struct vnode **vpp; 31946283Sdfr{ 32019370Spst int error; 32146283Sdfr error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, flags, vpp); 32219370Spst if (error) 32346283Sdfr return (error); 32446283Sdfr 32546283Sdfr return (null_nodeget(mp, *vpp, vpp)); 32646283Sdfr} 32719370Spst 32846283Sdfrstatic int 32946283Sdfrnullfs_fhtovp(mp, fidp, vpp) 33046283Sdfr struct mount *mp; 33119370Spst struct fid *fidp; 33246283Sdfr struct vnode **vpp; 33346283Sdfr{ 33446283Sdfr int error; 33546283Sdfr error = VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, vpp); 33619370Spst if (error) 33746283Sdfr return (error); 33819370Spst 33946283Sdfr return (null_nodeget(mp, *vpp, vpp)); 34019370Spst} 34146283Sdfr 34219370Spststatic int 34346283Sdfrnullfs_extattrctl(mp, cmd, filename_vp, namespace, attrname, td) 34446283Sdfr struct mount *mp; 34519370Spst int cmd; 34646283Sdfr struct vnode *filename_vp; 34719370Spst int namespace; 34846283Sdfr const char *attrname; 34919370Spst struct thread *td; 35046283Sdfr{ 35146283Sdfr return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, filename_vp, 35219370Spst namespace, attrname, td); 35346283Sdfr} 35419370Spst 35546283Sdfr 35646283Sdfrstatic struct vfsops null_vfsops = { 35746283Sdfr .vfs_extattrctl = nullfs_extattrctl, 35846283Sdfr .vfs_fhtovp = nullfs_fhtovp, 35946283Sdfr .vfs_init = nullfs_init, 36019370Spst .vfs_mount = nullfs_mount, 36146283Sdfr .vfs_quotactl = nullfs_quotactl, 36246283Sdfr .vfs_root = nullfs_root, 36346283Sdfr .vfs_statfs = nullfs_statfs, 36446283Sdfr .vfs_sync = nullfs_sync, 36519370Spst .vfs_uninit = nullfs_uninit, 36646283Sdfr .vfs_unmount = nullfs_unmount, 36746283Sdfr .vfs_vget = nullfs_vget, 36846283Sdfr}; 36946283Sdfr 37046283SdfrVFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK); 37146283Sdfr