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*54893Sheideman  *	@(#)null_vfsops.c	1.4 (Berkeley) 07/10/92
1254752Sjohnh  *
1354766Sjohnh  * @(#)lofs_vfsops.c	1.2 (Berkeley) 6/18/92
1454766Sjohnh  * $Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $
1554752Sjohnh  */
1654752Sjohnh 
1754752Sjohnh /*
1854766Sjohnh  * Null Layer
1954766Sjohnh  * (See null_vnops.c for a description of what this does.)
2054752Sjohnh  */
2154752Sjohnh 
2254752Sjohnh #include <sys/param.h>
2354752Sjohnh #include <sys/systm.h>
2454752Sjohnh #include <sys/time.h>
2554752Sjohnh #include <sys/types.h>
2654752Sjohnh #include <sys/vnode.h>
2754752Sjohnh #include <sys/mount.h>
2854752Sjohnh #include <sys/namei.h>
2954752Sjohnh #include <sys/malloc.h>
30*54893Sheideman #include <nullfs/null.h>
3154752Sjohnh 
3254752Sjohnh /*
3354766Sjohnh  * Mount null layer
3454752Sjohnh  */
35*54893Sheideman int
3654754Sjohnh nullfs_mount(mp, path, data, ndp, p)
3754752Sjohnh 	struct mount *mp;
3854752Sjohnh 	char *path;
3954752Sjohnh 	caddr_t data;
4054752Sjohnh 	struct nameidata *ndp;
4154752Sjohnh 	struct proc *p;
4254752Sjohnh {
4354752Sjohnh 	int error = 0;
4454754Sjohnh 	struct null_args args;
4554766Sjohnh 	struct vnode *lowerrootvp, *vp;
4654754Sjohnh 	struct vnode *nullm_rootvp;
4754754Sjohnh 	struct null_mount *amp;
4854752Sjohnh 	u_int size;
4954752Sjohnh 
5054754Sjohnh #ifdef NULLFS_DIAGNOSTIC
5154754Sjohnh 	printf("nullfs_mount(mp = %x)\n", mp);
5254752Sjohnh #endif
5354752Sjohnh 
5454752Sjohnh 	/*
5554752Sjohnh 	 * Update is a no-op
5654752Sjohnh 	 */
5754752Sjohnh 	if (mp->mnt_flag & MNT_UPDATE) {
5854752Sjohnh 		return (EOPNOTSUPP);
5954754Sjohnh 		/* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/
6054752Sjohnh 	}
6154752Sjohnh 
6254752Sjohnh 	/*
6354752Sjohnh 	 * Get argument
6454752Sjohnh 	 */
6554754Sjohnh 	if (error = copyin(data, (caddr_t)&args, sizeof(struct null_args)))
6654752Sjohnh 		return (error);
6754752Sjohnh 
6854752Sjohnh 	/*
6954752Sjohnh 	 * Find target node
7054752Sjohnh 	 */
7154752Sjohnh 	NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
7254752Sjohnh 		UIO_USERSPACE, args.target, p);
7354752Sjohnh 	if (error = namei(ndp))
7454752Sjohnh 		return (error);
7554752Sjohnh 
7654752Sjohnh 	/*
7754752Sjohnh 	 * Sanity check on target vnode
7854752Sjohnh 	 */
7954766Sjohnh 	lowerrootvp = ndp->ni_vp;
8054754Sjohnh #ifdef NULLFS_DIAGNOSTIC
8154766Sjohnh 	printf("vp = %x, check for VDIR...\n", lowerrootvp);
8254752Sjohnh #endif
8354752Sjohnh 	vrele(ndp->ni_dvp);
8454752Sjohnh 	ndp->ni_dvp = 0;
8554752Sjohnh 
8654766Sjohnh 	/*
8754766Sjohnh 	 * NEEDSWORK: Is this really bad, or just not
8854766Sjohnh 	 * the way it's been?
8954766Sjohnh 	 */
9054766Sjohnh 	if (lowerrootvp->v_type != VDIR) {
9154766Sjohnh 		vput(lowerrootvp);
9254752Sjohnh 		return (EINVAL);
9354752Sjohnh 	}
9454752Sjohnh 
9554754Sjohnh #ifdef NULLFS_DIAGNOSTIC
9654752Sjohnh 	printf("mp = %x\n", mp);
9754752Sjohnh #endif
9854752Sjohnh 
9954754Sjohnh 	amp = (struct null_mount *) malloc(sizeof(struct null_mount),
10054752Sjohnh 				M_UFSMNT, M_WAITOK);	/* XXX */
10154752Sjohnh 
10254752Sjohnh 	/*
10354752Sjohnh 	 * Save reference to underlying target FS
10454752Sjohnh 	 */
10554766Sjohnh 	amp->nullm_vfs = lowerrootvp->v_mount;
10654752Sjohnh 
10754752Sjohnh 	/*
10854752Sjohnh 	 * Save reference.  Each mount also holds
10954752Sjohnh 	 * a reference on the root vnode.
11054752Sjohnh 	 */
111*54893Sheideman 	error = null_node_create(mp, lowerrootvp, &vp);
11254752Sjohnh 	/*
11354752Sjohnh 	 * Unlock the node (either the target or the alias)
11454752Sjohnh 	 */
11554752Sjohnh 	VOP_UNLOCK(vp);
11654752Sjohnh 	/*
11754752Sjohnh 	 * Make sure the node alias worked
11854752Sjohnh 	 */
11954752Sjohnh 	if (error) {
12054766Sjohnh 		vrele(lowerrootvp);
12154752Sjohnh 		free(amp, M_UFSMNT);	/* XXX */
12254752Sjohnh 		return (error);
12354752Sjohnh 	}
12454752Sjohnh 
12554752Sjohnh 	/*
12654752Sjohnh 	 * Keep a held reference to the root vnode.
12754754Sjohnh 	 * It is vrele'd in nullfs_unmount.
12854752Sjohnh 	 */
12954754Sjohnh 	nullm_rootvp = vp;
13054754Sjohnh 	nullm_rootvp->v_flag |= VROOT;
13154754Sjohnh 	amp->nullm_rootvp = nullm_rootvp;
132*54893Sheideman 	if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
13354752Sjohnh 		mp->mnt_flag |= MNT_LOCAL;
13454752Sjohnh 	mp->mnt_data = (qaddr_t) amp;
13554752Sjohnh 	getnewfsid(mp, MOUNT_LOFS);
13654752Sjohnh 
13754752Sjohnh 	(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
13854752Sjohnh 	bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
13954752Sjohnh 	(void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
14054752Sjohnh 	    &size);
14154752Sjohnh 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
14254754Sjohnh #ifdef NULLFS_DIAGNOSTIC
14354754Sjohnh 	printf("nullfs_mount: target %s, alias at %s\n",
14454752Sjohnh 		mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
14554752Sjohnh #endif
14654752Sjohnh 	return (0);
14754752Sjohnh }
14854752Sjohnh 
14954752Sjohnh /*
15054752Sjohnh  * VFS start.  Nothing needed here - the start routine
15154752Sjohnh  * on the underlying filesystem will have been called
15254752Sjohnh  * when that filesystem was mounted.
15354752Sjohnh  */
154*54893Sheideman int
15554754Sjohnh nullfs_start(mp, flags, p)
15654752Sjohnh 	struct mount *mp;
15754752Sjohnh 	int flags;
15854752Sjohnh 	struct proc *p;
15954752Sjohnh {
16054752Sjohnh 	return (0);
16154754Sjohnh 	/* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */
16254752Sjohnh }
16354752Sjohnh 
16454752Sjohnh /*
16554766Sjohnh  * Free reference to null layer
16654752Sjohnh  */
167*54893Sheideman int
16854754Sjohnh nullfs_unmount(mp, mntflags, p)
16954752Sjohnh 	struct mount *mp;
17054752Sjohnh 	int mntflags;
17154752Sjohnh 	struct proc *p;
17254752Sjohnh {
17354754Sjohnh 	struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
17454752Sjohnh 	int error;
17554752Sjohnh 	int flags = 0;
17654752Sjohnh 	extern int doforce;
17754752Sjohnh 
17854754Sjohnh #ifdef NULLFS_DIAGNOSTIC
17954754Sjohnh 	printf("nullfs_unmount(mp = %x)\n", mp);
18054752Sjohnh #endif
18154752Sjohnh 
18254752Sjohnh 	if (mntflags & MNT_FORCE) {
18354752Sjohnh 		/* lofs can never be rootfs so don't check for it */
18454752Sjohnh 		if (!doforce)
18554752Sjohnh 			return (EINVAL);
18654752Sjohnh 		flags |= FORCECLOSE;
18754752Sjohnh 	}
18854752Sjohnh 
18954752Sjohnh 	/*
19054752Sjohnh 	 * Clear out buffer cache.  I don't think we
19154752Sjohnh 	 * ever get anything cached at this level at the
19254752Sjohnh 	 * moment, but who knows...
19354752Sjohnh 	 */
194*54893Sheideman #if 0
19554752Sjohnh 	mntflushbuf(mp, 0);
19654752Sjohnh 	if (mntinvalbuf(mp, 1))
19754752Sjohnh 		return (EBUSY);
198*54893Sheideman #endif
19954754Sjohnh 	if (nullm_rootvp->v_usecount > 1)
20054752Sjohnh 		return (EBUSY);
20154754Sjohnh 	if (error = vflush(mp, nullm_rootvp, flags))
20254752Sjohnh 		return (error);
20354752Sjohnh 
20454754Sjohnh #ifdef NULLFS_DIAGNOSTIC
20554752Sjohnh 	/*
20654752Sjohnh 	 * Flush any remaining vnode references
20754752Sjohnh 	 */
20854754Sjohnh 	null_node_flushmp (mp);
20954752Sjohnh #endif
21054752Sjohnh 
21154754Sjohnh #ifdef NULLFS_DIAGNOSTIC
21254754Sjohnh 	vprint("alias root of target", nullm_rootvp);
21354752Sjohnh #endif
21454752Sjohnh 	/*
21554752Sjohnh 	 * Release reference on underlying root vnode
21654752Sjohnh 	 */
21754754Sjohnh 	vrele(nullm_rootvp);
21854752Sjohnh 	/*
21954752Sjohnh 	 * And blow it away for future re-use
22054752Sjohnh 	 */
22154754Sjohnh 	vgone(nullm_rootvp);
22254752Sjohnh 	/*
22354754Sjohnh 	 * Finally, throw away the null_mount structure
22454752Sjohnh 	 */
22554752Sjohnh 	free(mp->mnt_data, M_UFSMNT);	/* XXX */
22654752Sjohnh 	mp->mnt_data = 0;
22754752Sjohnh 	return 0;
22854752Sjohnh }
22954752Sjohnh 
230*54893Sheideman int
23154754Sjohnh nullfs_root(mp, vpp)
23254752Sjohnh 	struct mount *mp;
23354752Sjohnh 	struct vnode **vpp;
23454752Sjohnh {
23554752Sjohnh 	struct vnode *vp;
23654752Sjohnh 
23754754Sjohnh #ifdef NULLFS_DIAGNOSTIC
23854754Sjohnh 	printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp,
23954754Sjohnh 			MOUNTTONULLMOUNT(mp)->nullm_rootvp,
240*54893Sheideman 			NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
24154752Sjohnh 			);
24254752Sjohnh #endif
24354752Sjohnh 
24454752Sjohnh 	/*
24554752Sjohnh 	 * Return locked reference to root.
24654752Sjohnh 	 */
24754754Sjohnh 	vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
24854752Sjohnh 	VREF(vp);
24954752Sjohnh 	VOP_LOCK(vp);
25054752Sjohnh 	*vpp = vp;
25154752Sjohnh 	return 0;
25254752Sjohnh }
25354752Sjohnh 
254*54893Sheideman int
25554754Sjohnh nullfs_quotactl(mp, cmd, uid, arg, p)
25654752Sjohnh 	struct mount *mp;
25754752Sjohnh 	int cmd;
25854752Sjohnh 	uid_t uid;
25954752Sjohnh 	caddr_t arg;
26054752Sjohnh 	struct proc *p;
26154752Sjohnh {
26254754Sjohnh 	return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p);
26354752Sjohnh }
26454752Sjohnh 
265*54893Sheideman int
26654754Sjohnh nullfs_statfs(mp, sbp, p)
26754752Sjohnh 	struct mount *mp;
26854752Sjohnh 	struct statfs *sbp;
26954752Sjohnh 	struct proc *p;
27054752Sjohnh {
27154752Sjohnh 	int error;
27254752Sjohnh 	struct statfs mstat;
27354752Sjohnh 
27454754Sjohnh #ifdef NULLFS_DIAGNOSTIC
27554754Sjohnh 	printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp,
27654754Sjohnh 			MOUNTTONULLMOUNT(mp)->nullm_rootvp,
277*54893Sheideman 			NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
27854752Sjohnh 			);
27954752Sjohnh #endif
28054752Sjohnh 
28154752Sjohnh 	bzero(&mstat, sizeof(mstat));
28254752Sjohnh 
28354754Sjohnh 	error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p);
28454752Sjohnh 	if (error)
28554752Sjohnh 		return (error);
28654752Sjohnh 
28754752Sjohnh 	/* now copy across the "interesting" information and fake the rest */
28854752Sjohnh 	sbp->f_type = mstat.f_type;
28954752Sjohnh 	sbp->f_flags = mstat.f_flags;
29054752Sjohnh 	sbp->f_bsize = mstat.f_bsize;
29154752Sjohnh 	sbp->f_iosize = mstat.f_iosize;
29254752Sjohnh 	sbp->f_blocks = mstat.f_blocks;
29354752Sjohnh 	sbp->f_bfree = mstat.f_bfree;
29454752Sjohnh 	sbp->f_bavail = mstat.f_bavail;
29554752Sjohnh 	sbp->f_files = mstat.f_files;
29654752Sjohnh 	sbp->f_ffree = mstat.f_ffree;
29754752Sjohnh 	if (sbp != &mp->mnt_stat) {
29854752Sjohnh 		bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
29954752Sjohnh 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
30054752Sjohnh 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
30154752Sjohnh 	}
30254752Sjohnh 	return (0);
30354752Sjohnh }
30454752Sjohnh 
305*54893Sheideman int
306*54893Sheideman nullfs_sync(mp, waitfor, cred, p)
307*54893Sheideman 	struct mount *mp;
308*54893Sheideman 	int waitfor;
309*54893Sheideman 	struct ucred *cred;
310*54893Sheideman 	struct proc *p;
31154752Sjohnh {
31254766Sjohnh 	/*
313*54893Sheideman 	 * XXX - Assumes no data cached at null layer.
31454766Sjohnh 	 */
31554752Sjohnh 	return (0);
31654752Sjohnh }
31754752Sjohnh 
318*54893Sheideman int
319*54893Sheideman nullfs_vget(mp, ino, vpp)
32054752Sjohnh 	struct mount *mp;
321*54893Sheideman 	ino_t ino;
32254752Sjohnh 	struct vnode **vpp;
32354752Sjohnh {
324*54893Sheideman 
325*54893Sheideman 	return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp);
32654752Sjohnh }
32754752Sjohnh 
328*54893Sheideman int
329*54893Sheideman nullfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp)
330*54893Sheideman 	struct mount *mp;
331*54893Sheideman 	struct fid *fidp;
332*54893Sheideman 	struct mbuf *nam;
333*54893Sheideman 	struct vnode **vpp;
334*54893Sheideman 	int *exflagsp;
335*54893Sheideman 	struct ucred**credanonp;
336*54893Sheideman {
337*54893Sheideman 
338*54893Sheideman 	return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, nam, vpp, exflagsp,credanonp);
339*54893Sheideman }
340*54893Sheideman 
341*54893Sheideman int
34254754Sjohnh nullfs_vptofh(vp, fhp)
34354752Sjohnh 	struct vnode *vp;
34454752Sjohnh 	struct fid *fhp;
34554752Sjohnh {
346*54893Sheideman 	return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp);
34754752Sjohnh }
34854752Sjohnh 
34954754Sjohnh int nullfs_init __P((void));
35054752Sjohnh 
35154754Sjohnh struct vfsops null_vfsops = {
35254754Sjohnh 	nullfs_mount,
35354754Sjohnh 	nullfs_start,
35454754Sjohnh 	nullfs_unmount,
35554754Sjohnh 	nullfs_root,
35654754Sjohnh 	nullfs_quotactl,
35754754Sjohnh 	nullfs_statfs,
35854754Sjohnh 	nullfs_sync,
359*54893Sheideman 	nullfs_vget,
36054754Sjohnh 	nullfs_fhtovp,
36154754Sjohnh 	nullfs_vptofh,
36254754Sjohnh 	nullfs_init,
36354752Sjohnh };
364