1*54752Sjohnh /* 2*54752Sjohnh * Copyright (c) 1992 The Regents of the University of California 3*54752Sjohnh * Copyright (c) 1990, 1992 Jan-Simon Pendry 4*54752Sjohnh * All rights reserved. 5*54752Sjohnh * 6*54752Sjohnh * This code is derived from software donated to Berkeley by 7*54752Sjohnh * Jan-Simon Pendry. 8*54752Sjohnh * 9*54752Sjohnh * %sccs.include.redist.c% 10*54752Sjohnh * 11*54752Sjohnh * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 12*54752Sjohnh * 13*54752Sjohnh * $Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $ 14*54752Sjohnh */ 15*54752Sjohnh 16*54752Sjohnh /* 17*54752Sjohnh * Loopback Filesystem 18*54752Sjohnh */ 19*54752Sjohnh 20*54752Sjohnh #include <sys/param.h> 21*54752Sjohnh #include <sys/systm.h> 22*54752Sjohnh #include <sys/time.h> 23*54752Sjohnh #include <sys/types.h> 24*54752Sjohnh #include <sys/vnode.h> 25*54752Sjohnh #include <sys/mount.h> 26*54752Sjohnh #include <sys/namei.h> 27*54752Sjohnh #include <sys/malloc.h> 28*54752Sjohnh #include <lofs/lofs.h> 29*54752Sjohnh 30*54752Sjohnh /* 31*54752Sjohnh * Mount loopback copy of existing name space 32*54752Sjohnh */ 33*54752Sjohnh lofs_mount(mp, path, data, ndp, p) 34*54752Sjohnh struct mount *mp; 35*54752Sjohnh char *path; 36*54752Sjohnh caddr_t data; 37*54752Sjohnh struct nameidata *ndp; 38*54752Sjohnh struct proc *p; 39*54752Sjohnh { 40*54752Sjohnh USES_VOP_UNLOCK; 41*54752Sjohnh int error = 0; 42*54752Sjohnh struct lofs_args args; 43*54752Sjohnh struct vnode *vp; 44*54752Sjohnh struct vnode *rootvp; 45*54752Sjohnh struct lofsmount *amp; 46*54752Sjohnh u_int size; 47*54752Sjohnh 48*54752Sjohnh #ifdef LOFS_DIAGNOSTIC 49*54752Sjohnh printf("lofs_mount(mp = %x)\n", mp); 50*54752Sjohnh #endif 51*54752Sjohnh 52*54752Sjohnh /* 53*54752Sjohnh * Update is a no-op 54*54752Sjohnh */ 55*54752Sjohnh if (mp->mnt_flag & MNT_UPDATE) { 56*54752Sjohnh return (EOPNOTSUPP); 57*54752Sjohnh /* return VFS_MOUNT(VFSTOLOFS(mp)->looped_vfs, path, data, ndp, p);*/ 58*54752Sjohnh } 59*54752Sjohnh 60*54752Sjohnh /* 61*54752Sjohnh * Get argument 62*54752Sjohnh */ 63*54752Sjohnh if (error = copyin(data, (caddr_t)&args, sizeof(struct lofs_args))) 64*54752Sjohnh return (error); 65*54752Sjohnh 66*54752Sjohnh /* 67*54752Sjohnh * Find target node 68*54752Sjohnh */ 69*54752Sjohnh NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF, 70*54752Sjohnh UIO_USERSPACE, args.target, p); 71*54752Sjohnh if (error = namei(ndp)) 72*54752Sjohnh return (error); 73*54752Sjohnh 74*54752Sjohnh /* 75*54752Sjohnh * Sanity check on target vnode 76*54752Sjohnh */ 77*54752Sjohnh vp = ndp->ni_vp; 78*54752Sjohnh #ifdef LOFS_DIAGNOSTIC 79*54752Sjohnh printf("vp = %x, check for VDIR...\n", vp); 80*54752Sjohnh #endif 81*54752Sjohnh vrele(ndp->ni_dvp); 82*54752Sjohnh ndp->ni_dvp = 0; 83*54752Sjohnh 84*54752Sjohnh if (vp->v_type != VDIR) { 85*54752Sjohnh vput(vp); 86*54752Sjohnh return (EINVAL); 87*54752Sjohnh } 88*54752Sjohnh 89*54752Sjohnh #ifdef LOFS_DIAGNOSTIC 90*54752Sjohnh printf("mp = %x\n", mp); 91*54752Sjohnh #endif 92*54752Sjohnh 93*54752Sjohnh amp = (struct lofsmount *) malloc(sizeof(struct lofsmount), 94*54752Sjohnh M_UFSMNT, M_WAITOK); /* XXX */ 95*54752Sjohnh 96*54752Sjohnh /* 97*54752Sjohnh * Save reference to underlying target FS 98*54752Sjohnh */ 99*54752Sjohnh amp->looped_vfs = vp->v_mount; 100*54752Sjohnh 101*54752Sjohnh /* 102*54752Sjohnh * Save reference. Each mount also holds 103*54752Sjohnh * a reference on the root vnode. 104*54752Sjohnh */ 105*54752Sjohnh error = make_lofs(mp, &vp); 106*54752Sjohnh /* 107*54752Sjohnh * Unlock the node (either the target or the alias) 108*54752Sjohnh */ 109*54752Sjohnh VOP_UNLOCK(vp); 110*54752Sjohnh /* 111*54752Sjohnh * Make sure the node alias worked 112*54752Sjohnh */ 113*54752Sjohnh if (error) { 114*54752Sjohnh vrele(vp); 115*54752Sjohnh free(amp, M_UFSMNT); /* XXX */ 116*54752Sjohnh return (error); 117*54752Sjohnh } 118*54752Sjohnh 119*54752Sjohnh /* 120*54752Sjohnh * Keep a held reference to the root vnode. 121*54752Sjohnh * It is vrele'd in lofs_unmount. 122*54752Sjohnh */ 123*54752Sjohnh rootvp = vp; 124*54752Sjohnh rootvp->v_flag |= VROOT; 125*54752Sjohnh amp->rootvp = rootvp; 126*54752Sjohnh if (LOFSVP(rootvp)->v_mount->mnt_flag & MNT_LOCAL) 127*54752Sjohnh mp->mnt_flag |= MNT_LOCAL; 128*54752Sjohnh mp->mnt_data = (qaddr_t) amp; 129*54752Sjohnh getnewfsid(mp, MOUNT_LOFS); 130*54752Sjohnh 131*54752Sjohnh (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 132*54752Sjohnh bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 133*54752Sjohnh (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 134*54752Sjohnh &size); 135*54752Sjohnh bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 136*54752Sjohnh #ifdef LOFS_DIAGNOSTIC 137*54752Sjohnh printf("lofs_mount: target %s, alias at %s\n", 138*54752Sjohnh mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 139*54752Sjohnh #endif 140*54752Sjohnh return (0); 141*54752Sjohnh } 142*54752Sjohnh 143*54752Sjohnh /* 144*54752Sjohnh * VFS start. Nothing needed here - the start routine 145*54752Sjohnh * on the underlying filesystem will have been called 146*54752Sjohnh * when that filesystem was mounted. 147*54752Sjohnh */ 148*54752Sjohnh lofs_start(mp, flags, p) 149*54752Sjohnh struct mount *mp; 150*54752Sjohnh int flags; 151*54752Sjohnh struct proc *p; 152*54752Sjohnh { 153*54752Sjohnh return (0); 154*54752Sjohnh /* return VFS_START(VFSTOLOFS(mp)->looped_vfs, flags, p); */ 155*54752Sjohnh } 156*54752Sjohnh 157*54752Sjohnh /* 158*54752Sjohnh * Free reference to looped FS 159*54752Sjohnh */ 160*54752Sjohnh lofs_unmount(mp, mntflags, p) 161*54752Sjohnh struct mount *mp; 162*54752Sjohnh int mntflags; 163*54752Sjohnh struct proc *p; 164*54752Sjohnh { 165*54752Sjohnh struct vnode *rootvp = VFSTOLOFS(mp)->rootvp; 166*54752Sjohnh int error; 167*54752Sjohnh int flags = 0; 168*54752Sjohnh extern int doforce; 169*54752Sjohnh 170*54752Sjohnh #ifdef LOFS_DIAGNOSTIC 171*54752Sjohnh printf("lofs_unmount(mp = %x)\n", mp); 172*54752Sjohnh #endif 173*54752Sjohnh 174*54752Sjohnh if (mntflags & MNT_FORCE) { 175*54752Sjohnh /* lofs can never be rootfs so don't check for it */ 176*54752Sjohnh if (!doforce) 177*54752Sjohnh return (EINVAL); 178*54752Sjohnh flags |= FORCECLOSE; 179*54752Sjohnh } 180*54752Sjohnh 181*54752Sjohnh /* 182*54752Sjohnh * Clear out buffer cache. I don't think we 183*54752Sjohnh * ever get anything cached at this level at the 184*54752Sjohnh * moment, but who knows... 185*54752Sjohnh */ 186*54752Sjohnh mntflushbuf(mp, 0); 187*54752Sjohnh if (mntinvalbuf(mp, 1)) 188*54752Sjohnh return (EBUSY); 189*54752Sjohnh if (rootvp->v_usecount > 1) 190*54752Sjohnh return (EBUSY); 191*54752Sjohnh if (error = vflush(mp, rootvp, flags)) 192*54752Sjohnh return (error); 193*54752Sjohnh 194*54752Sjohnh #ifdef LOFS_DIAGNOSTIC 195*54752Sjohnh /* 196*54752Sjohnh * Flush any remaining vnode references 197*54752Sjohnh */ 198*54752Sjohnh lofs_flushmp(mp); 199*54752Sjohnh #endif 200*54752Sjohnh 201*54752Sjohnh #ifdef LOFS_DIAGNOSTIC 202*54752Sjohnh vprint("alias root of target", rootvp); 203*54752Sjohnh #endif 204*54752Sjohnh /* 205*54752Sjohnh * Release reference on underlying root vnode 206*54752Sjohnh */ 207*54752Sjohnh vrele(rootvp); 208*54752Sjohnh /* 209*54752Sjohnh * And blow it away for future re-use 210*54752Sjohnh */ 211*54752Sjohnh vgone(rootvp); 212*54752Sjohnh /* 213*54752Sjohnh * Finally, throw away the lofsmount structure 214*54752Sjohnh */ 215*54752Sjohnh free(mp->mnt_data, M_UFSMNT); /* XXX */ 216*54752Sjohnh mp->mnt_data = 0; 217*54752Sjohnh return 0; 218*54752Sjohnh } 219*54752Sjohnh 220*54752Sjohnh lofs_root(mp, vpp) 221*54752Sjohnh struct mount *mp; 222*54752Sjohnh struct vnode **vpp; 223*54752Sjohnh { 224*54752Sjohnh USES_VOP_LOCK; 225*54752Sjohnh struct vnode *vp; 226*54752Sjohnh 227*54752Sjohnh #ifdef LOFS_DIAGNOSTIC 228*54752Sjohnh printf("lofs_root(mp = %x, vp = %x->%x)\n", mp, 229*54752Sjohnh VFSTOLOFS(mp)->rootvp, 230*54752Sjohnh LOFSVP(VFSTOLOFS(mp)->rootvp) 231*54752Sjohnh ); 232*54752Sjohnh #endif 233*54752Sjohnh 234*54752Sjohnh /* 235*54752Sjohnh * Return locked reference to root. 236*54752Sjohnh */ 237*54752Sjohnh vp = VFSTOLOFS(mp)->rootvp; 238*54752Sjohnh VREF(vp); 239*54752Sjohnh VOP_LOCK(vp); 240*54752Sjohnh *vpp = vp; 241*54752Sjohnh return 0; 242*54752Sjohnh } 243*54752Sjohnh 244*54752Sjohnh lofs_quotactl(mp, cmd, uid, arg, p) 245*54752Sjohnh struct mount *mp; 246*54752Sjohnh int cmd; 247*54752Sjohnh uid_t uid; 248*54752Sjohnh caddr_t arg; 249*54752Sjohnh struct proc *p; 250*54752Sjohnh { 251*54752Sjohnh return VFS_QUOTACTL(VFSTOLOFS(mp)->looped_vfs, cmd, uid, arg, p); 252*54752Sjohnh } 253*54752Sjohnh 254*54752Sjohnh lofs_statfs(mp, sbp, p) 255*54752Sjohnh struct mount *mp; 256*54752Sjohnh struct statfs *sbp; 257*54752Sjohnh struct proc *p; 258*54752Sjohnh { 259*54752Sjohnh int error; 260*54752Sjohnh struct statfs mstat; 261*54752Sjohnh 262*54752Sjohnh #ifdef LOFS_DIAGNOSTIC 263*54752Sjohnh printf("lofs_statfs(mp = %x, vp = %x->%x)\n", mp, 264*54752Sjohnh VFSTOLOFS(mp)->rootvp, 265*54752Sjohnh LOFSVP(VFSTOLOFS(mp)->rootvp) 266*54752Sjohnh ); 267*54752Sjohnh #endif 268*54752Sjohnh 269*54752Sjohnh bzero(&mstat, sizeof(mstat)); 270*54752Sjohnh 271*54752Sjohnh error = VFS_STATFS(VFSTOLOFS(mp)->looped_vfs, &mstat, p); 272*54752Sjohnh if (error) 273*54752Sjohnh return (error); 274*54752Sjohnh 275*54752Sjohnh /* now copy across the "interesting" information and fake the rest */ 276*54752Sjohnh sbp->f_type = mstat.f_type; 277*54752Sjohnh sbp->f_flags = mstat.f_flags; 278*54752Sjohnh sbp->f_bsize = mstat.f_bsize; 279*54752Sjohnh sbp->f_iosize = mstat.f_iosize; 280*54752Sjohnh sbp->f_blocks = mstat.f_blocks; 281*54752Sjohnh sbp->f_bfree = mstat.f_bfree; 282*54752Sjohnh sbp->f_bavail = mstat.f_bavail; 283*54752Sjohnh sbp->f_files = mstat.f_files; 284*54752Sjohnh sbp->f_ffree = mstat.f_ffree; 285*54752Sjohnh if (sbp != &mp->mnt_stat) { 286*54752Sjohnh bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 287*54752Sjohnh bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 288*54752Sjohnh bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 289*54752Sjohnh } 290*54752Sjohnh return (0); 291*54752Sjohnh } 292*54752Sjohnh 293*54752Sjohnh lofs_sync(mp, waitfor) 294*54752Sjohnh struct mount *mp; 295*54752Sjohnh int waitfor; 296*54752Sjohnh { 297*54752Sjohnh return (0); 298*54752Sjohnh } 299*54752Sjohnh 300*54752Sjohnh lofs_fhtovp(mp, fhp, setgen, vpp) 301*54752Sjohnh struct mount *mp; 302*54752Sjohnh struct fid *fhp; 303*54752Sjohnh int setgen; 304*54752Sjohnh struct vnode **vpp; 305*54752Sjohnh { 306*54752Sjohnh return VFS_FHTOVP(VFSTOLOFS(mp)->looped_vfs, fhp, setgen, vpp); 307*54752Sjohnh } 308*54752Sjohnh 309*54752Sjohnh lofs_vptofh(vp, fhp) 310*54752Sjohnh struct vnode *vp; 311*54752Sjohnh struct fid *fhp; 312*54752Sjohnh { 313*54752Sjohnh return VFS_VPTOFH(LOFSVP(vp), fhp); 314*54752Sjohnh } 315*54752Sjohnh 316*54752Sjohnh int lofs_init __P((void)); 317*54752Sjohnh 318*54752Sjohnh struct vfsops lofs_vfsops = { 319*54752Sjohnh lofs_mount, 320*54752Sjohnh lofs_start, 321*54752Sjohnh lofs_unmount, 322*54752Sjohnh lofs_root, 323*54752Sjohnh lofs_quotactl, 324*54752Sjohnh lofs_statfs, 325*54752Sjohnh lofs_sync, 326*54752Sjohnh lofs_fhtovp, 327*54752Sjohnh lofs_vptofh, 328*54752Sjohnh lofs_init, 329*54752Sjohnh }; 330