null_vfsops.c revision 56272
1214571Sdim/* 2214571Sdim * Copyright (c) 1992, 1993, 1995 3214571Sdim * The Regents of the University of California. All rights reserved. 4214571Sdim * 5214571Sdim * This code is derived from software donated to Berkeley by 6214571Sdim * Jan-Simon Pendry. 7214571Sdim * 8214571Sdim * Redistribution and use in source and binary forms, with or without 9214571Sdim * modification, are permitted provided that the following conditions 10214571Sdim * are met: 11214571Sdim * 1. Redistributions of source code must retain the above copyright 12214571Sdim * notice, this list of conditions and the following disclaimer. 13214571Sdim * 2. Redistributions in binary form must reproduce the above copyright 14214571Sdim * notice, this list of conditions and the following disclaimer in the 15214571Sdim * documentation and/or other materials provided with the distribution. 16214571Sdim * 3. All advertising materials mentioning features or use of this software 17214571Sdim * must display the following acknowledgement: 18214571Sdim * This product includes software developed by the University of 19214571Sdim * California, Berkeley and its contributors. 20214571Sdim * 4. Neither the name of the University nor the names of its contributors 21214571Sdim * may be used to endorse or promote products derived from this software 22214571Sdim * without specific prior written permission. 23214571Sdim * 24214571Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25214571Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26214571Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27214571Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28214571Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29214571Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30214571Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31214571Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32214571Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33214571Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34214571Sdim * SUCH DAMAGE. 35214571Sdim * 36214571Sdim * @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94 37214571Sdim * 38214571Sdim * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 39214571Sdim * $FreeBSD: head/sys/fs/nullfs/null_vfsops.c 56272 2000-01-19 06:07:34Z rwatson $ 40214571Sdim */ 41214571Sdim 42214571Sdim/* 43214571Sdim * Null Layer 44214571Sdim * (See null_vnops.c for a description of what this does.) 45214571Sdim */ 46214571Sdim 47214571Sdim#include <sys/param.h> 48214571Sdim#include <sys/systm.h> 49214571Sdim#include <sys/kernel.h> 50214571Sdim#include <sys/proc.h> 51214571Sdim#include <sys/malloc.h> 52214571Sdim#include <sys/vnode.h> 53214571Sdim#include <sys/mount.h> 54214571Sdim#include <sys/namei.h> 55214571Sdim#include <miscfs/nullfs/null.h> 56214571Sdim#include <vm/vm_zone.h> 57214571Sdim 58214571Sdimstatic MALLOC_DEFINE(M_NULLFSMNT, "NULLFS mount", "NULLFS mount structure"); 59214571Sdim 60214571Sdimstatic int nullfs_fhtovp __P((struct mount *mp, struct fid *fidp, 61214571Sdim struct vnode **vpp)); 62214571Sdimstatic int nullfs_checkexp __P((struct mount *mp, struct sockaddr *nam, 63214571Sdim int *extflagsp, struct ucred **credanonp)); 64214571Sdimstatic int nullfs_mount __P((struct mount *mp, char *path, caddr_t data, 65214571Sdim struct nameidata *ndp, struct proc *p)); 66214571Sdimstatic int nullfs_quotactl __P((struct mount *mp, int cmd, uid_t uid, 67214571Sdim caddr_t arg, struct proc *p)); 68214571Sdimstatic int nullfs_root __P((struct mount *mp, struct vnode **vpp)); 69214571Sdimstatic int nullfs_start __P((struct mount *mp, int flags, struct proc *p)); 70214571Sdimstatic int nullfs_statfs __P((struct mount *mp, struct statfs *sbp, 71214571Sdim struct proc *p)); 72214571Sdimstatic int nullfs_sync __P((struct mount *mp, int waitfor, 73214571Sdim struct ucred *cred, struct proc *p)); 74214571Sdimstatic int nullfs_unmount __P((struct mount *mp, int mntflags, 75214571Sdim struct proc *p)); 76214571Sdimstatic int nullfs_vget __P((struct mount *mp, ino_t ino, 77214571Sdim struct vnode **vpp)); 78214571Sdimstatic int nullfs_vptofh __P((struct vnode *vp, struct fid *fhp)); 79214571Sdim 80214571Sdim/* 81214571Sdim * Mount null layer 82214571Sdim */ 83214571Sdimstatic int 84214571Sdimnullfs_mount(mp, path, data, ndp, p) 85214571Sdim struct mount *mp; 86214571Sdim char *path; 87214571Sdim caddr_t data; 88214571Sdim struct nameidata *ndp; 89214571Sdim struct proc *p; 90214571Sdim{ 91214571Sdim int error = 0; 92214571Sdim struct null_args args; 93214571Sdim struct vnode *lowerrootvp, *vp; 94214571Sdim struct vnode *nullm_rootvp; 95214571Sdim struct null_mount *xmp; 96214571Sdim u_int size; 97214571Sdim int isvnunlocked = 0; 98214571Sdim 99214571Sdim#ifdef DEBUG 100214571Sdim printf("nullfs_mount(mp = %p)\n", (void *)mp); 101214571Sdim#endif 102214571Sdim 103214571Sdim /* 104214571Sdim * Update is a no-op 105214571Sdim */ 106214571Sdim if (mp->mnt_flag & MNT_UPDATE) { 107214571Sdim return (EOPNOTSUPP); 108214571Sdim /* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/ 109214571Sdim } 110214571Sdim 111214571Sdim /* 112214571Sdim * Get argument 113214571Sdim */ 114214571Sdim error = copyin(data, (caddr_t)&args, sizeof(struct null_args)); 115214571Sdim if (error) 116214571Sdim return (error); 117214571Sdim 118214571Sdim /* 119214571Sdim * Unlock lower node to avoid deadlock. 120214571Sdim * (XXX) VOP_ISLOCKED is needed? 121214571Sdim */ 122214571Sdim if ((mp->mnt_vnodecovered->v_op == null_vnodeop_p) && 123214571Sdim VOP_ISLOCKED(mp->mnt_vnodecovered, NULL)) { 124214571Sdim VOP_UNLOCK(mp->mnt_vnodecovered, 0, p); 125214571Sdim isvnunlocked = 1; 126214571Sdim } 127214571Sdim /* 128214571Sdim * Find lower node 129214571Sdim */ 130214571Sdim NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF, 131214571Sdim UIO_USERSPACE, args.target, p); 132214571Sdim error = namei(ndp); 133214571Sdim /* 134214571Sdim * Re-lock vnode. 135214571Sdim */ 136214571Sdim if (isvnunlocked && !VOP_ISLOCKED(mp->mnt_vnodecovered, NULL)) 137214571Sdim vn_lock(mp->mnt_vnodecovered, LK_EXCLUSIVE | LK_RETRY, p); 138214571Sdim 139214571Sdim if (error) 140214571Sdim return (error); 141214571Sdim NDFREE(ndp, NDF_ONLY_PNBUF); 142214571Sdim 143214571Sdim /* 144214571Sdim * Sanity check on lower vnode 145214571Sdim */ 146214571Sdim lowerrootvp = ndp->ni_vp; 147214571Sdim 148214571Sdim vrele(ndp->ni_dvp); 149214571Sdim ndp->ni_dvp = NULLVP; 150214571Sdim 151214571Sdim /* 152214571Sdim * Check multi null mount to avoid `lock against myself' panic. 153214571Sdim */ 154214571Sdim if (lowerrootvp == VTONULL(mp->mnt_vnodecovered)->null_lowervp) { 155214571Sdim#ifdef DEBUG 156214571Sdim printf("nullfs_mount: multi null mount?\n"); 157214571Sdim#endif 158214571Sdim return (EDEADLK); 159214571Sdim } 160214571Sdim 161214571Sdim xmp = (struct null_mount *) malloc(sizeof(struct null_mount), 162214571Sdim M_NULLFSMNT, M_WAITOK); /* XXX */ 163214571Sdim 164214571Sdim /* 165214571Sdim * Save reference to underlying FS 166214571Sdim */ 167214571Sdim xmp->nullm_vfs = lowerrootvp->v_mount; 168214571Sdim 169214571Sdim /* 170214571Sdim * Save reference. Each mount also holds 171214571Sdim * a reference on the root vnode. 172214571Sdim */ 173214571Sdim error = null_node_create(mp, lowerrootvp, &vp); 174214571Sdim /* 175214571Sdim * Unlock the node (either the lower or the alias) 176214571Sdim */ 177214571Sdim VOP_UNLOCK(vp, 0, p); 178214571Sdim /* 179214571Sdim * Make sure the node alias worked 180214571Sdim */ 181214571Sdim if (error) { 182214571Sdim vrele(lowerrootvp); 183214571Sdim free(xmp, M_NULLFSMNT); /* XXX */ 184214571Sdim return (error); 185214571Sdim } 186214571Sdim 187214571Sdim /* 188214571Sdim * Keep a held reference to the root vnode. 189214571Sdim * It is vrele'd in nullfs_unmount. 190214571Sdim */ 191214571Sdim nullm_rootvp = vp; 192214571Sdim nullm_rootvp->v_flag |= VROOT; 193214571Sdim xmp->nullm_rootvp = nullm_rootvp; 194214571Sdim if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) 195214571Sdim mp->mnt_flag |= MNT_LOCAL; 196214571Sdim mp->mnt_data = (qaddr_t) xmp; 197214571Sdim vfs_getnewfsid(mp); 198214571Sdim 199214571Sdim (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 200214571Sdim bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 201214571Sdim (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 202214571Sdim &size); 203214571Sdim bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 204214571Sdim (void)nullfs_statfs(mp, &mp->mnt_stat, p); 205214571Sdim#ifdef DEBUG 206214571Sdim printf("nullfs_mount: lower %s, alias at %s\n", 207214571Sdim mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 208214571Sdim#endif 209214571Sdim return (0); 210214571Sdim} 211214571Sdim 212214571Sdim/* 213214571Sdim * VFS start. Nothing needed here - the start routine 214214571Sdim * on the underlying filesystem will have been called 215214571Sdim * when that filesystem was mounted. 216214571Sdim */ 217214571Sdimstatic int 218214571Sdimnullfs_start(mp, flags, p) 219214571Sdim struct mount *mp; 220214571Sdim int flags; 221214571Sdim struct proc *p; 222214571Sdim{ 223214571Sdim return (0); 224214571Sdim /* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */ 225214571Sdim} 226214571Sdim 227214571Sdim/* 228214571Sdim * Free reference to null layer 229214571Sdim */ 230214571Sdimstatic int 231214571Sdimnullfs_unmount(mp, mntflags, p) 232214571Sdim struct mount *mp; 233214571Sdim int mntflags; 234214571Sdim struct proc *p; 235214571Sdim{ 236214571Sdim struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 237214571Sdim int error; 238214571Sdim int flags = 0; 239214571Sdim 240214571Sdim#ifdef DEBUG 241214571Sdim printf("nullfs_unmount(mp = %p)\n", (void *)mp); 242214571Sdim#endif 243214571Sdim 244214571Sdim if (mntflags & MNT_FORCE) 245214571Sdim flags |= FORCECLOSE; 246214571Sdim 247214571Sdim /* 248214571Sdim * Clear out buffer cache. I don't think we 249214571Sdim * ever get anything cached at this level at the 250214571Sdim * moment, but who knows... 251214571Sdim */ 252214571Sdim#if 0 253214571Sdim mntflushbuf(mp, 0); 254214571Sdim if (mntinvalbuf(mp, 1)) 255214571Sdim return (EBUSY); 256214571Sdim#endif 257214571Sdim if (nullm_rootvp->v_usecount > 1) 258214571Sdim return (EBUSY); 259214571Sdim error = vflush(mp, nullm_rootvp, flags); 260214571Sdim if (error) 261214571Sdim return (error); 262214571Sdim 263214571Sdim#ifdef DEBUG 264214571Sdim vprint("alias root of lower", nullm_rootvp); 265214571Sdim#endif 266214571Sdim /* 267214571Sdim * Release reference on underlying root vnode 268214571Sdim */ 269214571Sdim vrele(nullm_rootvp); 270214571Sdim /* 271214571Sdim * And blow it away for future re-use 272214571Sdim */ 273214571Sdim vgone(nullm_rootvp); 274214571Sdim /* 275214571Sdim * Finally, throw away the null_mount structure 276214571Sdim */ 277214571Sdim free(mp->mnt_data, M_NULLFSMNT); /* XXX */ 278214571Sdim mp->mnt_data = 0; 279214571Sdim return 0; 280214571Sdim} 281214571Sdim 282214571Sdimstatic int 283214571Sdimnullfs_root(mp, vpp) 284214571Sdim struct mount *mp; 285214571Sdim struct vnode **vpp; 286214571Sdim{ 287214571Sdim struct proc *p = curproc; /* XXX */ 288214571Sdim struct vnode *vp; 289214571Sdim 290214571Sdim#ifdef DEBUG 291214571Sdim printf("nullfs_root(mp = %p, vp = %p->%p)\n", (void *)mp, 292214571Sdim (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 293214571Sdim (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 294214571Sdim#endif 295214571Sdim 296214571Sdim /* 297214571Sdim * Return locked reference to root. 298214571Sdim */ 299214571Sdim vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 300214571Sdim VREF(vp); 301214571Sdim if (VOP_ISLOCKED(vp, NULL)) { 302214571Sdim /* 303214571Sdim * XXX 304214571Sdim * Should we check type of node? 305214571Sdim */ 306214571Sdim#ifdef DEBUG 307214571Sdim printf("nullfs_root: multi null mount?\n"); 308214571Sdim#endif 309214571Sdim vrele(vp); 310214571Sdim return (EDEADLK); 311214571Sdim } else 312214571Sdim vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); 313214571Sdim *vpp = vp; 314214571Sdim return 0; 315214571Sdim} 316214571Sdim 317214571Sdimstatic int 318214571Sdimnullfs_quotactl(mp, cmd, uid, arg, p) 319214571Sdim struct mount *mp; 320214571Sdim int cmd; 321214571Sdim uid_t uid; 322214571Sdim caddr_t arg; 323214571Sdim struct proc *p; 324214571Sdim{ 325214571Sdim return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p); 326214571Sdim} 327214571Sdim 328214571Sdimstatic int 329214571Sdimnullfs_statfs(mp, sbp, p) 330214571Sdim struct mount *mp; 331214571Sdim struct statfs *sbp; 332214571Sdim struct proc *p; 333214571Sdim{ 334214571Sdim int error; 335214571Sdim struct statfs mstat; 336214571Sdim 337214571Sdim#ifdef DEBUG 338214571Sdim printf("nullfs_statfs(mp = %p, vp = %p->%p)\n", (void *)mp, 339214571Sdim (void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp, 340214571Sdim (void *)NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)); 341214571Sdim#endif 342214571Sdim 343214571Sdim bzero(&mstat, sizeof(mstat)); 344214571Sdim 345214571Sdim error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p); 346214571Sdim if (error) 347214571Sdim return (error); 348214571Sdim 349214571Sdim /* now copy across the "interesting" information and fake the rest */ 350214571Sdim sbp->f_type = mstat.f_type; 351214571Sdim sbp->f_flags = mstat.f_flags; 352214571Sdim sbp->f_bsize = mstat.f_bsize; 353214571Sdim sbp->f_iosize = mstat.f_iosize; 354214571Sdim sbp->f_blocks = mstat.f_blocks; 355214571Sdim sbp->f_bfree = mstat.f_bfree; 356214571Sdim sbp->f_bavail = mstat.f_bavail; 357214571Sdim sbp->f_files = mstat.f_files; 358214571Sdim sbp->f_ffree = mstat.f_ffree; 359214571Sdim if (sbp != &mp->mnt_stat) { 360214571Sdim bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 361214571Sdim bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 362214571Sdim bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 363214571Sdim } 364214571Sdim return (0); 365214571Sdim} 366214571Sdim 367214571Sdimstatic int 368214571Sdimnullfs_sync(mp, waitfor, cred, p) 369214571Sdim struct mount *mp; 370214571Sdim int waitfor; 371214571Sdim struct ucred *cred; 372214571Sdim struct proc *p; 373214571Sdim{ 374214571Sdim /* 375214571Sdim * XXX - Assumes no data cached at null layer. 376214571Sdim */ 377214571Sdim return (0); 378214571Sdim} 379214571Sdim 380214571Sdimstatic int 381214571Sdimnullfs_vget(mp, ino, vpp) 382214571Sdim struct mount *mp; 383214571Sdim ino_t ino; 384214571Sdim struct vnode **vpp; 385214571Sdim{ 386214571Sdim 387214571Sdim return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp); 388214571Sdim} 389214571Sdim 390214571Sdimstatic int 391214571Sdimnullfs_fhtovp(mp, fidp, vpp) 392214571Sdim struct mount *mp; 393214571Sdim struct fid *fidp; 394214571Sdim struct vnode **vpp; 395214571Sdim{ 396214571Sdim 397214571Sdim return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, vpp); 398214571Sdim} 399214571Sdim 400214571Sdimstatic int 401214571Sdimnullfs_checkexp(mp, nam, extflagsp, credanonp) 402214571Sdim struct mount *mp; 403214571Sdim struct sockaddr *nam; 404214571Sdim int *extflagsp; 405214571Sdim struct ucred **credanonp; 406214571Sdim{ 407214571Sdim 408214571Sdim return VFS_CHECKEXP(MOUNTTONULLMOUNT(mp)->nullm_vfs, nam, 409214571Sdim extflagsp, credanonp); 410214571Sdim} 411214571Sdim 412214571Sdimstatic int 413214571Sdimnullfs_vptofh(vp, fhp) 414214571Sdim struct vnode *vp; 415214571Sdim struct fid *fhp; 416214571Sdim{ 417214571Sdim return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp); 418214571Sdim} 419214571Sdim 420214571Sdimstatic int 421214571Sdimnullfs_extattrctl(mp, cmd, attrname, arg, p) 422214571Sdim struct mount *mp; 423214571Sdim int cmd; 424214571Sdim const char *attrname; 425214571Sdim caddr_t arg; 426214571Sdim struct proc *p; 427214571Sdim{ 428214571Sdim return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, attrname, 429214571Sdim arg, p); 430214571Sdim} 431214571Sdim 432214571Sdim 433214571Sdimstatic struct vfsops null_vfsops = { 434214571Sdim nullfs_mount, 435214571Sdim nullfs_start, 436214571Sdim nullfs_unmount, 437214571Sdim nullfs_root, 438214571Sdim nullfs_quotactl, 439214571Sdim nullfs_statfs, 440214571Sdim nullfs_sync, 441214571Sdim nullfs_vget, 442214571Sdim nullfs_fhtovp, 443214571Sdim nullfs_checkexp, 444214571Sdim nullfs_vptofh, 445214571Sdim nullfs_init, 446214571Sdim vfs_stduninit, 447214571Sdim nullfs_extattrctl, 448214571Sdim}; 449214571Sdim 450214571SdimVFS_SET(null_vfsops, null, VFCF_LOOPBACK); 451214571Sdim