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