null_vfsops.c revision 222167
1186681Sed/*- 2186681Sed * Copyright (c) 1992, 1993, 1995 3186681Sed * The Regents of the University of California. All rights reserved. 4186681Sed * 5186681Sed * This code is derived from software donated to Berkeley by 6186681Sed * Jan-Simon Pendry. 7186681Sed * 8186681Sed * Redistribution and use in source and binary forms, with or without 9186681Sed * modification, are permitted provided that the following conditions 10186681Sed * are met: 11186681Sed * 1. Redistributions of source code must retain the above copyright 12186681Sed * notice, this list of conditions and the following disclaimer. 13186681Sed * 2. Redistributions in binary form must reproduce the above copyright 14186681Sed * notice, this list of conditions and the following disclaimer in the 15186681Sed * documentation and/or other materials provided with the distribution. 16186681Sed * 4. Neither the name of the University nor the names of its contributors 17186681Sed * may be used to endorse or promote products derived from this software 18186681Sed * without specific prior written permission. 19186681Sed * 20186681Sed * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21186681Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22186681Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23186681Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24186681Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25186681Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26186681Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27186681Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28186681Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29186681Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30186681Sed * SUCH DAMAGE. 31186681Sed * 32186681Sed * @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94 33186681Sed * 34186681Sed * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 35186681Sed * $FreeBSD: head/sys/fs/nullfs/null_vfsops.c 222167 2011-05-22 01:07:54Z rmacklem $ 36186681Sed */ 37186681Sed 38206141Sed/* 39186681Sed * Null Layer 40186681Sed * (See null_vnops.c for a description of what this does.) 41186681Sed */ 42186681Sed 43186681Sed#include <sys/param.h> 44221698Sed#include <sys/systm.h> 45221698Sed#include <sys/fcntl.h> 46221698Sed#include <sys/kernel.h> 47186681Sed#include <sys/lock.h> 48199171Sed#include <sys/malloc.h> 49199171Sed#include <sys/mount.h> 50199171Sed#include <sys/namei.h> 51199171Sed#include <sys/proc.h> 52199171Sed#include <sys/vnode.h> 53199171Sed 54199171Sed#include <fs/nullfs/null.h> 55199171Sed 56199171Sedstatic MALLOC_DEFINE(M_NULLFSMNT, "nullfs_mount", "NULLFS mount structure"); 57186681Sed 58186681Sedstatic vfs_fhtovp_t nullfs_fhtovp; 59186681Sedstatic vfs_mount_t nullfs_mount; 60186681Sedstatic vfs_quotactl_t nullfs_quotactl; 61197470Sedstatic vfs_root_t nullfs_root; 62197470Sedstatic vfs_sync_t nullfs_sync; 63197470Sedstatic vfs_statfs_t nullfs_statfs; 64197470Sedstatic vfs_unmount_t nullfs_unmount; 65186681Sedstatic vfs_vget_t nullfs_vget; 66186681Sedstatic vfs_extattrctl_t nullfs_extattrctl; 67186681Sed 68186681Sed/* 69186681Sed * Mount null layer 70186681Sed */ 71186681Sedstatic int 72186681Sednullfs_mount(struct mount *mp) 73186681Sed{ 74186681Sed int error = 0; 75186681Sed struct vnode *lowerrootvp, *vp; 76186681Sed struct vnode *nullm_rootvp; 77186681Sed struct null_mount *xmp; 78186681Sed char *target; 79186681Sed int isvnunlocked = 0, len; 80186681Sed struct nameidata nd, *ndp = &nd; 81186681Sed 82186681Sed NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp); 83186681Sed 84186681Sed if (mp->mnt_flag & MNT_ROOTFS) 85186681Sed return (EOPNOTSUPP); 86186681Sed /* 87186681Sed * Update is a no-op 88186681Sed */ 89186681Sed if (mp->mnt_flag & MNT_UPDATE) { 90186681Sed /* 91186681Sed * Only support update mounts for NFS export. 92186681Sed */ 93186681Sed if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) 94186681Sed return (0); 95186681Sed else 96186681Sed return (EOPNOTSUPP); 97186681Sed } 98186681Sed 99186681Sed /* 100186681Sed * Get argument 101186681Sed */ 102186681Sed error = vfs_getopt(mp->mnt_optnew, "target", (void **)&target, &len); 103186681Sed if (error || target[len - 1] != '\0') 104186681Sed return (EINVAL); 105186681Sed 106186681Sed /* 107186681Sed * Unlock lower node to avoid deadlock. 108186681Sed * (XXX) VOP_ISLOCKED is needed? 109186681Sed */ 110186681Sed if ((mp->mnt_vnodecovered->v_op == &null_vnodeops) && 111186681Sed VOP_ISLOCKED(mp->mnt_vnodecovered)) { 112186681Sed VOP_UNLOCK(mp->mnt_vnodecovered, 0); 113186681Sed isvnunlocked = 1; 114186681Sed } 115186681Sed /* 116186681Sed * Find lower node 117186681Sed */ 118186681Sed NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target, curthread); 119186681Sed error = namei(ndp); 120186681Sed /* 121186681Sed * Re-lock vnode. 122186681Sed */ 123186681Sed if (isvnunlocked && !VOP_ISLOCKED(mp->mnt_vnodecovered)) 124186681Sed vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY); 125186681Sed 126186681Sed if (error) 127193184Sed return (error); 128186681Sed NDFREE(ndp, NDF_ONLY_PNBUF); 129186681Sed 130186681Sed /* 131186681Sed * Sanity check on lower vnode 132186681Sed */ 133186681Sed lowerrootvp = ndp->ni_vp; 134186681Sed 135186681Sed /* 136186681Sed * Check multi null mount to avoid `lock against myself' panic. 137186681Sed */ 138186681Sed if (lowerrootvp == VTONULL(mp->mnt_vnodecovered)->null_lowervp) { 139186681Sed NULLFSDEBUG("nullfs_mount: multi null mount?\n"); 140186681Sed vput(lowerrootvp); 141186681Sed return (EDEADLK); 142186681Sed } 143186681Sed 144186681Sed xmp = (struct null_mount *) malloc(sizeof(struct null_mount), 145186681Sed M_NULLFSMNT, M_WAITOK); /* XXX */ 146186681Sed 147186681Sed /* 148186681Sed * Save reference to underlying FS 149186681Sed */ 150186681Sed xmp->nullm_vfs = lowerrootvp->v_mount; 151186681Sed 152186681Sed /* 153186681Sed * Save reference. Each mount also holds 154186681Sed * a reference on the root vnode. 155186681Sed */ 156197117Sed error = null_nodeget(mp, lowerrootvp, &vp); 157197117Sed /* 158186681Sed * Make sure the node alias worked 159186681Sed */ 160186681Sed if (error) { 161186681Sed VOP_UNLOCK(vp, 0); 162186681Sed vrele(lowerrootvp); 163186681Sed free(xmp, M_NULLFSMNT); /* XXX */ 164186681Sed return (error); 165186681Sed } 166186681Sed 167186681Sed /* 168186681Sed * Keep a held reference to the root vnode. 169186681Sed * It is vrele'd in nullfs_unmount. 170186681Sed */ 171197853Sed nullm_rootvp = vp; 172197853Sed nullm_rootvp->v_vflag |= VV_ROOT; 173197853Sed xmp->nullm_rootvp = nullm_rootvp; 174197853Sed 175197853Sed /* 176197853Sed * Unlock the node (either the lower or the alias) 177197853Sed */ 178197853Sed VOP_UNLOCK(vp, 0); 179197853Sed 180197853Sed if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) { 181197853Sed MNT_ILOCK(mp); 182197853Sed mp->mnt_flag |= MNT_LOCAL; 183197853Sed MNT_IUNLOCK(mp); 184197853Sed } 185197853Sed MNT_ILOCK(mp); 186197853Sed mp->mnt_kern_flag |= lowerrootvp->v_mount->mnt_kern_flag & MNTK_MPSAFE; 187197853Sed MNT_IUNLOCK(mp); 188197853Sed mp->mnt_data = xmp; 189186681Sed vfs_getnewfsid(mp); 190186681Sed 191186681Sed vfs_mountedfrom(mp, target); 192186681Sed 193186681Sed NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n", 194186681Sed mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 195186681Sed return (0); 196186681Sed} 197186681Sed 198186681Sed/* 199186681Sed * Free reference to null layer 200186681Sed */ 201186681Sedstatic int 202186798Sednullfs_unmount(mp, mntflags) 203186798Sed struct mount *mp; 204186798Sed int mntflags; 205187469Sed{ 206197117Sed void *mntdata; 207197117Sed int error; 208197117Sed int flags = 0; 209197520Sed 210187469Sed NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp); 211187469Sed 212197117Sed if (mntflags & MNT_FORCE) 213197117Sed flags |= FORCECLOSE; 214197117Sed 215197520Sed /* There is 1 extra root vnode reference (nullm_rootvp). */ 216187469Sed error = vflush(mp, 1, flags, curthread); 217186681Sed if (error) 218186681Sed return (error); 219186681Sed 220186681Sed /* 221186681Sed * Finally, throw away the null_mount structure 222186681Sed */ 223186681Sed mntdata = mp->mnt_data; 224186681Sed mp->mnt_data = 0; 225186681Sed free(mntdata, M_NULLFSMNT); 226186681Sed return 0; 227186681Sed} 228186681Sed 229186681Sedstatic int 230186681Sednullfs_root(mp, flags, vpp) 231186681Sed struct mount *mp; 232186681Sed int flags; 233186681Sed struct vnode **vpp; 234186681Sed{ 235186681Sed struct vnode *vp; 236186681Sed 237186681Sed NULLFSDEBUG("nullfs_root(mp = %p, vp = %p->%p)\n", (void *)mp, 238186681Sed (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 239186681Sed (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 240186681Sed 241186681Sed /* 242186681Sed * Return locked reference to root. 243186681Sed */ 244186681Sed vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 245186681Sed VREF(vp); 246186681Sed 247186681Sed#ifdef NULLFS_DEBUG 248186681Sed if (VOP_ISLOCKED(vp)) 249186681Sed panic("root vnode is locked.\n"); 250186681Sed#endif 251197117Sed vn_lock(vp, flags | LK_RETRY); 252186681Sed *vpp = vp; 253186681Sed return 0; 254186681Sed} 255186681Sed 256186681Sedstatic int 257186681Sednullfs_quotactl(mp, cmd, uid, arg) 258186681Sed struct mount *mp; 259186681Sed int cmd; 260186681Sed uid_t uid; 261186681Sed void *arg; 262186681Sed{ 263186681Sed return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg); 264186681Sed} 265186681Sed 266186681Sedstatic int 267186681Sednullfs_statfs(mp, sbp) 268186681Sed struct mount *mp; 269186681Sed struct statfs *sbp; 270186681Sed{ 271186681Sed int error; 272186681Sed struct statfs mstat; 273194293Sed 274186681Sed NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp, 275186681Sed (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 276186681Sed (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 277186681Sed 278186681Sed bzero(&mstat, sizeof(mstat)); 279186681Sed 280186681Sed error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat); 281186681Sed if (error) 282186681Sed return (error); 283186681Sed 284186681Sed /* now copy across the "interesting" information and fake the rest */ 285186681Sed sbp->f_type = mstat.f_type; 286186681Sed sbp->f_flags = mstat.f_flags; 287186681Sed sbp->f_bsize = mstat.f_bsize; 288197117Sed sbp->f_iosize = mstat.f_iosize; 289197117Sed sbp->f_blocks = mstat.f_blocks; 290197117Sed sbp->f_bfree = mstat.f_bfree; 291197117Sed sbp->f_bavail = mstat.f_bavail; 292197117Sed sbp->f_files = mstat.f_files; 293197117Sed sbp->f_ffree = mstat.f_ffree; 294197117Sed return (0); 295186681Sed} 296186681Sed 297186681Sedstatic int 298186681Sednullfs_sync(mp, waitfor) 299186681Sed struct mount *mp; 300186681Sed int waitfor; 301186681Sed{ 302186681Sed /* 303186681Sed * XXX - Assumes no data cached at null layer. 304186681Sed */ 305186681Sed return (0); 306188391Sed} 307188391Sed 308188391Sedstatic int 309188391Sednullfs_vget(mp, ino, flags, vpp) 310188391Sed struct mount *mp; 311188391Sed ino_t ino; 312188391Sed int flags; 313189617Sed struct vnode **vpp; 314189617Sed{ 315189617Sed int error; 316189617Sed error = VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, flags, vpp); 317189617Sed if (error) 318189617Sed return (error); 319189617Sed 320188391Sed return (null_nodeget(mp, *vpp, vpp)); 321188391Sed} 322188391Sed 323188391Sedstatic int 324188391Sednullfs_fhtovp(mp, fidp, flags, vpp) 325188391Sed struct mount *mp; 326188391Sed struct fid *fidp; 327186681Sed int flags; 328186681Sed struct vnode **vpp; 329186681Sed{ 330186681Sed int error; 331186681Sed error = VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, LK_EXCLUSIVE, 332186681Sed vpp); 333186681Sed if (error) 334197117Sed return (error); 335197117Sed 336197117Sed return (null_nodeget(mp, *vpp, vpp)); 337197117Sed} 338197117Sed 339197117Sedstatic int 340197117Sednullfs_extattrctl(mp, cmd, filename_vp, namespace, attrname) 341186681Sed struct mount *mp; 342186681Sed int cmd; 343186681Sed struct vnode *filename_vp; 344186681Sed int namespace; 345186681Sed const char *attrname; 346197114Sed{ 347186681Sed return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, filename_vp, 348186681Sed namespace, attrname); 349197115Sed} 350259016Sray 351259016Sray 352259016Sraystatic struct vfsops null_vfsops = { 353259016Sray .vfs_extattrctl = nullfs_extattrctl, 354259016Sray .vfs_fhtovp = nullfs_fhtovp, 355259016Sray .vfs_init = nullfs_init, 356259016Sray .vfs_mount = nullfs_mount, 357259016Sray .vfs_quotactl = nullfs_quotactl, 358197115Sed .vfs_root = nullfs_root, 359197115Sed .vfs_statfs = nullfs_statfs, 360197115Sed .vfs_sync = nullfs_sync, 361197117Sed .vfs_uninit = nullfs_uninit, 362197115Sed .vfs_unmount = nullfs_unmount, 363197115Sed .vfs_vget = nullfs_vget, 364197117Sed}; 365197117Sed 366197117SedVFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK); 367197117Sed