153841Spendry /* 2*63237Sbostic * Copyright (c) 1992, 1993 3*63237Sbostic * The Regents of the University of California. All rights reserved. 453841Spendry * All rights reserved. 553841Spendry * 653841Spendry * This code is derived from software donated to Berkeley by 753841Spendry * Jan-Simon Pendry. 853841Spendry * 953841Spendry * %sccs.include.redist.c% 1053841Spendry * 11*63237Sbostic * @(#)lofs_vfsops.c 8.1 (Berkeley) 06/10/93 1253841Spendry * 1353841Spendry * $Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $ 1453841Spendry */ 1553841Spendry 1653841Spendry /* 1753841Spendry * Loopback Filesystem 1853841Spendry */ 1953841Spendry 2053841Spendry #include <sys/param.h> 2153841Spendry #include <sys/systm.h> 2253841Spendry #include <sys/time.h> 2353841Spendry #include <sys/types.h> 2453841Spendry #include <sys/vnode.h> 2553841Spendry #include <sys/mount.h> 2653841Spendry #include <sys/namei.h> 2753841Spendry #include <sys/malloc.h> 2855022Smckusick #include <miscfs/lofs/lofs.h> 2953841Spendry 3053841Spendry /* 3153841Spendry * Mount loopback copy of existing name space 3253841Spendry */ 3353841Spendry lofs_mount(mp, path, data, ndp, p) 3453841Spendry struct mount *mp; 3553841Spendry char *path; 3653841Spendry caddr_t data; 3753841Spendry struct nameidata *ndp; 3853841Spendry struct proc *p; 3953841Spendry { 4053841Spendry int error = 0; 4153841Spendry struct lofs_args args; 4253841Spendry struct vnode *vp; 4353841Spendry struct vnode *rootvp; 4453841Spendry struct lofsmount *amp; 4553841Spendry u_int size; 4653841Spendry 4753841Spendry #ifdef LOFS_DIAGNOSTIC 4853841Spendry printf("lofs_mount(mp = %x)\n", mp); 4953841Spendry #endif 5053841Spendry 5153841Spendry /* 5253841Spendry * Update is a no-op 5353841Spendry */ 5453841Spendry if (mp->mnt_flag & MNT_UPDATE) { 5553841Spendry return (EOPNOTSUPP); 5653841Spendry /* return VFS_MOUNT(VFSTOLOFS(mp)->looped_vfs, path, data, ndp, p);*/ 5753841Spendry } 5853841Spendry 5953841Spendry /* 6053841Spendry * Get argument 6153841Spendry */ 6253841Spendry if (error = copyin(data, (caddr_t)&args, sizeof(struct lofs_args))) 6353841Spendry return (error); 6453841Spendry 6553841Spendry /* 6653841Spendry * Find target node 6753841Spendry */ 6853841Spendry NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF, 6953841Spendry UIO_USERSPACE, args.target, p); 7053841Spendry if (error = namei(ndp)) 7153841Spendry return (error); 7253841Spendry 7353841Spendry /* 7453841Spendry * Sanity check on target vnode 7553841Spendry */ 7653841Spendry vp = ndp->ni_vp; 7753841Spendry #ifdef LOFS_DIAGNOSTIC 7853841Spendry printf("vp = %x, check for VDIR...\n", vp); 7953841Spendry #endif 8053841Spendry vrele(ndp->ni_dvp); 8153841Spendry ndp->ni_dvp = 0; 8253841Spendry 8353841Spendry if (vp->v_type != VDIR) { 8453841Spendry vput(vp); 8553841Spendry return (EINVAL); 8653841Spendry } 8753841Spendry 8853841Spendry #ifdef LOFS_DIAGNOSTIC 8953841Spendry printf("mp = %x\n", mp); 9053841Spendry #endif 9153841Spendry 9253841Spendry amp = (struct lofsmount *) malloc(sizeof(struct lofsmount), 9353841Spendry M_UFSMNT, M_WAITOK); /* XXX */ 9453841Spendry 9553841Spendry /* 9653841Spendry * Save reference to underlying target FS 9753841Spendry */ 9853841Spendry amp->looped_vfs = vp->v_mount; 9953841Spendry 10053841Spendry /* 10153841Spendry * Save reference. Each mount also holds 10253841Spendry * a reference on the root vnode. 10353841Spendry */ 10453841Spendry error = make_lofs(mp, &vp); 10553841Spendry /* 10653841Spendry * Unlock the node (either the target or the alias) 10753841Spendry */ 10853841Spendry VOP_UNLOCK(vp); 10953841Spendry /* 11053841Spendry * Make sure the node alias worked 11153841Spendry */ 11253841Spendry if (error) { 11353841Spendry vrele(vp); 11453841Spendry free(amp, M_UFSMNT); /* XXX */ 11553841Spendry return (error); 11653841Spendry } 11753841Spendry 11853841Spendry /* 11953841Spendry * Keep a held reference to the root vnode. 12053841Spendry * It is vrele'd in lofs_unmount. 12153841Spendry */ 12253841Spendry rootvp = vp; 12353841Spendry rootvp->v_flag |= VROOT; 12453841Spendry amp->rootvp = rootvp; 12553841Spendry if (LOFSVP(rootvp)->v_mount->mnt_flag & MNT_LOCAL) 12653841Spendry mp->mnt_flag |= MNT_LOCAL; 12753841Spendry mp->mnt_data = (qaddr_t) amp; 12853841Spendry getnewfsid(mp, MOUNT_LOFS); 12953841Spendry 13053841Spendry (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 13153841Spendry bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 13253841Spendry (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 13353841Spendry &size); 13453841Spendry bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 13553841Spendry #ifdef LOFS_DIAGNOSTIC 13653841Spendry printf("lofs_mount: target %s, alias at %s\n", 13753841Spendry mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); 13853841Spendry #endif 13953841Spendry return (0); 14053841Spendry } 14153841Spendry 14253841Spendry /* 14353841Spendry * VFS start. Nothing needed here - the start routine 14453841Spendry * on the underlying filesystem will have been called 14553841Spendry * when that filesystem was mounted. 14653841Spendry */ 14753841Spendry lofs_start(mp, flags, p) 14853841Spendry struct mount *mp; 14953841Spendry int flags; 15053841Spendry struct proc *p; 15153841Spendry { 15253841Spendry return (0); 15353841Spendry /* return VFS_START(VFSTOLOFS(mp)->looped_vfs, flags, p); */ 15453841Spendry } 15553841Spendry 15653841Spendry /* 15753841Spendry * Free reference to looped FS 15853841Spendry */ 15953841Spendry lofs_unmount(mp, mntflags, p) 16053841Spendry struct mount *mp; 16153841Spendry int mntflags; 16253841Spendry struct proc *p; 16353841Spendry { 16453841Spendry struct vnode *rootvp = VFSTOLOFS(mp)->rootvp; 16553841Spendry int error; 16653841Spendry int flags = 0; 16753841Spendry extern int doforce; 16853841Spendry 16953841Spendry #ifdef LOFS_DIAGNOSTIC 17053841Spendry printf("lofs_unmount(mp = %x)\n", mp); 17153841Spendry #endif 17253841Spendry 17353841Spendry if (mntflags & MNT_FORCE) { 17453841Spendry /* lofs can never be rootfs so don't check for it */ 17553841Spendry if (!doforce) 17653841Spendry return (EINVAL); 17753841Spendry flags |= FORCECLOSE; 17853841Spendry } 17953841Spendry 18053841Spendry /* 18153841Spendry * Clear out buffer cache. I don't think we 18253841Spendry * ever get anything cached at this level at the 18353841Spendry * moment, but who knows... 18453841Spendry */ 18553841Spendry if (rootvp->v_usecount > 1) 18653841Spendry return (EBUSY); 18753841Spendry if (error = vflush(mp, rootvp, flags)) 18853841Spendry return (error); 18953841Spendry 19053841Spendry #ifdef LOFS_DIAGNOSTIC 19153841Spendry /* 19253841Spendry * Flush any remaining vnode references 19353841Spendry */ 19453841Spendry lofs_flushmp(mp); 19553841Spendry #endif 19653841Spendry 19753841Spendry #ifdef LOFS_DIAGNOSTIC 19853841Spendry vprint("alias root of target", rootvp); 19953841Spendry #endif 20053841Spendry /* 20153841Spendry * Release reference on underlying root vnode 20253841Spendry */ 20353841Spendry vrele(rootvp); 20453841Spendry /* 20553841Spendry * And blow it away for future re-use 20653841Spendry */ 20753841Spendry vgone(rootvp); 20853841Spendry /* 20953841Spendry * Finally, throw away the lofsmount structure 21053841Spendry */ 21153841Spendry free(mp->mnt_data, M_UFSMNT); /* XXX */ 21253841Spendry mp->mnt_data = 0; 21353841Spendry return 0; 21453841Spendry } 21553841Spendry 21653841Spendry lofs_root(mp, vpp) 21753841Spendry struct mount *mp; 21853841Spendry struct vnode **vpp; 21953841Spendry { 22053841Spendry struct vnode *vp; 22153841Spendry 22253841Spendry #ifdef LOFS_DIAGNOSTIC 22353841Spendry printf("lofs_root(mp = %x, vp = %x->%x)\n", mp, 22453841Spendry VFSTOLOFS(mp)->rootvp, 22553841Spendry LOFSVP(VFSTOLOFS(mp)->rootvp) 22653841Spendry ); 22753841Spendry #endif 22853841Spendry 22953841Spendry /* 23053841Spendry * Return locked reference to root. 23153841Spendry */ 23253841Spendry vp = VFSTOLOFS(mp)->rootvp; 23353841Spendry VREF(vp); 23453841Spendry VOP_LOCK(vp); 23553841Spendry *vpp = vp; 23653841Spendry return 0; 23753841Spendry } 23853841Spendry 23953841Spendry lofs_quotactl(mp, cmd, uid, arg, p) 24053841Spendry struct mount *mp; 24153841Spendry int cmd; 24253841Spendry uid_t uid; 24353841Spendry caddr_t arg; 24453841Spendry struct proc *p; 24553841Spendry { 24653841Spendry return VFS_QUOTACTL(VFSTOLOFS(mp)->looped_vfs, cmd, uid, arg, p); 24753841Spendry } 24853841Spendry 24953841Spendry lofs_statfs(mp, sbp, p) 25053841Spendry struct mount *mp; 25153841Spendry struct statfs *sbp; 25253841Spendry struct proc *p; 25353841Spendry { 25453841Spendry int error; 25553841Spendry struct statfs mstat; 25653841Spendry 25753841Spendry #ifdef LOFS_DIAGNOSTIC 25853841Spendry printf("lofs_statfs(mp = %x, vp = %x->%x)\n", mp, 25953841Spendry VFSTOLOFS(mp)->rootvp, 26053841Spendry LOFSVP(VFSTOLOFS(mp)->rootvp) 26153841Spendry ); 26253841Spendry #endif 26353841Spendry 26453841Spendry bzero(&mstat, sizeof(mstat)); 26553841Spendry 26653841Spendry error = VFS_STATFS(VFSTOLOFS(mp)->looped_vfs, &mstat, p); 26753841Spendry if (error) 26853841Spendry return (error); 26953841Spendry 27053841Spendry /* now copy across the "interesting" information and fake the rest */ 27153841Spendry sbp->f_type = mstat.f_type; 27253841Spendry sbp->f_flags = mstat.f_flags; 27353841Spendry sbp->f_bsize = mstat.f_bsize; 27453841Spendry sbp->f_iosize = mstat.f_iosize; 27553841Spendry sbp->f_blocks = mstat.f_blocks; 27653841Spendry sbp->f_bfree = mstat.f_bfree; 27753841Spendry sbp->f_bavail = mstat.f_bavail; 27853841Spendry sbp->f_files = mstat.f_files; 27953841Spendry sbp->f_ffree = mstat.f_ffree; 28053841Spendry if (sbp != &mp->mnt_stat) { 28153841Spendry bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid)); 28253841Spendry bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 28353841Spendry bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 28453841Spendry } 28553841Spendry return (0); 28653841Spendry } 28753841Spendry 28853841Spendry lofs_sync(mp, waitfor) 28953841Spendry struct mount *mp; 29053841Spendry int waitfor; 29153841Spendry { 29254051Spendry return (0); 29353841Spendry } 29453841Spendry 29554982Spendry /* 29654982Spendry * LOFS flat namespace lookup. 29754982Spendry * Currently unsupported. 29854982Spendry */ 29954982Spendry lofs_vget(mp, ino, vpp) 30053841Spendry struct mount *mp; 30154982Spendry ino_t ino; 30254982Spendry struct vnode **vpp; 30354982Spendry { 30454982Spendry 30554982Spendry return (EOPNOTSUPP); 30654982Spendry } 30754982Spendry 30854982Spendry lofs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 30954982Spendry register struct mount *mp; 31053841Spendry struct fid *fhp; 31154982Spendry struct mbuf *nam; 31253841Spendry struct vnode **vpp; 31354982Spendry int *exflagsp; 31454982Spendry struct ucred **credanonp; 31553841Spendry { 31654982Spendry return VFS_FHTOVP(VFSTOLOFS(mp)->looped_vfs, fhp, nam, vpp, exflagsp, credanonp); 31753841Spendry } 31853841Spendry 31953841Spendry lofs_vptofh(vp, fhp) 32053841Spendry struct vnode *vp; 32153841Spendry struct fid *fhp; 32253841Spendry { 32353841Spendry return VFS_VPTOFH(LOFSVP(vp), fhp); 32453841Spendry } 32553841Spendry 32653841Spendry int lofs_init __P((void)); 32753841Spendry 32853841Spendry struct vfsops lofs_vfsops = { 32953841Spendry lofs_mount, 33053841Spendry lofs_start, 33153841Spendry lofs_unmount, 33253841Spendry lofs_root, 33353841Spendry lofs_quotactl, 33453841Spendry lofs_statfs, 33553841Spendry lofs_sync, 33654982Spendry lofs_vget, 33753841Spendry lofs_fhtovp, 33853841Spendry lofs_vptofh, 33953841Spendry lofs_init, 34053841Spendry }; 341