153841Spendry /*
263237Sbostic  * Copyright (c) 1992, 1993
363237Sbostic  *	The Regents of the University of California.  All rights reserved.
453841Spendry  *
553841Spendry  * This code is derived from software donated to Berkeley by
653841Spendry  * Jan-Simon Pendry.
753841Spendry  *
853841Spendry  * %sccs.include.redist.c%
953841Spendry  *
10*65803Sbostic  *	@(#)lofs_vfsops.c	8.3 (Berkeley) 01/21/94
1153841Spendry  *
1253841Spendry  * $Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $
1353841Spendry  */
1453841Spendry 
1553841Spendry /*
1653841Spendry  * Loopback Filesystem
1753841Spendry  */
1853841Spendry 
1953841Spendry #include <sys/param.h>
2053841Spendry #include <sys/systm.h>
2153841Spendry #include <sys/time.h>
2253841Spendry #include <sys/types.h>
2353841Spendry #include <sys/vnode.h>
2453841Spendry #include <sys/mount.h>
2553841Spendry #include <sys/namei.h>
2653841Spendry #include <sys/malloc.h>
2755022Smckusick #include <miscfs/lofs/lofs.h>
2853841Spendry 
2953841Spendry /*
3053841Spendry  * Mount loopback copy of existing name space
3153841Spendry  */
3265518Spendry int
lofs_mount(mp,path,data,ndp,p)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 	/*
4853841Spendry 	 * Update is a no-op
4953841Spendry 	 */
5065518Spendry 	if (mp->mnt_flag & MNT_UPDATE)
5153841Spendry 		return (EOPNOTSUPP);
5253841Spendry 
5353841Spendry 	/*
5453841Spendry 	 * Get argument
5553841Spendry 	 */
5653841Spendry 	if (error = copyin(data, (caddr_t)&args, sizeof(struct lofs_args)))
5753841Spendry 		return (error);
5853841Spendry 
5953841Spendry 	/*
6053841Spendry 	 * Find target node
6153841Spendry 	 */
6253841Spendry 	NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
6353841Spendry 		UIO_USERSPACE, args.target, p);
6453841Spendry 	if (error = namei(ndp))
6553841Spendry 		return (error);
6653841Spendry 
6753841Spendry 	/*
6853841Spendry 	 * Sanity check on target vnode
6953841Spendry 	 */
7053841Spendry 	vp = ndp->ni_vp;
7153841Spendry 	vrele(ndp->ni_dvp);
7253841Spendry 	ndp->ni_dvp = 0;
7353841Spendry 
7453841Spendry 	if (vp->v_type != VDIR) {
7553841Spendry 		vput(vp);
7653841Spendry 		return (EINVAL);
7753841Spendry 	}
7853841Spendry 
7953841Spendry 	amp = (struct lofsmount *) malloc(sizeof(struct lofsmount),
8053841Spendry 				M_UFSMNT, M_WAITOK);	/* XXX */
8153841Spendry 
8253841Spendry 	/*
8353841Spendry 	 * Save reference to underlying target FS
8453841Spendry 	 */
8553841Spendry 	amp->looped_vfs = vp->v_mount;
8653841Spendry 
8753841Spendry 	/*
8853841Spendry 	 * Save reference.  Each mount also holds
8953841Spendry 	 * a reference on the root vnode.
9053841Spendry 	 */
9153841Spendry 	error = make_lofs(mp, &vp);
9253841Spendry 	/*
9353841Spendry 	 * Unlock the node (either the target or the alias)
9453841Spendry 	 */
9553841Spendry 	VOP_UNLOCK(vp);
9653841Spendry 	/*
9753841Spendry 	 * Make sure the node alias worked
9853841Spendry 	 */
9953841Spendry 	if (error) {
10053841Spendry 		vrele(vp);
10153841Spendry 		free(amp, M_UFSMNT);	/* XXX */
10253841Spendry 		return (error);
10353841Spendry 	}
10453841Spendry 
10553841Spendry 	/*
10653841Spendry 	 * Keep a held reference to the root vnode.
10753841Spendry 	 * It is vrele'd in lofs_unmount.
10853841Spendry 	 */
10953841Spendry 	rootvp = vp;
11053841Spendry 	rootvp->v_flag |= VROOT;
11153841Spendry 	amp->rootvp = rootvp;
11253841Spendry 	if (LOFSVP(rootvp)->v_mount->mnt_flag & MNT_LOCAL)
11353841Spendry 		mp->mnt_flag |= MNT_LOCAL;
11453841Spendry 	mp->mnt_data = (qaddr_t) amp;
11553841Spendry 	getnewfsid(mp, MOUNT_LOFS);
11653841Spendry 
11753841Spendry 	(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
11853841Spendry 	bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
11953841Spendry 	(void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
12053841Spendry 	    &size);
12153841Spendry 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
12253841Spendry 	return (0);
12353841Spendry }
12453841Spendry 
12553841Spendry /*
12653841Spendry  * VFS start.  Nothing needed here - the start routine
12753841Spendry  * on the underlying filesystem will have been called
12853841Spendry  * when that filesystem was mounted.
12953841Spendry  */
13065518Spendry int
lofs_start(mp,flags,p)13153841Spendry lofs_start(mp, flags, p)
13253841Spendry 	struct mount *mp;
13353841Spendry 	int flags;
13453841Spendry 	struct proc *p;
13553841Spendry {
13665518Spendry 
13753841Spendry 	return (0);
13853841Spendry }
13953841Spendry 
14053841Spendry /*
14153841Spendry  * Free reference to looped FS
14253841Spendry  */
14365518Spendry int
lofs_unmount(mp,mntflags,p)14453841Spendry lofs_unmount(mp, mntflags, p)
14553841Spendry 	struct mount *mp;
14653841Spendry 	int mntflags;
14753841Spendry 	struct proc *p;
14853841Spendry {
14953841Spendry 	struct vnode *rootvp = VFSTOLOFS(mp)->rootvp;
15053841Spendry 	int error;
15153841Spendry 	int flags = 0;
15253841Spendry 	extern int doforce;
15353841Spendry 
15453841Spendry 	if (mntflags & MNT_FORCE) {
15553841Spendry 		/* lofs can never be rootfs so don't check for it */
15653841Spendry 		if (!doforce)
15753841Spendry 			return (EINVAL);
15853841Spendry 		flags |= FORCECLOSE;
15953841Spendry 	}
16053841Spendry 
16153841Spendry 	/*
16253841Spendry 	 * Clear out buffer cache.  I don't think we
16353841Spendry 	 * ever get anything cached at this level at the
16453841Spendry 	 * moment, but who knows...
16553841Spendry 	 */
16653841Spendry 	if (rootvp->v_usecount > 1)
16753841Spendry 		return (EBUSY);
16853841Spendry 	if (error = vflush(mp, rootvp, flags))
16953841Spendry 		return (error);
17053841Spendry 
17153841Spendry 	/*
17253841Spendry 	 * Release reference on underlying root vnode
17353841Spendry 	 */
17453841Spendry 	vrele(rootvp);
17553841Spendry 	/*
17653841Spendry 	 * And blow it away for future re-use
17753841Spendry 	 */
17853841Spendry 	vgone(rootvp);
17953841Spendry 	/*
18053841Spendry 	 * Finally, throw away the lofsmount structure
18153841Spendry 	 */
18253841Spendry 	free(mp->mnt_data, M_UFSMNT);	/* XXX */
18353841Spendry 	mp->mnt_data = 0;
18465518Spendry 	return (0);
18553841Spendry }
18653841Spendry 
18765518Spendry int
lofs_root(mp,vpp)18853841Spendry lofs_root(mp, vpp)
18953841Spendry 	struct mount *mp;
19053841Spendry 	struct vnode **vpp;
19153841Spendry {
19253841Spendry 	struct vnode *vp;
19353841Spendry 
19453841Spendry 	/*
19553841Spendry 	 * Return locked reference to root.
19653841Spendry 	 */
19753841Spendry 	vp = VFSTOLOFS(mp)->rootvp;
19853841Spendry 	VREF(vp);
19953841Spendry 	VOP_LOCK(vp);
20053841Spendry 	*vpp = vp;
20165518Spendry 	return (0);
20253841Spendry }
20353841Spendry 
20465518Spendry int
lofs_quotactl(mp,cmd,uid,arg,p)20553841Spendry lofs_quotactl(mp, cmd, uid, arg, p)
20653841Spendry 	struct mount *mp;
20753841Spendry 	int cmd;
20853841Spendry 	uid_t uid;
20953841Spendry 	caddr_t arg;
21053841Spendry 	struct proc *p;
21153841Spendry {
21265518Spendry 	return (VFS_QUOTACTL(VFSTOLOFS(mp)->looped_vfs, cmd, uid, arg, p));
21353841Spendry }
21453841Spendry 
21565518Spendry int
lofs_statfs(mp,sbp,p)21653841Spendry lofs_statfs(mp, sbp, p)
21753841Spendry 	struct mount *mp;
21853841Spendry 	struct statfs *sbp;
21953841Spendry 	struct proc *p;
22053841Spendry {
22153841Spendry 	int error;
22253841Spendry 	struct statfs mstat;
22353841Spendry 
22453841Spendry 	bzero(&mstat, sizeof(mstat));
22553841Spendry 
22653841Spendry 	error = VFS_STATFS(VFSTOLOFS(mp)->looped_vfs, &mstat, p);
22753841Spendry 	if (error)
22853841Spendry 		return (error);
22953841Spendry 
23053841Spendry 	/* now copy across the "interesting" information and fake the rest */
23153841Spendry 	sbp->f_type = mstat.f_type;
23253841Spendry 	sbp->f_flags = mstat.f_flags;
23353841Spendry 	sbp->f_bsize = mstat.f_bsize;
23453841Spendry 	sbp->f_iosize = mstat.f_iosize;
23553841Spendry 	sbp->f_blocks = mstat.f_blocks;
23653841Spendry 	sbp->f_bfree = mstat.f_bfree;
23753841Spendry 	sbp->f_bavail = mstat.f_bavail;
23853841Spendry 	sbp->f_files = mstat.f_files;
23953841Spendry 	sbp->f_ffree = mstat.f_ffree;
24053841Spendry 	if (sbp != &mp->mnt_stat) {
24153841Spendry 		bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
24253841Spendry 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
24353841Spendry 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
24453841Spendry 	}
24553841Spendry 	return (0);
24653841Spendry }
24753841Spendry 
24865518Spendry int
lofs_sync(mp,waitfor)24953841Spendry lofs_sync(mp, waitfor)
25053841Spendry struct mount *mp;
25153841Spendry int waitfor;
25253841Spendry {
25354051Spendry 	return (0);
25453841Spendry }
25553841Spendry 
25654982Spendry /*
25754982Spendry  * LOFS flat namespace lookup.
25854982Spendry  * Currently unsupported.
25954982Spendry  */
26065518Spendry int
lofs_vget(mp,ino,vpp)26154982Spendry lofs_vget(mp, ino, vpp)
26253841Spendry 	struct mount *mp;
26354982Spendry 	ino_t ino;
26454982Spendry 	struct vnode **vpp;
26554982Spendry {
26654982Spendry 
26754982Spendry 	return (EOPNOTSUPP);
26854982Spendry }
26954982Spendry 
27065518Spendry int
lofs_fhtovp(mp,fhp,nam,vpp,exflagsp,credanonp)27154982Spendry lofs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
27254982Spendry 	register struct mount *mp;
27353841Spendry 	struct fid *fhp;
27454982Spendry 	struct mbuf *nam;
27553841Spendry 	struct vnode **vpp;
27654982Spendry 	int *exflagsp;
27754982Spendry 	struct ucred **credanonp;
27853841Spendry {
27965518Spendry 	return (VFS_FHTOVP(VFSTOLOFS(mp)->looped_vfs, fhp, nam, vpp, exflagsp, credanonp));
28053841Spendry }
28153841Spendry 
28265518Spendry int
lofs_vptofh(vp,fhp)28353841Spendry lofs_vptofh(vp, fhp)
28453841Spendry 	struct vnode *vp;
28553841Spendry 	struct fid *fhp;
28653841Spendry {
28765518Spendry 	return (VFS_VPTOFH(LOFSVP(vp), fhp));
28853841Spendry }
28953841Spendry 
29053841Spendry struct vfsops lofs_vfsops = {
29153841Spendry 	lofs_mount,
29253841Spendry 	lofs_start,
29353841Spendry 	lofs_unmount,
29453841Spendry 	lofs_root,
29553841Spendry 	lofs_quotactl,
29653841Spendry 	lofs_statfs,
29753841Spendry 	lofs_sync,
29854982Spendry 	lofs_vget,
29953841Spendry 	lofs_fhtovp,
30053841Spendry 	lofs_vptofh,
30153841Spendry 	lofs_init,
30253841Spendry };
303