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*69337Smckusick * @(#)null_vfsops.c 8.5 (Berkeley) 05/10/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; 11968618Smckusick vfs_getnewfsid(mp); 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 16154754Sjohnh #ifdef NULLFS_DIAGNOSTIC 16254754Sjohnh printf("nullfs_unmount(mp = %x)\n", mp); 16354752Sjohnh #endif 16454752Sjohnh 165*69337Smckusick if (mntflags & MNT_FORCE) 16654752Sjohnh flags |= FORCECLOSE; 16754752Sjohnh 16854752Sjohnh /* 16954752Sjohnh * Clear out buffer cache. I don't think we 17054752Sjohnh * ever get anything cached at this level at the 17154752Sjohnh * moment, but who knows... 17254752Sjohnh */ 17354893Sheideman #if 0 17454752Sjohnh mntflushbuf(mp, 0); 17554752Sjohnh if (mntinvalbuf(mp, 1)) 17654752Sjohnh return (EBUSY); 17754893Sheideman #endif 17854754Sjohnh if (nullm_rootvp->v_usecount > 1) 17954752Sjohnh return (EBUSY); 18054754Sjohnh if (error = vflush(mp, nullm_rootvp, flags)) 18154752Sjohnh return (error); 18254752Sjohnh 18354754Sjohnh #ifdef NULLFS_DIAGNOSTIC 18454938Sheideman vprint("alias root of lower", nullm_rootvp); 18554752Sjohnh #endif 18654752Sjohnh /* 18754752Sjohnh * Release reference on underlying root vnode 18854752Sjohnh */ 18954754Sjohnh vrele(nullm_rootvp); 19054752Sjohnh /* 19154752Sjohnh * And blow it away for future re-use 19254752Sjohnh */ 19368427Smckusick VOP_REVOKE(nullm_rootvp, 0); 19454752Sjohnh /* 19554754Sjohnh * Finally, throw away the null_mount structure 19654752Sjohnh */ 19754752Sjohnh free(mp->mnt_data, M_UFSMNT); /* XXX */ 19854752Sjohnh mp->mnt_data = 0; 19954752Sjohnh return 0; 20054752Sjohnh } 20154752Sjohnh 20254893Sheideman int 20354754Sjohnh nullfs_root(mp, vpp) 20454752Sjohnh struct mount *mp; 20554752Sjohnh struct vnode **vpp; 20654752Sjohnh { 20754752Sjohnh struct vnode *vp; 20854752Sjohnh 20954754Sjohnh #ifdef NULLFS_DIAGNOSTIC 21054754Sjohnh printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp, 21154754Sjohnh MOUNTTONULLMOUNT(mp)->nullm_rootvp, 21254893Sheideman NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) 21354752Sjohnh ); 21454752Sjohnh #endif 21554752Sjohnh 21654752Sjohnh /* 21754752Sjohnh * Return locked reference to root. 21854752Sjohnh */ 21954754Sjohnh vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp; 22054752Sjohnh VREF(vp); 22154752Sjohnh VOP_LOCK(vp); 22254752Sjohnh *vpp = vp; 22354752Sjohnh return 0; 22454752Sjohnh } 22554752Sjohnh 22654893Sheideman int 22754754Sjohnh nullfs_quotactl(mp, cmd, uid, arg, p) 22854752Sjohnh struct mount *mp; 22954752Sjohnh int cmd; 23054752Sjohnh uid_t uid; 23154752Sjohnh caddr_t arg; 23254752Sjohnh struct proc *p; 23354752Sjohnh { 23454754Sjohnh return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p); 23554752Sjohnh } 23654752Sjohnh 23754893Sheideman int 23854754Sjohnh nullfs_statfs(mp, sbp, p) 23954752Sjohnh struct mount *mp; 24054752Sjohnh struct statfs *sbp; 24154752Sjohnh struct proc *p; 24254752Sjohnh { 24354752Sjohnh int error; 24454752Sjohnh struct statfs mstat; 24554752Sjohnh 24654754Sjohnh #ifdef NULLFS_DIAGNOSTIC 24754754Sjohnh printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp, 24854754Sjohnh MOUNTTONULLMOUNT(mp)->nullm_rootvp, 24954893Sheideman NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp) 25054752Sjohnh ); 25154752Sjohnh #endif 25254752Sjohnh 25354752Sjohnh bzero(&mstat, sizeof(mstat)); 25454752Sjohnh 25554754Sjohnh error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p); 25654752Sjohnh if (error) 25754752Sjohnh return (error); 25854752Sjohnh 25954752Sjohnh /* now copy across the "interesting" information and fake the rest */ 26054752Sjohnh sbp->f_type = mstat.f_type; 26154752Sjohnh sbp->f_flags = mstat.f_flags; 26254752Sjohnh sbp->f_bsize = mstat.f_bsize; 26354752Sjohnh sbp->f_iosize = mstat.f_iosize; 26454752Sjohnh sbp->f_blocks = mstat.f_blocks; 26554752Sjohnh sbp->f_bfree = mstat.f_bfree; 26654752Sjohnh sbp->f_bavail = mstat.f_bavail; 26754752Sjohnh sbp->f_files = mstat.f_files; 26854752Sjohnh sbp->f_ffree = mstat.f_ffree; 26954752Sjohnh if (sbp != &mp->mnt_stat) { 27054752Sjohnh bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 27154752Sjohnh bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 27254752Sjohnh bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 27354752Sjohnh } 27454752Sjohnh return (0); 27554752Sjohnh } 27654752Sjohnh 27754893Sheideman int 27854893Sheideman nullfs_sync(mp, waitfor, cred, p) 27954893Sheideman struct mount *mp; 28054893Sheideman int waitfor; 28154893Sheideman struct ucred *cred; 28254893Sheideman struct proc *p; 28354752Sjohnh { 28454766Sjohnh /* 28554893Sheideman * XXX - Assumes no data cached at null layer. 28654766Sjohnh */ 28754752Sjohnh return (0); 28854752Sjohnh } 28954752Sjohnh 29054893Sheideman int 29154893Sheideman nullfs_vget(mp, ino, vpp) 29254752Sjohnh struct mount *mp; 29354893Sheideman ino_t ino; 29454752Sjohnh struct vnode **vpp; 29554752Sjohnh { 29654893Sheideman 29754893Sheideman return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp); 29854752Sjohnh } 29954752Sjohnh 30054893Sheideman int 30154893Sheideman nullfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp) 30254893Sheideman struct mount *mp; 30354893Sheideman struct fid *fidp; 30454893Sheideman struct mbuf *nam; 30554893Sheideman struct vnode **vpp; 30654893Sheideman int *exflagsp; 30754893Sheideman struct ucred**credanonp; 30854893Sheideman { 30954893Sheideman 31054893Sheideman return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, nam, vpp, exflagsp,credanonp); 31154893Sheideman } 31254893Sheideman 31354893Sheideman int 31454754Sjohnh nullfs_vptofh(vp, fhp) 31554752Sjohnh struct vnode *vp; 31654752Sjohnh struct fid *fhp; 31754752Sjohnh { 31854893Sheideman return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp); 31954752Sjohnh } 32054752Sjohnh 32168618Smckusick int nullfs_init __P((struct vfsconf *)); 32254752Sjohnh 32368618Smckusick #define nullfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \ 32468618Smckusick size_t, struct proc *)))eopnotsupp) 32568618Smckusick 32654754Sjohnh struct vfsops null_vfsops = { 32754754Sjohnh nullfs_mount, 32854754Sjohnh nullfs_start, 32954754Sjohnh nullfs_unmount, 33054754Sjohnh nullfs_root, 33154754Sjohnh nullfs_quotactl, 33254754Sjohnh nullfs_statfs, 33354754Sjohnh nullfs_sync, 33454893Sheideman nullfs_vget, 33554754Sjohnh nullfs_fhtovp, 33654754Sjohnh nullfs_vptofh, 33754754Sjohnh nullfs_init, 33868618Smckusick nullfs_sysctl, 33954752Sjohnh }; 340