154752Sjohnh /* 2*63245Sbostic * Copyright (c) 1992, 1993 3*63245Sbostic * The Regents of the University of California. All rights reserved. 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*63245Sbostic * @(#)null_vfsops.c 8.1 (Berkeley) 06/10/93 1254752Sjohnh * 1354766Sjohnh * @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92 1454766Sjohnh * $Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $ 1554752Sjohnh */ 1654752Sjohnh 1754752Sjohnh /* 1854766Sjohnh * Null Layer 1954766Sjohnh * (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> 3055025Smckusick #include <miscfs/nullfs/null.h> 3154752Sjohnh 3254752Sjohnh /* 3354766Sjohnh * Mount null layer 3454752Sjohnh */ 3554893Sheideman int 3654754Sjohnh nullfs_mount(mp, path, data, ndp, p) 3754752Sjohnh struct mount *mp; 3854752Sjohnh char *path; 3954752Sjohnh caddr_t data; 4054752Sjohnh struct nameidata *ndp; 4154752Sjohnh struct proc *p; 4254752Sjohnh { 4354752Sjohnh int error = 0; 4454754Sjohnh struct null_args args; 4554766Sjohnh struct vnode *lowerrootvp, *vp; 4654754Sjohnh struct vnode *nullm_rootvp; 4754951Sheideman struct null_mount *xmp; 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 /* 6954938Sheideman * Find lower 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 /* 7754938Sheideman * Sanity check on lower vnode 7854752Sjohnh */ 7954766Sjohnh lowerrootvp = ndp->ni_vp; 8054951Sheideman 8154752Sjohnh vrele(ndp->ni_dvp); 8254951Sheideman ndp->ni_dvp = NULL; 8354752Sjohnh 8454951Sheideman xmp = (struct null_mount *) malloc(sizeof(struct null_mount), 8554752Sjohnh M_UFSMNT, M_WAITOK); /* XXX */ 8654752Sjohnh 8754752Sjohnh /* 8854951Sheideman * Save reference to underlying FS 8954752Sjohnh */ 9054951Sheideman xmp->nullm_vfs = lowerrootvp->v_mount; 9154752Sjohnh 9254752Sjohnh /* 9354752Sjohnh * Save reference. Each mount also holds 9454752Sjohnh * a reference on the root vnode. 9554752Sjohnh */ 9654893Sheideman error = null_node_create(mp, lowerrootvp, &vp); 9754752Sjohnh /* 9854938Sheideman * Unlock the node (either the lower or the alias) 9954752Sjohnh */ 10054752Sjohnh VOP_UNLOCK(vp); 10154752Sjohnh /* 10254752Sjohnh * Make sure the node alias worked 10354752Sjohnh */ 10454752Sjohnh if (error) { 10554766Sjohnh vrele(lowerrootvp); 10654951Sheideman free(xmp, M_UFSMNT); /* XXX */ 10754752Sjohnh return (error); 10854752Sjohnh } 10954752Sjohnh 11054752Sjohnh /* 11154752Sjohnh * Keep a held reference to the root vnode. 11254754Sjohnh * It is vrele'd in nullfs_unmount. 11354752Sjohnh */ 11454754Sjohnh nullm_rootvp = vp; 11554754Sjohnh nullm_rootvp->v_flag |= VROOT; 11654951Sheideman xmp->nullm_rootvp = nullm_rootvp; 11754893Sheideman if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL) 11854752Sjohnh mp->mnt_flag |= MNT_LOCAL; 11954951Sheideman mp->mnt_data = (qaddr_t) xmp; 12054752Sjohnh getnewfsid(mp, MOUNT_LOFS); 12154752Sjohnh 12254752Sjohnh (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 12354752Sjohnh bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 12454752Sjohnh (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 12554752Sjohnh &size); 12654752Sjohnh bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 12754754Sjohnh #ifdef NULLFS_DIAGNOSTIC 12854938Sheideman printf("nullfs_mount: lower %s, alias at %s\n", 12954752Sjohnh mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 13054752Sjohnh #endif 13154752Sjohnh return (0); 13254752Sjohnh } 13354752Sjohnh 13454752Sjohnh /* 13554752Sjohnh * VFS start. Nothing needed here - the start routine 13654752Sjohnh * on the underlying filesystem will have been called 13754752Sjohnh * when that filesystem was mounted. 13854752Sjohnh */ 13954893Sheideman int 14054754Sjohnh nullfs_start(mp, flags, p) 14154752Sjohnh struct mount *mp; 14254752Sjohnh int flags; 14354752Sjohnh struct proc *p; 14454752Sjohnh { 14554752Sjohnh return (0); 14654754Sjohnh /* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */ 14754752Sjohnh } 14854752Sjohnh 14954752Sjohnh /* 15054766Sjohnh * Free reference to null layer 15154752Sjohnh */ 15254893Sheideman int 15354754Sjohnh nullfs_unmount(mp, mntflags, p) 15454752Sjohnh struct mount *mp; 15554752Sjohnh int mntflags; 15654752Sjohnh struct proc *p; 15754752Sjohnh { 15854754Sjohnh struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 15954752Sjohnh int error; 16054752Sjohnh int flags = 0; 16154752Sjohnh extern int doforce; 16254752Sjohnh 16354754Sjohnh #ifdef NULLFS_DIAGNOSTIC 16454754Sjohnh printf("nullfs_unmount(mp = %x)\n", mp); 16554752Sjohnh #endif 16654752Sjohnh 16754752Sjohnh if (mntflags & MNT_FORCE) { 16854752Sjohnh /* lofs can never be rootfs so don't check for it */ 16954752Sjohnh if (!doforce) 17054752Sjohnh return (EINVAL); 17154752Sjohnh flags |= FORCECLOSE; 17254752Sjohnh } 17354752Sjohnh 17454752Sjohnh /* 17554752Sjohnh * Clear out buffer cache. I don't think we 17654752Sjohnh * ever get anything cached at this level at the 17754752Sjohnh * moment, but who knows... 17854752Sjohnh */ 17954893Sheideman #if 0 18054752Sjohnh mntflushbuf(mp, 0); 18154752Sjohnh if (mntinvalbuf(mp, 1)) 18254752Sjohnh return (EBUSY); 18354893Sheideman #endif 18454754Sjohnh if (nullm_rootvp->v_usecount > 1) 18554752Sjohnh return (EBUSY); 18654754Sjohnh if (error = vflush(mp, nullm_rootvp, flags)) 18754752Sjohnh return (error); 18854752Sjohnh 18954754Sjohnh #ifdef NULLFS_DIAGNOSTIC 19054938Sheideman vprint("alias root of lower", nullm_rootvp); 19154752Sjohnh #endif 19254752Sjohnh /* 19354752Sjohnh * Release reference on underlying root vnode 19454752Sjohnh */ 19554754Sjohnh vrele(nullm_rootvp); 19654752Sjohnh /* 19754752Sjohnh * And blow it away for future re-use 19854752Sjohnh */ 19954754Sjohnh vgone(nullm_rootvp); 20054752Sjohnh /* 20154754Sjohnh * Finally, throw away the null_mount structure 20254752Sjohnh */ 20354752Sjohnh free(mp->mnt_data, M_UFSMNT); /* XXX */ 20454752Sjohnh mp->mnt_data = 0; 20554752Sjohnh return 0; 20654752Sjohnh } 20754752Sjohnh 20854893Sheideman int 20954754Sjohnh nullfs_root(mp, vpp) 21054752Sjohnh struct mount *mp; 21154752Sjohnh struct vnode **vpp; 21254752Sjohnh { 21354752Sjohnh struct vnode *vp; 21454752Sjohnh 21554754Sjohnh #ifdef NULLFS_DIAGNOSTIC 21654754Sjohnh printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp, 21754754Sjohnh MOUNTTONULLMOUNT(mp)->nullm_rootvp, 21854893Sheideman NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) 21954752Sjohnh ); 22054752Sjohnh #endif 22154752Sjohnh 22254752Sjohnh /* 22354752Sjohnh * Return locked reference to root. 22454752Sjohnh */ 22554754Sjohnh vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 22654752Sjohnh VREF(vp); 22754752Sjohnh VOP_LOCK(vp); 22854752Sjohnh *vpp = vp; 22954752Sjohnh return 0; 23054752Sjohnh } 23154752Sjohnh 23254893Sheideman int 23354754Sjohnh nullfs_quotactl(mp, cmd, uid, arg, p) 23454752Sjohnh struct mount *mp; 23554752Sjohnh int cmd; 23654752Sjohnh uid_t uid; 23754752Sjohnh caddr_t arg; 23854752Sjohnh struct proc *p; 23954752Sjohnh { 24054754Sjohnh return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p); 24154752Sjohnh } 24254752Sjohnh 24354893Sheideman int 24454754Sjohnh nullfs_statfs(mp, sbp, p) 24554752Sjohnh struct mount *mp; 24654752Sjohnh struct statfs *sbp; 24754752Sjohnh struct proc *p; 24854752Sjohnh { 24954752Sjohnh int error; 25054752Sjohnh struct statfs mstat; 25154752Sjohnh 25254754Sjohnh #ifdef NULLFS_DIAGNOSTIC 25354754Sjohnh printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp, 25454754Sjohnh MOUNTTONULLMOUNT(mp)->nullm_rootvp, 25554893Sheideman NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) 25654752Sjohnh ); 25754752Sjohnh #endif 25854752Sjohnh 25954752Sjohnh bzero(&mstat, sizeof(mstat)); 26054752Sjohnh 26154754Sjohnh error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p); 26254752Sjohnh if (error) 26354752Sjohnh return (error); 26454752Sjohnh 26554752Sjohnh /* now copy across the "interesting" information and fake the rest */ 26654752Sjohnh sbp->f_type = mstat.f_type; 26754752Sjohnh sbp->f_flags = mstat.f_flags; 26854752Sjohnh sbp->f_bsize = mstat.f_bsize; 26954752Sjohnh sbp->f_iosize = mstat.f_iosize; 27054752Sjohnh sbp->f_blocks = mstat.f_blocks; 27154752Sjohnh sbp->f_bfree = mstat.f_bfree; 27254752Sjohnh sbp->f_bavail = mstat.f_bavail; 27354752Sjohnh sbp->f_files = mstat.f_files; 27454752Sjohnh sbp->f_ffree = mstat.f_ffree; 27554752Sjohnh if (sbp != &mp->mnt_stat) { 27654752Sjohnh bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 27754752Sjohnh bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 27854752Sjohnh bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 27954752Sjohnh } 28054752Sjohnh return (0); 28154752Sjohnh } 28254752Sjohnh 28354893Sheideman int 28454893Sheideman nullfs_sync(mp, waitfor, cred, p) 28554893Sheideman struct mount *mp; 28654893Sheideman int waitfor; 28754893Sheideman struct ucred *cred; 28854893Sheideman struct proc *p; 28954752Sjohnh { 29054766Sjohnh /* 29154893Sheideman * XXX - Assumes no data cached at null layer. 29254766Sjohnh */ 29354752Sjohnh return (0); 29454752Sjohnh } 29554752Sjohnh 29654893Sheideman int 29754893Sheideman nullfs_vget(mp, ino, vpp) 29854752Sjohnh struct mount *mp; 29954893Sheideman ino_t ino; 30054752Sjohnh struct vnode **vpp; 30154752Sjohnh { 30254893Sheideman 30354893Sheideman return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp); 30454752Sjohnh } 30554752Sjohnh 30654893Sheideman int 30754893Sheideman nullfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp) 30854893Sheideman struct mount *mp; 30954893Sheideman struct fid *fidp; 31054893Sheideman struct mbuf *nam; 31154893Sheideman struct vnode **vpp; 31254893Sheideman int *exflagsp; 31354893Sheideman struct ucred**credanonp; 31454893Sheideman { 31554893Sheideman 31654893Sheideman return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, nam, vpp, exflagsp,credanonp); 31754893Sheideman } 31854893Sheideman 31954893Sheideman int 32054754Sjohnh nullfs_vptofh(vp, fhp) 32154752Sjohnh struct vnode *vp; 32254752Sjohnh struct fid *fhp; 32354752Sjohnh { 32454893Sheideman return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp); 32554752Sjohnh } 32654752Sjohnh 32754754Sjohnh int nullfs_init __P((void)); 32854752Sjohnh 32954754Sjohnh struct vfsops null_vfsops = { 33054754Sjohnh nullfs_mount, 33154754Sjohnh nullfs_start, 33254754Sjohnh nullfs_unmount, 33354754Sjohnh nullfs_root, 33454754Sjohnh nullfs_quotactl, 33554754Sjohnh nullfs_statfs, 33654754Sjohnh nullfs_sync, 33754893Sheideman nullfs_vget, 33854754Sjohnh nullfs_fhtovp, 33954754Sjohnh nullfs_vptofh, 34054754Sjohnh nullfs_init, 34154752Sjohnh }; 342