154752Sjohnh /* 254752Sjohnh * Copyright (c) 1992 The Regents of the University of California 354752Sjohnh * Copyright (c) 1990, 1992 Jan-Simon Pendry 454752Sjohnh * All rights reserved. 554752Sjohnh * 654752Sjohnh * This code is derived from software donated to Berkeley by 754752Sjohnh * Jan-Simon Pendry. 854752Sjohnh * 954752Sjohnh * %sccs.include.redist.c% 1054752Sjohnh * 11*54754Sjohnh * @(#)null_vfsops.c 1.2 (Berkeley) 6/18/92 1254752Sjohnh * 13*54754Sjohnh * $Id: null_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $ 1454752Sjohnh */ 1554752Sjohnh 1654752Sjohnh /* 17*54754Sjohnh * Null layer Filesystem 1854752Sjohnh */ 1954752Sjohnh 2054752Sjohnh #include <sys/param.h> 2154752Sjohnh #include <sys/systm.h> 2254752Sjohnh #include <sys/time.h> 2354752Sjohnh #include <sys/types.h> 2454752Sjohnh #include <sys/vnode.h> 2554752Sjohnh #include <sys/mount.h> 2654752Sjohnh #include <sys/namei.h> 2754752Sjohnh #include <sys/malloc.h> 2854752Sjohnh #include <lofs/lofs.h> 2954752Sjohnh 3054752Sjohnh /* 3154752Sjohnh * Mount loopback copy of existing name space 3254752Sjohnh */ 33*54754Sjohnh nullfs_mount(mp, path, data, ndp, p) 3454752Sjohnh struct mount *mp; 3554752Sjohnh char *path; 3654752Sjohnh caddr_t data; 3754752Sjohnh struct nameidata *ndp; 3854752Sjohnh struct proc *p; 3954752Sjohnh { 4054752Sjohnh USES_VOP_UNLOCK; 4154752Sjohnh int error = 0; 42*54754Sjohnh struct null_args args; 4354752Sjohnh struct vnode *vp; 44*54754Sjohnh struct vnode *nullm_rootvp; 45*54754Sjohnh struct null_mount *amp; 4654752Sjohnh u_int size; 4754752Sjohnh 48*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 49*54754Sjohnh printf("nullfs_mount(mp = %x)\n", mp); 5054752Sjohnh #endif 5154752Sjohnh 5254752Sjohnh /* 5354752Sjohnh * Update is a no-op 5454752Sjohnh */ 5554752Sjohnh if (mp->mnt_flag & MNT_UPDATE) { 5654752Sjohnh return (EOPNOTSUPP); 57*54754Sjohnh /* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/ 5854752Sjohnh } 5954752Sjohnh 6054752Sjohnh /* 6154752Sjohnh * Get argument 6254752Sjohnh */ 63*54754Sjohnh if (error = copyin(data, (caddr_t)&args, sizeof(struct null_args))) 6454752Sjohnh return (error); 6554752Sjohnh 6654752Sjohnh /* 6754752Sjohnh * Find target node 6854752Sjohnh */ 6954752Sjohnh NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF, 7054752Sjohnh UIO_USERSPACE, args.target, p); 7154752Sjohnh if (error = namei(ndp)) 7254752Sjohnh return (error); 7354752Sjohnh 7454752Sjohnh /* 7554752Sjohnh * Sanity check on target vnode 7654752Sjohnh */ 7754752Sjohnh vp = ndp->ni_vp; 78*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 7954752Sjohnh printf("vp = %x, check for VDIR...\n", vp); 8054752Sjohnh #endif 8154752Sjohnh vrele(ndp->ni_dvp); 8254752Sjohnh ndp->ni_dvp = 0; 8354752Sjohnh 8454752Sjohnh if (vp->v_type != VDIR) { 8554752Sjohnh vput(vp); 8654752Sjohnh return (EINVAL); 8754752Sjohnh } 8854752Sjohnh 89*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 9054752Sjohnh printf("mp = %x\n", mp); 9154752Sjohnh #endif 9254752Sjohnh 93*54754Sjohnh amp = (struct null_mount *) malloc(sizeof(struct null_mount), 9454752Sjohnh M_UFSMNT, M_WAITOK); /* XXX */ 9554752Sjohnh 9654752Sjohnh /* 9754752Sjohnh * Save reference to underlying target FS 9854752Sjohnh */ 99*54754Sjohnh amp->nullm_vfs = vp->v_mount; 10054752Sjohnh 10154752Sjohnh /* 10254752Sjohnh * Save reference. Each mount also holds 10354752Sjohnh * a reference on the root vnode. 10454752Sjohnh */ 105*54754Sjohnh error = make_null_node(mp, &vp); 10654752Sjohnh /* 10754752Sjohnh * Unlock the node (either the target or the alias) 10854752Sjohnh */ 10954752Sjohnh VOP_UNLOCK(vp); 11054752Sjohnh /* 11154752Sjohnh * Make sure the node alias worked 11254752Sjohnh */ 11354752Sjohnh if (error) { 11454752Sjohnh vrele(vp); 11554752Sjohnh free(amp, M_UFSMNT); /* XXX */ 11654752Sjohnh return (error); 11754752Sjohnh } 11854752Sjohnh 11954752Sjohnh /* 12054752Sjohnh * Keep a held reference to the root vnode. 121*54754Sjohnh * It is vrele'd in nullfs_unmount. 12254752Sjohnh */ 123*54754Sjohnh nullm_rootvp = vp; 124*54754Sjohnh nullm_rootvp->v_flag |= VROOT; 125*54754Sjohnh amp->nullm_rootvp = nullm_rootvp; 126*54754Sjohnh if (NULLTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) 12754752Sjohnh mp->mnt_flag |= MNT_LOCAL; 12854752Sjohnh mp->mnt_data = (qaddr_t) amp; 12954752Sjohnh getnewfsid(mp, MOUNT_LOFS); 13054752Sjohnh 13154752Sjohnh (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 13254752Sjohnh bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 13354752Sjohnh (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 13454752Sjohnh &size); 13554752Sjohnh bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 136*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 137*54754Sjohnh printf("nullfs_mount: target %s, alias at %s\n", 13854752Sjohnh mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 13954752Sjohnh #endif 14054752Sjohnh return (0); 14154752Sjohnh } 14254752Sjohnh 14354752Sjohnh /* 14454752Sjohnh * VFS start. Nothing needed here - the start routine 14554752Sjohnh * on the underlying filesystem will have been called 14654752Sjohnh * when that filesystem was mounted. 14754752Sjohnh */ 148*54754Sjohnh nullfs_start(mp, flags, p) 14954752Sjohnh struct mount *mp; 15054752Sjohnh int flags; 15154752Sjohnh struct proc *p; 15254752Sjohnh { 15354752Sjohnh return (0); 154*54754Sjohnh /* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */ 15554752Sjohnh } 15654752Sjohnh 15754752Sjohnh /* 15854752Sjohnh * Free reference to looped FS 15954752Sjohnh */ 160*54754Sjohnh nullfs_unmount(mp, mntflags, p) 16154752Sjohnh struct mount *mp; 16254752Sjohnh int mntflags; 16354752Sjohnh struct proc *p; 16454752Sjohnh { 165*54754Sjohnh struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 16654752Sjohnh int error; 16754752Sjohnh int flags = 0; 16854752Sjohnh extern int doforce; 16954752Sjohnh 170*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 171*54754Sjohnh printf("nullfs_unmount(mp = %x)\n", mp); 17254752Sjohnh #endif 17354752Sjohnh 17454752Sjohnh if (mntflags & MNT_FORCE) { 17554752Sjohnh /* lofs can never be rootfs so don't check for it */ 17654752Sjohnh if (!doforce) 17754752Sjohnh return (EINVAL); 17854752Sjohnh flags |= FORCECLOSE; 17954752Sjohnh } 18054752Sjohnh 18154752Sjohnh /* 18254752Sjohnh * Clear out buffer cache. I don't think we 18354752Sjohnh * ever get anything cached at this level at the 18454752Sjohnh * moment, but who knows... 18554752Sjohnh */ 18654752Sjohnh mntflushbuf(mp, 0); 18754752Sjohnh if (mntinvalbuf(mp, 1)) 18854752Sjohnh return (EBUSY); 189*54754Sjohnh if (nullm_rootvp->v_usecount > 1) 19054752Sjohnh return (EBUSY); 191*54754Sjohnh if (error = vflush(mp, nullm_rootvp, flags)) 19254752Sjohnh return (error); 19354752Sjohnh 194*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 19554752Sjohnh /* 19654752Sjohnh * Flush any remaining vnode references 19754752Sjohnh */ 198*54754Sjohnh null_node_flushmp (mp); 19954752Sjohnh #endif 20054752Sjohnh 201*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 202*54754Sjohnh vprint("alias root of target", nullm_rootvp); 20354752Sjohnh #endif 20454752Sjohnh /* 20554752Sjohnh * Release reference on underlying root vnode 20654752Sjohnh */ 207*54754Sjohnh vrele(nullm_rootvp); 20854752Sjohnh /* 20954752Sjohnh * And blow it away for future re-use 21054752Sjohnh */ 211*54754Sjohnh vgone(nullm_rootvp); 21254752Sjohnh /* 213*54754Sjohnh * Finally, throw away the null_mount structure 21454752Sjohnh */ 21554752Sjohnh free(mp->mnt_data, M_UFSMNT); /* XXX */ 21654752Sjohnh mp->mnt_data = 0; 21754752Sjohnh return 0; 21854752Sjohnh } 21954752Sjohnh 220*54754Sjohnh nullfs_root(mp, vpp) 22154752Sjohnh struct mount *mp; 22254752Sjohnh struct vnode **vpp; 22354752Sjohnh { 22454752Sjohnh USES_VOP_LOCK; 22554752Sjohnh struct vnode *vp; 22654752Sjohnh 227*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 228*54754Sjohnh printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp, 229*54754Sjohnh MOUNTTONULLMOUNT(mp)->nullm_rootvp, 230*54754Sjohnh NULLTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) 23154752Sjohnh ); 23254752Sjohnh #endif 23354752Sjohnh 23454752Sjohnh /* 23554752Sjohnh * Return locked reference to root. 23654752Sjohnh */ 237*54754Sjohnh vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 23854752Sjohnh VREF(vp); 23954752Sjohnh VOP_LOCK(vp); 24054752Sjohnh *vpp = vp; 24154752Sjohnh return 0; 24254752Sjohnh } 24354752Sjohnh 244*54754Sjohnh nullfs_quotactl(mp, cmd, uid, arg, p) 24554752Sjohnh struct mount *mp; 24654752Sjohnh int cmd; 24754752Sjohnh uid_t uid; 24854752Sjohnh caddr_t arg; 24954752Sjohnh struct proc *p; 25054752Sjohnh { 251*54754Sjohnh return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p); 25254752Sjohnh } 25354752Sjohnh 254*54754Sjohnh nullfs_statfs(mp, sbp, p) 25554752Sjohnh struct mount *mp; 25654752Sjohnh struct statfs *sbp; 25754752Sjohnh struct proc *p; 25854752Sjohnh { 25954752Sjohnh int error; 26054752Sjohnh struct statfs mstat; 26154752Sjohnh 262*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC 263*54754Sjohnh printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp, 264*54754Sjohnh MOUNTTONULLMOUNT(mp)->nullm_rootvp, 265*54754Sjohnh NULLTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) 26654752Sjohnh ); 26754752Sjohnh #endif 26854752Sjohnh 26954752Sjohnh bzero(&mstat, sizeof(mstat)); 27054752Sjohnh 271*54754Sjohnh error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p); 27254752Sjohnh if (error) 27354752Sjohnh return (error); 27454752Sjohnh 27554752Sjohnh /* now copy across the "interesting" information and fake the rest */ 27654752Sjohnh sbp->f_type = mstat.f_type; 27754752Sjohnh sbp->f_flags = mstat.f_flags; 27854752Sjohnh sbp->f_bsize = mstat.f_bsize; 27954752Sjohnh sbp->f_iosize = mstat.f_iosize; 28054752Sjohnh sbp->f_blocks = mstat.f_blocks; 28154752Sjohnh sbp->f_bfree = mstat.f_bfree; 28254752Sjohnh sbp->f_bavail = mstat.f_bavail; 28354752Sjohnh sbp->f_files = mstat.f_files; 28454752Sjohnh sbp->f_ffree = mstat.f_ffree; 28554752Sjohnh if (sbp != &mp->mnt_stat) { 28654752Sjohnh bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 28754752Sjohnh bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 28854752Sjohnh bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 28954752Sjohnh } 29054752Sjohnh return (0); 29154752Sjohnh } 29254752Sjohnh 293*54754Sjohnh nullfs_sync(mp, waitfor) 29454752Sjohnh struct mount *mp; 29554752Sjohnh int waitfor; 29654752Sjohnh { 29754752Sjohnh return (0); 29854752Sjohnh } 29954752Sjohnh 300*54754Sjohnh nullfs_fhtovp(mp, fhp, setgen, vpp) 30154752Sjohnh struct mount *mp; 30254752Sjohnh struct fid *fhp; 30354752Sjohnh int setgen; 30454752Sjohnh struct vnode **vpp; 30554752Sjohnh { 306*54754Sjohnh return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fhp, setgen, vpp); 30754752Sjohnh } 30854752Sjohnh 309*54754Sjohnh nullfs_vptofh(vp, fhp) 31054752Sjohnh struct vnode *vp; 31154752Sjohnh struct fid *fhp; 31254752Sjohnh { 313*54754Sjohnh return VFS_VPTOFH(NULLTOLOWERVP(vp), fhp); 31454752Sjohnh } 31554752Sjohnh 316*54754Sjohnh int nullfs_init __P((void)); 31754752Sjohnh 318*54754Sjohnh struct vfsops null_vfsops = { 319*54754Sjohnh nullfs_mount, 320*54754Sjohnh nullfs_start, 321*54754Sjohnh nullfs_unmount, 322*54754Sjohnh nullfs_root, 323*54754Sjohnh nullfs_quotactl, 324*54754Sjohnh nullfs_statfs, 325*54754Sjohnh nullfs_sync, 326*54754Sjohnh nullfs_fhtovp, 327*54754Sjohnh nullfs_vptofh, 328*54754Sjohnh nullfs_init, 32954752Sjohnh }; 330