154752Sjohnh /* 263245Sbostic * Copyright (c) 1992, 1993 363245Sbostic * The Regents of the University of California. All rights reserved. 454752Sjohnh * 554752Sjohnh * This code is derived from software donated to Berkeley by 654752Sjohnh * Jan-Simon Pendry. 754752Sjohnh * 854752Sjohnh * %sccs.include.redist.c% 954752Sjohnh * 10*68427Smckusick * @(#)null_vfsops.c 8.3 (Berkeley) 02/23/95 1154752Sjohnh * 1254766Sjohnh * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 1354766Sjohnh * $Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $ 1454752Sjohnh */ 1554752Sjohnh 1654752Sjohnh /* 1754766Sjohnh * Null Layer 1854766Sjohnh * (See null_vnops.c for a description of what this does.) 1954752Sjohnh */ 2054752Sjohnh 2154752Sjohnh #include <sys/param.h> 2254752Sjohnh #include <sys/systm.h> 2354752Sjohnh #include <sys/time.h> 2454752Sjohnh #include <sys/types.h> 2554752Sjohnh #include <sys/vnode.h> 2654752Sjohnh #include <sys/mount.h> 2754752Sjohnh #include <sys/namei.h> 2854752Sjohnh #include <sys/malloc.h> 2955025Smckusick #include <miscfs/nullfs/null.h> 3054752Sjohnh 3154752Sjohnh /* 3254766Sjohnh * Mount null layer 3354752Sjohnh */ 3454893Sheideman int 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 int error = 0; 4354754Sjohnh struct null_args args; 4454766Sjohnh struct vnode *lowerrootvp, *vp; 4554754Sjohnh struct vnode *nullm_rootvp; 4654951Sheideman struct null_mount *xmp; 4754752Sjohnh u_int size; 4854752Sjohnh 4954754Sjohnh #ifdef NULLFS_DIAGNOSTIC 5054754Sjohnh printf("nullfs_mount(mp = %x)\n", mp); 5154752Sjohnh #endif 5254752Sjohnh 5354752Sjohnh /* 5454752Sjohnh * Update is a no-op 5554752Sjohnh */ 5654752Sjohnh if (mp->mnt_flag & MNT_UPDATE) { 5754752Sjohnh return (EOPNOTSUPP); 5854754Sjohnh /* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/ 5954752Sjohnh } 6054752Sjohnh 6154752Sjohnh /* 6254752Sjohnh * Get argument 6354752Sjohnh */ 6454754Sjohnh if (error = copyin(data, (caddr_t)&args, sizeof(struct null_args))) 6554752Sjohnh return (error); 6654752Sjohnh 6754752Sjohnh /* 6854938Sheideman * Find lower node 6954752Sjohnh */ 7054752Sjohnh NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF, 7154752Sjohnh UIO_USERSPACE, args.target, p); 7254752Sjohnh if (error = namei(ndp)) 7354752Sjohnh return (error); 7454752Sjohnh 7554752Sjohnh /* 7654938Sheideman * Sanity check on lower vnode 7754752Sjohnh */ 7854766Sjohnh lowerrootvp = ndp->ni_vp; 7954951Sheideman 8054752Sjohnh vrele(ndp->ni_dvp); 8154951Sheideman ndp->ni_dvp = NULL; 8254752Sjohnh 8354951Sheideman xmp = (struct null_mount *) malloc(sizeof(struct null_mount), 8454752Sjohnh M_UFSMNT, M_WAITOK); /* XXX */ 8554752Sjohnh 8654752Sjohnh /* 8754951Sheideman * Save reference to underlying FS 8854752Sjohnh */ 8954951Sheideman xmp->nullm_vfs = lowerrootvp->v_mount; 9054752Sjohnh 9154752Sjohnh /* 9254752Sjohnh * Save reference. Each mount also holds 9354752Sjohnh * a reference on the root vnode. 9454752Sjohnh */ 9554893Sheideman error = null_node_create(mp, lowerrootvp, &vp); 9654752Sjohnh /* 9754938Sheideman * Unlock the node (either the lower or the alias) 9854752Sjohnh */ 9954752Sjohnh VOP_UNLOCK(vp); 10054752Sjohnh /* 10154752Sjohnh * Make sure the node alias worked 10254752Sjohnh */ 10354752Sjohnh if (error) { 10454766Sjohnh vrele(lowerrootvp); 10554951Sheideman free(xmp, M_UFSMNT); /* XXX */ 10654752Sjohnh return (error); 10754752Sjohnh } 10854752Sjohnh 10954752Sjohnh /* 11054752Sjohnh * Keep a held reference to the root vnode. 11154754Sjohnh * It is vrele'd in nullfs_unmount. 11254752Sjohnh */ 11354754Sjohnh nullm_rootvp = vp; 11454754Sjohnh nullm_rootvp->v_flag |= VROOT; 11554951Sheideman xmp->nullm_rootvp = nullm_rootvp; 11654893Sheideman if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) 11754752Sjohnh mp->mnt_flag |= MNT_LOCAL; 11854951Sheideman mp->mnt_data = (qaddr_t) xmp; 11954752Sjohnh getnewfsid(mp, MOUNT_LOFS); 12054752Sjohnh 12154752Sjohnh (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 12254752Sjohnh bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 12354752Sjohnh (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 12454752Sjohnh &size); 12554752Sjohnh bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 12654754Sjohnh #ifdef NULLFS_DIAGNOSTIC 12754938Sheideman printf("nullfs_mount: lower %s, alias at %s\n", 12854752Sjohnh mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 12954752Sjohnh #endif 13054752Sjohnh return (0); 13154752Sjohnh } 13254752Sjohnh 13354752Sjohnh /* 13454752Sjohnh * VFS start. Nothing needed here - the start routine 13554752Sjohnh * on the underlying filesystem will have been called 13654752Sjohnh * when that filesystem was mounted. 13754752Sjohnh */ 13854893Sheideman int 13954754Sjohnh nullfs_start(mp, flags, p) 14054752Sjohnh struct mount *mp; 14154752Sjohnh int flags; 14254752Sjohnh struct proc *p; 14354752Sjohnh { 14454752Sjohnh return (0); 14554754Sjohnh /* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */ 14654752Sjohnh } 14754752Sjohnh 14854752Sjohnh /* 14954766Sjohnh * Free reference to null layer 15054752Sjohnh */ 15154893Sheideman int 15254754Sjohnh nullfs_unmount(mp, mntflags, p) 15354752Sjohnh struct mount *mp; 15454752Sjohnh int mntflags; 15554752Sjohnh struct proc *p; 15654752Sjohnh { 15754754Sjohnh struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 15854752Sjohnh int error; 15954752Sjohnh int flags = 0; 16054752Sjohnh extern int doforce; 16154752Sjohnh 16254754Sjohnh #ifdef NULLFS_DIAGNOSTIC 16354754Sjohnh printf("nullfs_unmount(mp = %x)\n", mp); 16454752Sjohnh #endif 16554752Sjohnh 16654752Sjohnh if (mntflags & MNT_FORCE) { 16754752Sjohnh /* lofs can never be rootfs so don't check for it */ 16854752Sjohnh if (!doforce) 16954752Sjohnh return (EINVAL); 17054752Sjohnh flags |= FORCECLOSE; 17154752Sjohnh } 17254752Sjohnh 17354752Sjohnh /* 17454752Sjohnh * Clear out buffer cache. I don't think we 17554752Sjohnh * ever get anything cached at this level at the 17654752Sjohnh * moment, but who knows... 17754752Sjohnh */ 17854893Sheideman #if 0 17954752Sjohnh mntflushbuf(mp, 0); 18054752Sjohnh if (mntinvalbuf(mp, 1)) 18154752Sjohnh return (EBUSY); 18254893Sheideman #endif 18354754Sjohnh if (nullm_rootvp->v_usecount > 1) 18454752Sjohnh return (EBUSY); 18554754Sjohnh if (error = vflush(mp, nullm_rootvp, flags)) 18654752Sjohnh return (error); 18754752Sjohnh 18854754Sjohnh #ifdef NULLFS_DIAGNOSTIC 18954938Sheideman vprint("alias root of lower", nullm_rootvp); 19054752Sjohnh #endif 19154752Sjohnh /* 19254752Sjohnh * Release reference on underlying root vnode 19354752Sjohnh */ 19454754Sjohnh vrele(nullm_rootvp); 19554752Sjohnh /* 19654752Sjohnh * And blow it away for future re-use 19754752Sjohnh */ 198*68427Smckusick VOP_REVOKE(nullm_rootvp, 0); 19954752Sjohnh /* 20054754Sjohnh * Finally, throw away the null_mount structure 20154752Sjohnh */ 20254752Sjohnh free(mp->mnt_data, M_UFSMNT); /* XXX */ 20354752Sjohnh mp->mnt_data = 0; 20454752Sjohnh return 0; 20554752Sjohnh } 20654752Sjohnh 20754893Sheideman int 20854754Sjohnh nullfs_root(mp, vpp) 20954752Sjohnh struct mount *mp; 21054752Sjohnh struct vnode **vpp; 21154752Sjohnh { 21254752Sjohnh struct vnode *vp; 21354752Sjohnh 21454754Sjohnh #ifdef NULLFS_DIAGNOSTIC 21554754Sjohnh printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp, 21654754Sjohnh MOUNTTONULLMOUNT(mp)->nullm_rootvp, 21754893Sheideman NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) 21854752Sjohnh ); 21954752Sjohnh #endif 22054752Sjohnh 22154752Sjohnh /* 22254752Sjohnh * Return locked reference to root. 22354752Sjohnh */ 22454754Sjohnh vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 22554752Sjohnh VREF(vp); 22654752Sjohnh VOP_LOCK(vp); 22754752Sjohnh *vpp = vp; 22854752Sjohnh return 0; 22954752Sjohnh } 23054752Sjohnh 23154893Sheideman int 23254754Sjohnh nullfs_quotactl(mp, cmd, uid, arg, p) 23354752Sjohnh struct mount *mp; 23454752Sjohnh int cmd; 23554752Sjohnh uid_t uid; 23654752Sjohnh caddr_t arg; 23754752Sjohnh struct proc *p; 23854752Sjohnh { 23954754Sjohnh return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p); 24054752Sjohnh } 24154752Sjohnh 24254893Sheideman int 24354754Sjohnh nullfs_statfs(mp, sbp, p) 24454752Sjohnh struct mount *mp; 24554752Sjohnh struct statfs *sbp; 24654752Sjohnh struct proc *p; 24754752Sjohnh { 24854752Sjohnh int error; 24954752Sjohnh struct statfs mstat; 25054752Sjohnh 25154754Sjohnh #ifdef NULLFS_DIAGNOSTIC 25254754Sjohnh printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp, 25354754Sjohnh MOUNTTONULLMOUNT(mp)->nullm_rootvp, 25454893Sheideman NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) 25554752Sjohnh ); 25654752Sjohnh #endif 25754752Sjohnh 25854752Sjohnh bzero(&mstat, sizeof(mstat)); 25954752Sjohnh 26054754Sjohnh error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p); 26154752Sjohnh if (error) 26254752Sjohnh return (error); 26354752Sjohnh 26454752Sjohnh /* now copy across the "interesting" information and fake the rest */ 26554752Sjohnh sbp->f_type = mstat.f_type; 26654752Sjohnh sbp->f_flags = mstat.f_flags; 26754752Sjohnh sbp->f_bsize = mstat.f_bsize; 26854752Sjohnh sbp->f_iosize = mstat.f_iosize; 26954752Sjohnh sbp->f_blocks = mstat.f_blocks; 27054752Sjohnh sbp->f_bfree = mstat.f_bfree; 27154752Sjohnh sbp->f_bavail = mstat.f_bavail; 27254752Sjohnh sbp->f_files = mstat.f_files; 27354752Sjohnh sbp->f_ffree = mstat.f_ffree; 27454752Sjohnh if (sbp != &mp->mnt_stat) { 27554752Sjohnh bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 27654752Sjohnh bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 27754752Sjohnh bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 27854752Sjohnh } 27954752Sjohnh return (0); 28054752Sjohnh } 28154752Sjohnh 28254893Sheideman int 28354893Sheideman nullfs_sync(mp, waitfor, cred, p) 28454893Sheideman struct mount *mp; 28554893Sheideman int waitfor; 28654893Sheideman struct ucred *cred; 28754893Sheideman struct proc *p; 28854752Sjohnh { 28954766Sjohnh /* 29054893Sheideman * XXX - Assumes no data cached at null layer. 29154766Sjohnh */ 29254752Sjohnh return (0); 29354752Sjohnh } 29454752Sjohnh 29554893Sheideman int 29654893Sheideman nullfs_vget(mp, ino, vpp) 29754752Sjohnh struct mount *mp; 29854893Sheideman ino_t ino; 29954752Sjohnh struct vnode **vpp; 30054752Sjohnh { 30154893Sheideman 30254893Sheideman return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp); 30354752Sjohnh } 30454752Sjohnh 30554893Sheideman int 30654893Sheideman nullfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp) 30754893Sheideman struct mount *mp; 30854893Sheideman struct fid *fidp; 30954893Sheideman struct mbuf *nam; 31054893Sheideman struct vnode **vpp; 31154893Sheideman int *exflagsp; 31254893Sheideman struct ucred**credanonp; 31354893Sheideman { 31454893Sheideman 31554893Sheideman return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, nam, vpp, exflagsp,credanonp); 31654893Sheideman } 31754893Sheideman 31854893Sheideman int 31954754Sjohnh nullfs_vptofh(vp, fhp) 32054752Sjohnh struct vnode *vp; 32154752Sjohnh struct fid *fhp; 32254752Sjohnh { 32354893Sheideman return VFS_VPTOFH(NULLVPTOLOWERVP(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, 33654893Sheideman nullfs_vget, 33754754Sjohnh nullfs_fhtovp, 33854754Sjohnh nullfs_vptofh, 33954754Sjohnh nullfs_init, 34054752Sjohnh }; 341