154752Sjohnh /*
263245Sbostic  * Copyright (c) 1992, 1993
363245Sbostic  *	The Regents of the University of California.  All rights reserved.
454752Sjohnh  *
554752Sjohnh  * This code is derived from software donated to Berkeley by
654752Sjohnh  * Jan-Simon Pendry.
754752Sjohnh  *
854752Sjohnh  * %sccs.include.redist.c%
954752Sjohnh  *
10*68618Smckusick  *	@(#)null_vfsops.c	8.4 (Berkeley) 03/29/95
1154752Sjohnh  *
1254766Sjohnh  * @(#)lofs_vfsops.c	1.2 (Berkeley) 6/18/92
1354766Sjohnh  * $Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp jsp $
1454752Sjohnh  */
1554752Sjohnh 
1654752Sjohnh /*
1754766Sjohnh  * Null Layer
1854766Sjohnh  * (See null_vnops.c for a description of what this does.)
1954752Sjohnh  */
2054752Sjohnh 
2154752Sjohnh #include <sys/param.h>
2254752Sjohnh #include <sys/systm.h>
2354752Sjohnh #include <sys/time.h>
2454752Sjohnh #include <sys/types.h>
2554752Sjohnh #include <sys/vnode.h>
2654752Sjohnh #include <sys/mount.h>
2754752Sjohnh #include <sys/namei.h>
2854752Sjohnh #include <sys/malloc.h>
2955025Smckusick #include <miscfs/nullfs/null.h>
3054752Sjohnh 
3154752Sjohnh /*
3254766Sjohnh  * Mount null layer
3354752Sjohnh  */
3454893Sheideman int
3554754Sjohnh nullfs_mount(mp, path, data, ndp, p)
3654752Sjohnh 	struct mount *mp;
3754752Sjohnh 	char *path;
3854752Sjohnh 	caddr_t data;
3954752Sjohnh 	struct nameidata *ndp;
4054752Sjohnh 	struct proc *p;
4154752Sjohnh {
4254752Sjohnh 	int error = 0;
4354754Sjohnh 	struct null_args args;
4454766Sjohnh 	struct vnode *lowerrootvp, *vp;
4554754Sjohnh 	struct vnode *nullm_rootvp;
4654951Sheideman 	struct null_mount *xmp;
4754752Sjohnh 	u_int size;
4854752Sjohnh 
4954754Sjohnh #ifdef NULLFS_DIAGNOSTIC
5054754Sjohnh 	printf("nullfs_mount(mp = %x)\n", mp);
5154752Sjohnh #endif
5254752Sjohnh 
5354752Sjohnh 	/*
5454752Sjohnh 	 * Update is a no-op
5554752Sjohnh 	 */
5654752Sjohnh 	if (mp->mnt_flag & MNT_UPDATE) {
5754752Sjohnh 		return (EOPNOTSUPP);
5854754Sjohnh 		/* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/
5954752Sjohnh 	}
6054752Sjohnh 
6154752Sjohnh 	/*
6254752Sjohnh 	 * Get argument
6354752Sjohnh 	 */
6454754Sjohnh 	if (error = copyin(data, (caddr_t)&args, sizeof(struct null_args)))
6554752Sjohnh 		return (error);
6654752Sjohnh 
6754752Sjohnh 	/*
6854938Sheideman 	 * Find lower node
6954752Sjohnh 	 */
7054752Sjohnh 	NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
7154752Sjohnh 		UIO_USERSPACE, args.target, p);
7254752Sjohnh 	if (error = namei(ndp))
7354752Sjohnh 		return (error);
7454752Sjohnh 
7554752Sjohnh 	/*
7654938Sheideman 	 * Sanity check on lower vnode
7754752Sjohnh 	 */
7854766Sjohnh 	lowerrootvp = ndp->ni_vp;
7954951Sheideman 
8054752Sjohnh 	vrele(ndp->ni_dvp);
8154951Sheideman 	ndp->ni_dvp = NULL;
8254752Sjohnh 
8354951Sheideman 	xmp = (struct null_mount *) malloc(sizeof(struct null_mount),
8454752Sjohnh 				M_UFSMNT, M_WAITOK);	/* XXX */
8554752Sjohnh 
8654752Sjohnh 	/*
8754951Sheideman 	 * Save reference to underlying FS
8854752Sjohnh 	 */
8954951Sheideman 	xmp->nullm_vfs = lowerrootvp->v_mount;
9054752Sjohnh 
9154752Sjohnh 	/*
9254752Sjohnh 	 * Save reference.  Each mount also holds
9354752Sjohnh 	 * a reference on the root vnode.
9454752Sjohnh 	 */
9554893Sheideman 	error = null_node_create(mp, lowerrootvp, &vp);
9654752Sjohnh 	/*
9754938Sheideman 	 * Unlock the node (either the lower or the alias)
9854752Sjohnh 	 */
9954752Sjohnh 	VOP_UNLOCK(vp);
10054752Sjohnh 	/*
10154752Sjohnh 	 * Make sure the node alias worked
10254752Sjohnh 	 */
10354752Sjohnh 	if (error) {
10454766Sjohnh 		vrele(lowerrootvp);
10554951Sheideman 		free(xmp, M_UFSMNT);	/* XXX */
10654752Sjohnh 		return (error);
10754752Sjohnh 	}
10854752Sjohnh 
10954752Sjohnh 	/*
11054752Sjohnh 	 * Keep a held reference to the root vnode.
11154754Sjohnh 	 * It is vrele'd in nullfs_unmount.
11254752Sjohnh 	 */
11354754Sjohnh 	nullm_rootvp = vp;
11454754Sjohnh 	nullm_rootvp->v_flag |= VROOT;
11554951Sheideman 	xmp->nullm_rootvp = nullm_rootvp;
11654893Sheideman 	if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
11754752Sjohnh 		mp->mnt_flag |= MNT_LOCAL;
11854951Sheideman 	mp->mnt_data = (qaddr_t) xmp;
119*68618Smckusick 	vfs_getnewfsid(mp);
12054752Sjohnh 
12154752Sjohnh 	(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
12254752Sjohnh 	bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
12354752Sjohnh 	(void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
12454752Sjohnh 	    &size);
12554752Sjohnh 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
12654754Sjohnh #ifdef NULLFS_DIAGNOSTIC
12754938Sheideman 	printf("nullfs_mount: lower %s, alias at %s\n",
12854752Sjohnh 		mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
12954752Sjohnh #endif
13054752Sjohnh 	return (0);
13154752Sjohnh }
13254752Sjohnh 
13354752Sjohnh /*
13454752Sjohnh  * VFS start.  Nothing needed here - the start routine
13554752Sjohnh  * on the underlying filesystem will have been called
13654752Sjohnh  * when that filesystem was mounted.
13754752Sjohnh  */
13854893Sheideman int
13954754Sjohnh nullfs_start(mp, flags, p)
14054752Sjohnh 	struct mount *mp;
14154752Sjohnh 	int flags;
14254752Sjohnh 	struct proc *p;
14354752Sjohnh {
14454752Sjohnh 	return (0);
14554754Sjohnh 	/* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */
14654752Sjohnh }
14754752Sjohnh 
14854752Sjohnh /*
14954766Sjohnh  * Free reference to null layer
15054752Sjohnh  */
15154893Sheideman int
15254754Sjohnh nullfs_unmount(mp, mntflags, p)
15354752Sjohnh 	struct mount *mp;
15454752Sjohnh 	int mntflags;
15554752Sjohnh 	struct proc *p;
15654752Sjohnh {
15754754Sjohnh 	struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
15854752Sjohnh 	int error;
15954752Sjohnh 	int flags = 0;
16054752Sjohnh 	extern int doforce;
16154752Sjohnh 
16254754Sjohnh #ifdef NULLFS_DIAGNOSTIC
16354754Sjohnh 	printf("nullfs_unmount(mp = %x)\n", mp);
16454752Sjohnh #endif
16554752Sjohnh 
16654752Sjohnh 	if (mntflags & MNT_FORCE) {
16754752Sjohnh 		/* lofs can never be rootfs so don't check for it */
16854752Sjohnh 		if (!doforce)
16954752Sjohnh 			return (EINVAL);
17054752Sjohnh 		flags |= FORCECLOSE;
17154752Sjohnh 	}
17254752Sjohnh 
17354752Sjohnh 	/*
17454752Sjohnh 	 * Clear out buffer cache.  I don't think we
17554752Sjohnh 	 * ever get anything cached at this level at the
17654752Sjohnh 	 * moment, but who knows...
17754752Sjohnh 	 */
17854893Sheideman #if 0
17954752Sjohnh 	mntflushbuf(mp, 0);
18054752Sjohnh 	if (mntinvalbuf(mp, 1))
18154752Sjohnh 		return (EBUSY);
18254893Sheideman #endif
18354754Sjohnh 	if (nullm_rootvp->v_usecount > 1)
18454752Sjohnh 		return (EBUSY);
18554754Sjohnh 	if (error = vflush(mp, nullm_rootvp, flags))
18654752Sjohnh 		return (error);
18754752Sjohnh 
18854754Sjohnh #ifdef NULLFS_DIAGNOSTIC
18954938Sheideman 	vprint("alias root of lower", nullm_rootvp);
19054752Sjohnh #endif
19154752Sjohnh 	/*
19254752Sjohnh 	 * Release reference on underlying root vnode
19354752Sjohnh 	 */
19454754Sjohnh 	vrele(nullm_rootvp);
19554752Sjohnh 	/*
19654752Sjohnh 	 * And blow it away for future re-use
19754752Sjohnh 	 */
19868427Smckusick 	VOP_REVOKE(nullm_rootvp, 0);
19954752Sjohnh 	/*
20054754Sjohnh 	 * Finally, throw away the null_mount structure
20154752Sjohnh 	 */
20254752Sjohnh 	free(mp->mnt_data, M_UFSMNT);	/* XXX */
20354752Sjohnh 	mp->mnt_data = 0;
20454752Sjohnh 	return 0;
20554752Sjohnh }
20654752Sjohnh 
20754893Sheideman int
20854754Sjohnh nullfs_root(mp, vpp)
20954752Sjohnh 	struct mount *mp;
21054752Sjohnh 	struct vnode **vpp;
21154752Sjohnh {
21254752Sjohnh 	struct vnode *vp;
21354752Sjohnh 
21454754Sjohnh #ifdef NULLFS_DIAGNOSTIC
21554754Sjohnh 	printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp,
21654754Sjohnh 			MOUNTTONULLMOUNT(mp)->nullm_rootvp,
21754893Sheideman 			NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
21854752Sjohnh 			);
21954752Sjohnh #endif
22054752Sjohnh 
22154752Sjohnh 	/*
22254752Sjohnh 	 * Return locked reference to root.
22354752Sjohnh 	 */
22454754Sjohnh 	vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
22554752Sjohnh 	VREF(vp);
22654752Sjohnh 	VOP_LOCK(vp);
22754752Sjohnh 	*vpp = vp;
22854752Sjohnh 	return 0;
22954752Sjohnh }
23054752Sjohnh 
23154893Sheideman int
23254754Sjohnh nullfs_quotactl(mp, cmd, uid, arg, p)
23354752Sjohnh 	struct mount *mp;
23454752Sjohnh 	int cmd;
23554752Sjohnh 	uid_t uid;
23654752Sjohnh 	caddr_t arg;
23754752Sjohnh 	struct proc *p;
23854752Sjohnh {
23954754Sjohnh 	return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p);
24054752Sjohnh }
24154752Sjohnh 
24254893Sheideman int
24354754Sjohnh nullfs_statfs(mp, sbp, p)
24454752Sjohnh 	struct mount *mp;
24554752Sjohnh 	struct statfs *sbp;
24654752Sjohnh 	struct proc *p;
24754752Sjohnh {
24854752Sjohnh 	int error;
24954752Sjohnh 	struct statfs mstat;
25054752Sjohnh 
25154754Sjohnh #ifdef NULLFS_DIAGNOSTIC
25254754Sjohnh 	printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp,
25354754Sjohnh 			MOUNTTONULLMOUNT(mp)->nullm_rootvp,
25454893Sheideman 			NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
25554752Sjohnh 			);
25654752Sjohnh #endif
25754752Sjohnh 
25854752Sjohnh 	bzero(&mstat, sizeof(mstat));
25954752Sjohnh 
26054754Sjohnh 	error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p);
26154752Sjohnh 	if (error)
26254752Sjohnh 		return (error);
26354752Sjohnh 
26454752Sjohnh 	/* now copy across the "interesting" information and fake the rest */
26554752Sjohnh 	sbp->f_type = mstat.f_type;
26654752Sjohnh 	sbp->f_flags = mstat.f_flags;
26754752Sjohnh 	sbp->f_bsize = mstat.f_bsize;
26854752Sjohnh 	sbp->f_iosize = mstat.f_iosize;
26954752Sjohnh 	sbp->f_blocks = mstat.f_blocks;
27054752Sjohnh 	sbp->f_bfree = mstat.f_bfree;
27154752Sjohnh 	sbp->f_bavail = mstat.f_bavail;
27254752Sjohnh 	sbp->f_files = mstat.f_files;
27354752Sjohnh 	sbp->f_ffree = mstat.f_ffree;
27454752Sjohnh 	if (sbp != &mp->mnt_stat) {
27554752Sjohnh 		bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
27654752Sjohnh 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
27754752Sjohnh 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
27854752Sjohnh 	}
27954752Sjohnh 	return (0);
28054752Sjohnh }
28154752Sjohnh 
28254893Sheideman int
28354893Sheideman nullfs_sync(mp, waitfor, cred, p)
28454893Sheideman 	struct mount *mp;
28554893Sheideman 	int waitfor;
28654893Sheideman 	struct ucred *cred;
28754893Sheideman 	struct proc *p;
28854752Sjohnh {
28954766Sjohnh 	/*
29054893Sheideman 	 * XXX - Assumes no data cached at null layer.
29154766Sjohnh 	 */
29254752Sjohnh 	return (0);
29354752Sjohnh }
29454752Sjohnh 
29554893Sheideman int
29654893Sheideman nullfs_vget(mp, ino, vpp)
29754752Sjohnh 	struct mount *mp;
29854893Sheideman 	ino_t ino;
29954752Sjohnh 	struct vnode **vpp;
30054752Sjohnh {
30154893Sheideman 
30254893Sheideman 	return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp);
30354752Sjohnh }
30454752Sjohnh 
30554893Sheideman int
30654893Sheideman nullfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp)
30754893Sheideman 	struct mount *mp;
30854893Sheideman 	struct fid *fidp;
30954893Sheideman 	struct mbuf *nam;
31054893Sheideman 	struct vnode **vpp;
31154893Sheideman 	int *exflagsp;
31254893Sheideman 	struct ucred**credanonp;
31354893Sheideman {
31454893Sheideman 
31554893Sheideman 	return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, nam, vpp, exflagsp,credanonp);
31654893Sheideman }
31754893Sheideman 
31854893Sheideman int
31954754Sjohnh nullfs_vptofh(vp, fhp)
32054752Sjohnh 	struct vnode *vp;
32154752Sjohnh 	struct fid *fhp;
32254752Sjohnh {
32354893Sheideman 	return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp);
32454752Sjohnh }
32554752Sjohnh 
326*68618Smckusick int nullfs_init __P((struct vfsconf *));
32754752Sjohnh 
328*68618Smckusick #define nullfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
329*68618Smckusick 	    size_t, struct proc *)))eopnotsupp)
330*68618Smckusick 
33154754Sjohnh struct vfsops null_vfsops = {
33254754Sjohnh 	nullfs_mount,
33354754Sjohnh 	nullfs_start,
33454754Sjohnh 	nullfs_unmount,
33554754Sjohnh 	nullfs_root,
33654754Sjohnh 	nullfs_quotactl,
33754754Sjohnh 	nullfs_statfs,
33854754Sjohnh 	nullfs_sync,
33954893Sheideman 	nullfs_vget,
34054754Sjohnh 	nullfs_fhtovp,
34154754Sjohnh 	nullfs_vptofh,
34254754Sjohnh 	nullfs_init,
343*68618Smckusick 	nullfs_sysctl,
34454752Sjohnh };
345