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*54766Sjohnh * @(#)null_vfsops.c 1.3 (Berkeley) 07/07/92 1254752Sjohnh * 13*54766Sjohnh * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 14*54766Sjohnh * $Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $ 1554752Sjohnh */ 1654752Sjohnh 1754752Sjohnh /* 18*54766Sjohnh * Null Layer 19*54766Sjohnh * (See null_vnops.c for a description of what this does.) 2054752Sjohnh */ 2154752Sjohnh 2254752Sjohnh #include <sys/param.h> 2354752Sjohnh #include <sys/systm.h> 2454752Sjohnh #include <sys/time.h> 2554752Sjohnh #include <sys/types.h> 2654752Sjohnh #include <sys/vnode.h> 2754752Sjohnh #include <sys/mount.h> 2854752Sjohnh #include <sys/namei.h> 2954752Sjohnh #include <sys/malloc.h> 3054752Sjohnh #include <lofs/lofs.h> 3154752Sjohnh 3254752Sjohnh /* 33*54766Sjohnh * Mount null layer 3454752Sjohnh */ 3554754Sjohnh nullfs_mount(mp, path, data, ndp, p) 3654752Sjohnh struct mount *mp; 3754752Sjohnh char *path; 3854752Sjohnh caddr_t data; 3954752Sjohnh struct nameidata *ndp; 4054752Sjohnh struct proc *p; 4154752Sjohnh { 4254752Sjohnh USES_VOP_UNLOCK; 4354752Sjohnh int error = 0; 4454754Sjohnh struct null_args args; 45*54766Sjohnh struct vnode *lowerrootvp, *vp; 4654754Sjohnh struct vnode *nullm_rootvp; 4754754Sjohnh struct null_mount *amp; 4854752Sjohnh u_int size; 4954752Sjohnh 5054754Sjohnh #ifdef NULLFS_DIAGNOSTIC 5154754Sjohnh printf("nullfs_mount(mp = %x)\n", mp); 5254752Sjohnh #endif 5354752Sjohnh 5454752Sjohnh /* 5554752Sjohnh * Update is a no-op 5654752Sjohnh */ 5754752Sjohnh if (mp->mnt_flag & MNT_UPDATE) { 5854752Sjohnh return (EOPNOTSUPP); 5954754Sjohnh /* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/ 6054752Sjohnh } 6154752Sjohnh 6254752Sjohnh /* 6354752Sjohnh * Get argument 6454752Sjohnh */ 6554754Sjohnh if (error = copyin(data, (caddr_t)&args, sizeof(struct null_args))) 6654752Sjohnh return (error); 6754752Sjohnh 6854752Sjohnh /* 6954752Sjohnh * Find target node 7054752Sjohnh */ 7154752Sjohnh NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF, 7254752Sjohnh UIO_USERSPACE, args.target, p); 7354752Sjohnh if (error = namei(ndp)) 7454752Sjohnh return (error); 7554752Sjohnh 7654752Sjohnh /* 7754752Sjohnh * Sanity check on target vnode 7854752Sjohnh */ 79*54766Sjohnh lowerrootvp = ndp->ni_vp; 8054754Sjohnh #ifdef NULLFS_DIAGNOSTIC 81*54766Sjohnh printf("vp = %x, check for VDIR...\n", lowerrootvp); 8254752Sjohnh #endif 8354752Sjohnh vrele(ndp->ni_dvp); 8454752Sjohnh ndp->ni_dvp = 0; 8554752Sjohnh 86*54766Sjohnh /* 87*54766Sjohnh * NEEDSWORK: Is this really bad, or just not 88*54766Sjohnh * the way it's been? 89*54766Sjohnh */ 90*54766Sjohnh if (lowerrootvp->v_type != VDIR) { 91*54766Sjohnh vput(lowerrootvp); 9254752Sjohnh return (EINVAL); 9354752Sjohnh } 9454752Sjohnh 9554754Sjohnh #ifdef NULLFS_DIAGNOSTIC 9654752Sjohnh printf("mp = %x\n", mp); 9754752Sjohnh #endif 9854752Sjohnh 9954754Sjohnh amp = (struct null_mount *) malloc(sizeof(struct null_mount), 10054752Sjohnh M_UFSMNT, M_WAITOK); /* XXX */ 10154752Sjohnh 10254752Sjohnh /* 10354752Sjohnh * Save reference to underlying target FS 10454752Sjohnh */ 105*54766Sjohnh amp->nullm_vfs = lowerrootvp->v_mount; 10654752Sjohnh 10754752Sjohnh /* 10854752Sjohnh * Save reference. Each mount also holds 10954752Sjohnh * a reference on the root vnode. 11054752Sjohnh */ 111*54766Sjohnh error = make_null_node(mp, lowerrootvp, &vp); 11254752Sjohnh /* 11354752Sjohnh * Unlock the node (either the target or the alias) 11454752Sjohnh */ 11554752Sjohnh VOP_UNLOCK(vp); 11654752Sjohnh /* 11754752Sjohnh * Make sure the node alias worked 11854752Sjohnh */ 11954752Sjohnh if (error) { 120*54766Sjohnh vrele(lowerrootvp); 12154752Sjohnh free(amp, M_UFSMNT); /* XXX */ 12254752Sjohnh return (error); 12354752Sjohnh } 12454752Sjohnh 12554752Sjohnh /* 12654752Sjohnh * Keep a held reference to the root vnode. 12754754Sjohnh * It is vrele'd in nullfs_unmount. 12854752Sjohnh */ 12954754Sjohnh nullm_rootvp = vp; 13054754Sjohnh nullm_rootvp->v_flag |= VROOT; 13154754Sjohnh amp->nullm_rootvp = nullm_rootvp; 13254754Sjohnh if (NULLTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) 13354752Sjohnh mp->mnt_flag |= MNT_LOCAL; 13454752Sjohnh mp->mnt_data = (qaddr_t) amp; 13554752Sjohnh getnewfsid(mp, MOUNT_LOFS); 13654752Sjohnh 13754752Sjohnh (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 13854752Sjohnh bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 13954752Sjohnh (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 14054752Sjohnh &size); 14154752Sjohnh bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 14254754Sjohnh #ifdef NULLFS_DIAGNOSTIC 14354754Sjohnh printf("nullfs_mount: target %s, alias at %s\n", 14454752Sjohnh mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 14554752Sjohnh #endif 14654752Sjohnh return (0); 14754752Sjohnh } 14854752Sjohnh 14954752Sjohnh /* 15054752Sjohnh * VFS start. Nothing needed here - the start routine 15154752Sjohnh * on the underlying filesystem will have been called 15254752Sjohnh * when that filesystem was mounted. 15354752Sjohnh */ 15454754Sjohnh nullfs_start(mp, flags, p) 15554752Sjohnh struct mount *mp; 15654752Sjohnh int flags; 15754752Sjohnh struct proc *p; 15854752Sjohnh { 15954752Sjohnh return (0); 16054754Sjohnh /* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */ 16154752Sjohnh } 16254752Sjohnh 16354752Sjohnh /* 164*54766Sjohnh * Free reference to null layer 16554752Sjohnh */ 16654754Sjohnh nullfs_unmount(mp, mntflags, p) 16754752Sjohnh struct mount *mp; 16854752Sjohnh int mntflags; 16954752Sjohnh struct proc *p; 17054752Sjohnh { 17154754Sjohnh struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 17254752Sjohnh int error; 17354752Sjohnh int flags = 0; 17454752Sjohnh extern int doforce; 17554752Sjohnh 17654754Sjohnh #ifdef NULLFS_DIAGNOSTIC 17754754Sjohnh printf("nullfs_unmount(mp = %x)\n", mp); 17854752Sjohnh #endif 17954752Sjohnh 18054752Sjohnh if (mntflags & MNT_FORCE) { 18154752Sjohnh /* lofs can never be rootfs so don't check for it */ 18254752Sjohnh if (!doforce) 18354752Sjohnh return (EINVAL); 18454752Sjohnh flags |= FORCECLOSE; 18554752Sjohnh } 18654752Sjohnh 18754752Sjohnh /* 18854752Sjohnh * Clear out buffer cache. I don't think we 18954752Sjohnh * ever get anything cached at this level at the 19054752Sjohnh * moment, but who knows... 19154752Sjohnh */ 19254752Sjohnh mntflushbuf(mp, 0); 19354752Sjohnh if (mntinvalbuf(mp, 1)) 19454752Sjohnh return (EBUSY); 19554754Sjohnh if (nullm_rootvp->v_usecount > 1) 19654752Sjohnh return (EBUSY); 19754754Sjohnh if (error = vflush(mp, nullm_rootvp, flags)) 19854752Sjohnh return (error); 19954752Sjohnh 20054754Sjohnh #ifdef NULLFS_DIAGNOSTIC 20154752Sjohnh /* 20254752Sjohnh * Flush any remaining vnode references 20354752Sjohnh */ 20454754Sjohnh null_node_flushmp (mp); 20554752Sjohnh #endif 20654752Sjohnh 20754754Sjohnh #ifdef NULLFS_DIAGNOSTIC 20854754Sjohnh vprint("alias root of target", nullm_rootvp); 20954752Sjohnh #endif 21054752Sjohnh /* 21154752Sjohnh * Release reference on underlying root vnode 21254752Sjohnh */ 21354754Sjohnh vrele(nullm_rootvp); 21454752Sjohnh /* 21554752Sjohnh * And blow it away for future re-use 21654752Sjohnh */ 21754754Sjohnh vgone(nullm_rootvp); 21854752Sjohnh /* 21954754Sjohnh * Finally, throw away the null_mount structure 22054752Sjohnh */ 22154752Sjohnh free(mp->mnt_data, M_UFSMNT); /* XXX */ 22254752Sjohnh mp->mnt_data = 0; 22354752Sjohnh return 0; 22454752Sjohnh } 22554752Sjohnh 22654754Sjohnh nullfs_root(mp, vpp) 22754752Sjohnh struct mount *mp; 22854752Sjohnh struct vnode **vpp; 22954752Sjohnh { 23054752Sjohnh USES_VOP_LOCK; 23154752Sjohnh struct vnode *vp; 23254752Sjohnh 23354754Sjohnh #ifdef NULLFS_DIAGNOSTIC 23454754Sjohnh printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp, 23554754Sjohnh MOUNTTONULLMOUNT(mp)->nullm_rootvp, 23654754Sjohnh NULLTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) 23754752Sjohnh ); 23854752Sjohnh #endif 23954752Sjohnh 24054752Sjohnh /* 24154752Sjohnh * Return locked reference to root. 24254752Sjohnh */ 24354754Sjohnh vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 24454752Sjohnh VREF(vp); 24554752Sjohnh VOP_LOCK(vp); 24654752Sjohnh *vpp = vp; 24754752Sjohnh return 0; 24854752Sjohnh } 24954752Sjohnh 25054754Sjohnh nullfs_quotactl(mp, cmd, uid, arg, p) 25154752Sjohnh struct mount *mp; 25254752Sjohnh int cmd; 25354752Sjohnh uid_t uid; 25454752Sjohnh caddr_t arg; 25554752Sjohnh struct proc *p; 25654752Sjohnh { 25754754Sjohnh return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p); 25854752Sjohnh } 25954752Sjohnh 26054754Sjohnh nullfs_statfs(mp, sbp, p) 26154752Sjohnh struct mount *mp; 26254752Sjohnh struct statfs *sbp; 26354752Sjohnh struct proc *p; 26454752Sjohnh { 26554752Sjohnh int error; 26654752Sjohnh struct statfs mstat; 26754752Sjohnh 26854754Sjohnh #ifdef NULLFS_DIAGNOSTIC 26954754Sjohnh printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp, 27054754Sjohnh MOUNTTONULLMOUNT(mp)->nullm_rootvp, 27154754Sjohnh NULLTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) 27254752Sjohnh ); 27354752Sjohnh #endif 27454752Sjohnh 27554752Sjohnh bzero(&mstat, sizeof(mstat)); 27654752Sjohnh 27754754Sjohnh error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p); 27854752Sjohnh if (error) 27954752Sjohnh return (error); 28054752Sjohnh 28154752Sjohnh /* now copy across the "interesting" information and fake the rest */ 28254752Sjohnh sbp->f_type = mstat.f_type; 28354752Sjohnh sbp->f_flags = mstat.f_flags; 28454752Sjohnh sbp->f_bsize = mstat.f_bsize; 28554752Sjohnh sbp->f_iosize = mstat.f_iosize; 28654752Sjohnh sbp->f_blocks = mstat.f_blocks; 28754752Sjohnh sbp->f_bfree = mstat.f_bfree; 28854752Sjohnh sbp->f_bavail = mstat.f_bavail; 28954752Sjohnh sbp->f_files = mstat.f_files; 29054752Sjohnh sbp->f_ffree = mstat.f_ffree; 29154752Sjohnh if (sbp != &mp->mnt_stat) { 29254752Sjohnh bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 29354752Sjohnh bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 29454752Sjohnh bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 29554752Sjohnh } 29654752Sjohnh return (0); 29754752Sjohnh } 29854752Sjohnh 29954754Sjohnh nullfs_sync(mp, waitfor) 30054752Sjohnh struct mount *mp; 30154752Sjohnh int waitfor; 30254752Sjohnh { 303*54766Sjohnh /* 304*54766Sjohnh * NEEDSWORK: Assumes no data cached at null layer. 305*54766Sjohnh * Is this true? 306*54766Sjohnh */ 30754752Sjohnh return (0); 30854752Sjohnh } 30954752Sjohnh 31054754Sjohnh nullfs_fhtovp(mp, fhp, setgen, vpp) 31154752Sjohnh struct mount *mp; 31254752Sjohnh struct fid *fhp; 31354752Sjohnh int setgen; 31454752Sjohnh struct vnode **vpp; 31554752Sjohnh { 31654754Sjohnh return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fhp, setgen, vpp); 31754752Sjohnh } 31854752Sjohnh 31954754Sjohnh nullfs_vptofh(vp, fhp) 32054752Sjohnh struct vnode *vp; 32154752Sjohnh struct fid *fhp; 32254752Sjohnh { 32354754Sjohnh return VFS_VPTOFH(NULLTOLOWERVP(vp), fhp); 32454752Sjohnh } 32554752Sjohnh 32654754Sjohnh int nullfs_init __P((void)); 32754752Sjohnh 32854754Sjohnh struct vfsops null_vfsops = { 32954754Sjohnh nullfs_mount, 33054754Sjohnh nullfs_start, 33154754Sjohnh nullfs_unmount, 33254754Sjohnh nullfs_root, 33354754Sjohnh nullfs_quotactl, 33454754Sjohnh nullfs_statfs, 33554754Sjohnh nullfs_sync, 33654754Sjohnh nullfs_fhtovp, 33754754Sjohnh nullfs_vptofh, 33854754Sjohnh nullfs_init, 33954752Sjohnh }; 340