154752Sjohnh /*
254752Sjohnh  * Copyright (c) 1992 The Regents of the University of California
354752Sjohnh  * Copyright (c) 1990, 1992 Jan-Simon Pendry
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*54754Sjohnh  *	@(#)null_vfsops.c	1.2 (Berkeley) 6/18/92
1254752Sjohnh  *
13*54754Sjohnh  * $Id: null_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $
1454752Sjohnh  */
1554752Sjohnh 
1654752Sjohnh /*
17*54754Sjohnh  * Null layer Filesystem
1854752Sjohnh  */
1954752Sjohnh 
2054752Sjohnh #include <sys/param.h>
2154752Sjohnh #include <sys/systm.h>
2254752Sjohnh #include <sys/time.h>
2354752Sjohnh #include <sys/types.h>
2454752Sjohnh #include <sys/vnode.h>
2554752Sjohnh #include <sys/mount.h>
2654752Sjohnh #include <sys/namei.h>
2754752Sjohnh #include <sys/malloc.h>
2854752Sjohnh #include <lofs/lofs.h>
2954752Sjohnh 
3054752Sjohnh /*
3154752Sjohnh  * Mount loopback copy of existing name space
3254752Sjohnh  */
33*54754Sjohnh nullfs_mount(mp, path, data, ndp, p)
3454752Sjohnh 	struct mount *mp;
3554752Sjohnh 	char *path;
3654752Sjohnh 	caddr_t data;
3754752Sjohnh 	struct nameidata *ndp;
3854752Sjohnh 	struct proc *p;
3954752Sjohnh {
4054752Sjohnh 	USES_VOP_UNLOCK;
4154752Sjohnh 	int error = 0;
42*54754Sjohnh 	struct null_args args;
4354752Sjohnh 	struct vnode *vp;
44*54754Sjohnh 	struct vnode *nullm_rootvp;
45*54754Sjohnh 	struct null_mount *amp;
4654752Sjohnh 	u_int size;
4754752Sjohnh 
48*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
49*54754Sjohnh 	printf("nullfs_mount(mp = %x)\n", mp);
5054752Sjohnh #endif
5154752Sjohnh 
5254752Sjohnh 	/*
5354752Sjohnh 	 * Update is a no-op
5454752Sjohnh 	 */
5554752Sjohnh 	if (mp->mnt_flag & MNT_UPDATE) {
5654752Sjohnh 		return (EOPNOTSUPP);
57*54754Sjohnh 		/* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/
5854752Sjohnh 	}
5954752Sjohnh 
6054752Sjohnh 	/*
6154752Sjohnh 	 * Get argument
6254752Sjohnh 	 */
63*54754Sjohnh 	if (error = copyin(data, (caddr_t)&args, sizeof(struct null_args)))
6454752Sjohnh 		return (error);
6554752Sjohnh 
6654752Sjohnh 	/*
6754752Sjohnh 	 * Find target node
6854752Sjohnh 	 */
6954752Sjohnh 	NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
7054752Sjohnh 		UIO_USERSPACE, args.target, p);
7154752Sjohnh 	if (error = namei(ndp))
7254752Sjohnh 		return (error);
7354752Sjohnh 
7454752Sjohnh 	/*
7554752Sjohnh 	 * Sanity check on target vnode
7654752Sjohnh 	 */
7754752Sjohnh 	vp = ndp->ni_vp;
78*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
7954752Sjohnh 	printf("vp = %x, check for VDIR...\n", vp);
8054752Sjohnh #endif
8154752Sjohnh 	vrele(ndp->ni_dvp);
8254752Sjohnh 	ndp->ni_dvp = 0;
8354752Sjohnh 
8454752Sjohnh 	if (vp->v_type != VDIR) {
8554752Sjohnh 		vput(vp);
8654752Sjohnh 		return (EINVAL);
8754752Sjohnh 	}
8854752Sjohnh 
89*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
9054752Sjohnh 	printf("mp = %x\n", mp);
9154752Sjohnh #endif
9254752Sjohnh 
93*54754Sjohnh 	amp = (struct null_mount *) malloc(sizeof(struct null_mount),
9454752Sjohnh 				M_UFSMNT, M_WAITOK);	/* XXX */
9554752Sjohnh 
9654752Sjohnh 	/*
9754752Sjohnh 	 * Save reference to underlying target FS
9854752Sjohnh 	 */
99*54754Sjohnh 	amp->nullm_vfs = vp->v_mount;
10054752Sjohnh 
10154752Sjohnh 	/*
10254752Sjohnh 	 * Save reference.  Each mount also holds
10354752Sjohnh 	 * a reference on the root vnode.
10454752Sjohnh 	 */
105*54754Sjohnh 	error = make_null_node(mp, &vp);
10654752Sjohnh 	/*
10754752Sjohnh 	 * Unlock the node (either the target or the alias)
10854752Sjohnh 	 */
10954752Sjohnh 	VOP_UNLOCK(vp);
11054752Sjohnh 	/*
11154752Sjohnh 	 * Make sure the node alias worked
11254752Sjohnh 	 */
11354752Sjohnh 	if (error) {
11454752Sjohnh 		vrele(vp);
11554752Sjohnh 		free(amp, M_UFSMNT);	/* XXX */
11654752Sjohnh 		return (error);
11754752Sjohnh 	}
11854752Sjohnh 
11954752Sjohnh 	/*
12054752Sjohnh 	 * Keep a held reference to the root vnode.
121*54754Sjohnh 	 * It is vrele'd in nullfs_unmount.
12254752Sjohnh 	 */
123*54754Sjohnh 	nullm_rootvp = vp;
124*54754Sjohnh 	nullm_rootvp->v_flag |= VROOT;
125*54754Sjohnh 	amp->nullm_rootvp = nullm_rootvp;
126*54754Sjohnh 	if (NULLTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
12754752Sjohnh 		mp->mnt_flag |= MNT_LOCAL;
12854752Sjohnh 	mp->mnt_data = (qaddr_t) amp;
12954752Sjohnh 	getnewfsid(mp, MOUNT_LOFS);
13054752Sjohnh 
13154752Sjohnh 	(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
13254752Sjohnh 	bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
13354752Sjohnh 	(void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
13454752Sjohnh 	    &size);
13554752Sjohnh 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
136*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
137*54754Sjohnh 	printf("nullfs_mount: target %s, alias at %s\n",
13854752Sjohnh 		mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
13954752Sjohnh #endif
14054752Sjohnh 	return (0);
14154752Sjohnh }
14254752Sjohnh 
14354752Sjohnh /*
14454752Sjohnh  * VFS start.  Nothing needed here - the start routine
14554752Sjohnh  * on the underlying filesystem will have been called
14654752Sjohnh  * when that filesystem was mounted.
14754752Sjohnh  */
148*54754Sjohnh nullfs_start(mp, flags, p)
14954752Sjohnh 	struct mount *mp;
15054752Sjohnh 	int flags;
15154752Sjohnh 	struct proc *p;
15254752Sjohnh {
15354752Sjohnh 	return (0);
154*54754Sjohnh 	/* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */
15554752Sjohnh }
15654752Sjohnh 
15754752Sjohnh /*
15854752Sjohnh  * Free reference to looped FS
15954752Sjohnh  */
160*54754Sjohnh nullfs_unmount(mp, mntflags, p)
16154752Sjohnh 	struct mount *mp;
16254752Sjohnh 	int mntflags;
16354752Sjohnh 	struct proc *p;
16454752Sjohnh {
165*54754Sjohnh 	struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
16654752Sjohnh 	int error;
16754752Sjohnh 	int flags = 0;
16854752Sjohnh 	extern int doforce;
16954752Sjohnh 
170*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
171*54754Sjohnh 	printf("nullfs_unmount(mp = %x)\n", mp);
17254752Sjohnh #endif
17354752Sjohnh 
17454752Sjohnh 	if (mntflags & MNT_FORCE) {
17554752Sjohnh 		/* lofs can never be rootfs so don't check for it */
17654752Sjohnh 		if (!doforce)
17754752Sjohnh 			return (EINVAL);
17854752Sjohnh 		flags |= FORCECLOSE;
17954752Sjohnh 	}
18054752Sjohnh 
18154752Sjohnh 	/*
18254752Sjohnh 	 * Clear out buffer cache.  I don't think we
18354752Sjohnh 	 * ever get anything cached at this level at the
18454752Sjohnh 	 * moment, but who knows...
18554752Sjohnh 	 */
18654752Sjohnh 	mntflushbuf(mp, 0);
18754752Sjohnh 	if (mntinvalbuf(mp, 1))
18854752Sjohnh 		return (EBUSY);
189*54754Sjohnh 	if (nullm_rootvp->v_usecount > 1)
19054752Sjohnh 		return (EBUSY);
191*54754Sjohnh 	if (error = vflush(mp, nullm_rootvp, flags))
19254752Sjohnh 		return (error);
19354752Sjohnh 
194*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
19554752Sjohnh 	/*
19654752Sjohnh 	 * Flush any remaining vnode references
19754752Sjohnh 	 */
198*54754Sjohnh 	null_node_flushmp (mp);
19954752Sjohnh #endif
20054752Sjohnh 
201*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
202*54754Sjohnh 	vprint("alias root of target", nullm_rootvp);
20354752Sjohnh #endif
20454752Sjohnh 	/*
20554752Sjohnh 	 * Release reference on underlying root vnode
20654752Sjohnh 	 */
207*54754Sjohnh 	vrele(nullm_rootvp);
20854752Sjohnh 	/*
20954752Sjohnh 	 * And blow it away for future re-use
21054752Sjohnh 	 */
211*54754Sjohnh 	vgone(nullm_rootvp);
21254752Sjohnh 	/*
213*54754Sjohnh 	 * Finally, throw away the null_mount structure
21454752Sjohnh 	 */
21554752Sjohnh 	free(mp->mnt_data, M_UFSMNT);	/* XXX */
21654752Sjohnh 	mp->mnt_data = 0;
21754752Sjohnh 	return 0;
21854752Sjohnh }
21954752Sjohnh 
220*54754Sjohnh nullfs_root(mp, vpp)
22154752Sjohnh 	struct mount *mp;
22254752Sjohnh 	struct vnode **vpp;
22354752Sjohnh {
22454752Sjohnh 	USES_VOP_LOCK;
22554752Sjohnh 	struct vnode *vp;
22654752Sjohnh 
227*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
228*54754Sjohnh 	printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp,
229*54754Sjohnh 			MOUNTTONULLMOUNT(mp)->nullm_rootvp,
230*54754Sjohnh 			NULLTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
23154752Sjohnh 			);
23254752Sjohnh #endif
23354752Sjohnh 
23454752Sjohnh 	/*
23554752Sjohnh 	 * Return locked reference to root.
23654752Sjohnh 	 */
237*54754Sjohnh 	vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
23854752Sjohnh 	VREF(vp);
23954752Sjohnh 	VOP_LOCK(vp);
24054752Sjohnh 	*vpp = vp;
24154752Sjohnh 	return 0;
24254752Sjohnh }
24354752Sjohnh 
244*54754Sjohnh nullfs_quotactl(mp, cmd, uid, arg, p)
24554752Sjohnh 	struct mount *mp;
24654752Sjohnh 	int cmd;
24754752Sjohnh 	uid_t uid;
24854752Sjohnh 	caddr_t arg;
24954752Sjohnh 	struct proc *p;
25054752Sjohnh {
251*54754Sjohnh 	return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p);
25254752Sjohnh }
25354752Sjohnh 
254*54754Sjohnh nullfs_statfs(mp, sbp, p)
25554752Sjohnh 	struct mount *mp;
25654752Sjohnh 	struct statfs *sbp;
25754752Sjohnh 	struct proc *p;
25854752Sjohnh {
25954752Sjohnh 	int error;
26054752Sjohnh 	struct statfs mstat;
26154752Sjohnh 
262*54754Sjohnh #ifdef NULLFS_DIAGNOSTIC
263*54754Sjohnh 	printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp,
264*54754Sjohnh 			MOUNTTONULLMOUNT(mp)->nullm_rootvp,
265*54754Sjohnh 			NULLTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
26654752Sjohnh 			);
26754752Sjohnh #endif
26854752Sjohnh 
26954752Sjohnh 	bzero(&mstat, sizeof(mstat));
27054752Sjohnh 
271*54754Sjohnh 	error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p);
27254752Sjohnh 	if (error)
27354752Sjohnh 		return (error);
27454752Sjohnh 
27554752Sjohnh 	/* now copy across the "interesting" information and fake the rest */
27654752Sjohnh 	sbp->f_type = mstat.f_type;
27754752Sjohnh 	sbp->f_flags = mstat.f_flags;
27854752Sjohnh 	sbp->f_bsize = mstat.f_bsize;
27954752Sjohnh 	sbp->f_iosize = mstat.f_iosize;
28054752Sjohnh 	sbp->f_blocks = mstat.f_blocks;
28154752Sjohnh 	sbp->f_bfree = mstat.f_bfree;
28254752Sjohnh 	sbp->f_bavail = mstat.f_bavail;
28354752Sjohnh 	sbp->f_files = mstat.f_files;
28454752Sjohnh 	sbp->f_ffree = mstat.f_ffree;
28554752Sjohnh 	if (sbp != &mp->mnt_stat) {
28654752Sjohnh 		bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
28754752Sjohnh 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
28854752Sjohnh 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
28954752Sjohnh 	}
29054752Sjohnh 	return (0);
29154752Sjohnh }
29254752Sjohnh 
293*54754Sjohnh nullfs_sync(mp, waitfor)
29454752Sjohnh struct mount *mp;
29554752Sjohnh int waitfor;
29654752Sjohnh {
29754752Sjohnh 	return (0);
29854752Sjohnh }
29954752Sjohnh 
300*54754Sjohnh nullfs_fhtovp(mp, fhp, setgen, vpp)
30154752Sjohnh 	struct mount *mp;
30254752Sjohnh 	struct fid *fhp;
30354752Sjohnh 	int setgen;
30454752Sjohnh 	struct vnode **vpp;
30554752Sjohnh {
306*54754Sjohnh 	return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fhp, setgen, vpp);
30754752Sjohnh }
30854752Sjohnh 
309*54754Sjohnh nullfs_vptofh(vp, fhp)
31054752Sjohnh 	struct vnode *vp;
31154752Sjohnh 	struct fid *fhp;
31254752Sjohnh {
313*54754Sjohnh 	return VFS_VPTOFH(NULLTOLOWERVP(vp), fhp);
31454752Sjohnh }
31554752Sjohnh 
316*54754Sjohnh int nullfs_init __P((void));
31754752Sjohnh 
318*54754Sjohnh struct vfsops null_vfsops = {
319*54754Sjohnh 	nullfs_mount,
320*54754Sjohnh 	nullfs_start,
321*54754Sjohnh 	nullfs_unmount,
322*54754Sjohnh 	nullfs_root,
323*54754Sjohnh 	nullfs_quotactl,
324*54754Sjohnh 	nullfs_statfs,
325*54754Sjohnh 	nullfs_sync,
326*54754Sjohnh 	nullfs_fhtovp,
327*54754Sjohnh 	nullfs_vptofh,
328*54754Sjohnh 	nullfs_init,
32954752Sjohnh };
330