154752Sjohnh /*
269360Spendry * Copyright (c) 1992, 1993, 1995
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*69438Smckusick * @(#)null_vfsops.c 8.7 (Berkeley) 05/14/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>
23*69438Smckusick #include <sys/proc.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>
3055025Smckusick #include <miscfs/nullfs/null.h>
3154752Sjohnh
3254752Sjohnh /*
3354766Sjohnh * Mount null layer
3454752Sjohnh */
3554893Sheideman int
nullfs_mount(mp,path,data,ndp,p)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;
4754951Sheideman struct null_mount *xmp;
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 /*
6954938Sheideman * Find lower 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 /*
7754938Sheideman * Sanity check on lower vnode
7854752Sjohnh */
7954766Sjohnh lowerrootvp = ndp->ni_vp;
8054951Sheideman
8154752Sjohnh vrele(ndp->ni_dvp);
8254951Sheideman ndp->ni_dvp = NULL;
8354752Sjohnh
8454951Sheideman xmp = (struct null_mount *) malloc(sizeof(struct null_mount),
8554752Sjohnh M_UFSMNT, M_WAITOK); /* XXX */
8654752Sjohnh
8754752Sjohnh /*
8854951Sheideman * Save reference to underlying FS
8954752Sjohnh */
9054951Sheideman xmp->nullm_vfs = lowerrootvp->v_mount;
9154752Sjohnh
9254752Sjohnh /*
9354752Sjohnh * Save reference. Each mount also holds
9454752Sjohnh * a reference on the root vnode.
9554752Sjohnh */
9654893Sheideman error = null_node_create(mp, lowerrootvp, &vp);
9754752Sjohnh /*
9854938Sheideman * Unlock the node (either the lower or the alias)
9954752Sjohnh */
100*69438Smckusick VOP_UNLOCK(vp, 0, p);
10154752Sjohnh /*
10254752Sjohnh * Make sure the node alias worked
10354752Sjohnh */
10454752Sjohnh if (error) {
10554766Sjohnh vrele(lowerrootvp);
10654951Sheideman free(xmp, M_UFSMNT); /* XXX */
10754752Sjohnh return (error);
10854752Sjohnh }
10954752Sjohnh
11054752Sjohnh /*
11154752Sjohnh * Keep a held reference to the root vnode.
11254754Sjohnh * It is vrele'd in nullfs_unmount.
11354752Sjohnh */
11454754Sjohnh nullm_rootvp = vp;
11554754Sjohnh nullm_rootvp->v_flag |= VROOT;
11654951Sheideman xmp->nullm_rootvp = nullm_rootvp;
11754893Sheideman if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
11854752Sjohnh mp->mnt_flag |= MNT_LOCAL;
11954951Sheideman mp->mnt_data = (qaddr_t) xmp;
12068618Smckusick vfs_getnewfsid(mp);
12154752Sjohnh
12254752Sjohnh (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
12354752Sjohnh bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
12454752Sjohnh (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
12554752Sjohnh &size);
12654752Sjohnh bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
12754754Sjohnh #ifdef NULLFS_DIAGNOSTIC
12854938Sheideman printf("nullfs_mount: lower %s, alias at %s\n",
12954752Sjohnh mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
13054752Sjohnh #endif
13154752Sjohnh return (0);
13254752Sjohnh }
13354752Sjohnh
13454752Sjohnh /*
13554752Sjohnh * VFS start. Nothing needed here - the start routine
13654752Sjohnh * on the underlying filesystem will have been called
13754752Sjohnh * when that filesystem was mounted.
13854752Sjohnh */
13954893Sheideman int
nullfs_start(mp,flags,p)14054754Sjohnh nullfs_start(mp, flags, p)
14154752Sjohnh struct mount *mp;
14254752Sjohnh int flags;
14354752Sjohnh struct proc *p;
14454752Sjohnh {
14554752Sjohnh return (0);
14654754Sjohnh /* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */
14754752Sjohnh }
14854752Sjohnh
14954752Sjohnh /*
15054766Sjohnh * Free reference to null layer
15154752Sjohnh */
15254893Sheideman int
nullfs_unmount(mp,mntflags,p)15354754Sjohnh nullfs_unmount(mp, mntflags, p)
15454752Sjohnh struct mount *mp;
15554752Sjohnh int mntflags;
15654752Sjohnh struct proc *p;
15754752Sjohnh {
15854754Sjohnh struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
15954752Sjohnh int error;
16054752Sjohnh int flags = 0;
16154752Sjohnh
16254754Sjohnh #ifdef NULLFS_DIAGNOSTIC
16354754Sjohnh printf("nullfs_unmount(mp = %x)\n", mp);
16454752Sjohnh #endif
16554752Sjohnh
16669337Smckusick if (mntflags & MNT_FORCE)
16754752Sjohnh flags |= FORCECLOSE;
16854752Sjohnh
16954752Sjohnh /*
17054752Sjohnh * Clear out buffer cache. I don't think we
17154752Sjohnh * ever get anything cached at this level at the
17254752Sjohnh * moment, but who knows...
17354752Sjohnh */
17454893Sheideman #if 0
17554752Sjohnh mntflushbuf(mp, 0);
17654752Sjohnh if (mntinvalbuf(mp, 1))
17754752Sjohnh return (EBUSY);
17854893Sheideman #endif
17954754Sjohnh if (nullm_rootvp->v_usecount > 1)
18054752Sjohnh return (EBUSY);
18154754Sjohnh if (error = vflush(mp, nullm_rootvp, flags))
18254752Sjohnh return (error);
18354752Sjohnh
18454754Sjohnh #ifdef NULLFS_DIAGNOSTIC
18554938Sheideman vprint("alias root of lower", nullm_rootvp);
18654752Sjohnh #endif
18754752Sjohnh /*
18854752Sjohnh * Release reference on underlying root vnode
18954752Sjohnh */
19054754Sjohnh vrele(nullm_rootvp);
19154752Sjohnh /*
19254752Sjohnh * And blow it away for future re-use
19354752Sjohnh */
19469360Spendry vgone(nullm_rootvp);
19554752Sjohnh /*
19654754Sjohnh * Finally, throw away the null_mount structure
19754752Sjohnh */
19854752Sjohnh free(mp->mnt_data, M_UFSMNT); /* XXX */
19954752Sjohnh mp->mnt_data = 0;
20054752Sjohnh return 0;
20154752Sjohnh }
20254752Sjohnh
20354893Sheideman int
nullfs_root(mp,vpp)20454754Sjohnh nullfs_root(mp, vpp)
20554752Sjohnh struct mount *mp;
20654752Sjohnh struct vnode **vpp;
20754752Sjohnh {
208*69438Smckusick struct proc *p = curproc; /* XXX */
20954752Sjohnh struct vnode *vp;
21054752Sjohnh
21154754Sjohnh #ifdef NULLFS_DIAGNOSTIC
21254754Sjohnh printf("nullfs_root(mp = %x, vp = %x->%x)\n", mp,
21354754Sjohnh MOUNTTONULLMOUNT(mp)->nullm_rootvp,
21454893Sheideman NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
21554752Sjohnh );
21654752Sjohnh #endif
21754752Sjohnh
21854752Sjohnh /*
21954752Sjohnh * Return locked reference to root.
22054752Sjohnh */
22154754Sjohnh vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
22254752Sjohnh VREF(vp);
223*69438Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
22454752Sjohnh *vpp = vp;
22554752Sjohnh return 0;
22654752Sjohnh }
22754752Sjohnh
22854893Sheideman int
nullfs_quotactl(mp,cmd,uid,arg,p)22954754Sjohnh nullfs_quotactl(mp, cmd, uid, arg, p)
23054752Sjohnh struct mount *mp;
23154752Sjohnh int cmd;
23254752Sjohnh uid_t uid;
23354752Sjohnh caddr_t arg;
23454752Sjohnh struct proc *p;
23554752Sjohnh {
23654754Sjohnh return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p);
23754752Sjohnh }
23854752Sjohnh
23954893Sheideman int
nullfs_statfs(mp,sbp,p)24054754Sjohnh nullfs_statfs(mp, sbp, p)
24154752Sjohnh struct mount *mp;
24254752Sjohnh struct statfs *sbp;
24354752Sjohnh struct proc *p;
24454752Sjohnh {
24554752Sjohnh int error;
24654752Sjohnh struct statfs mstat;
24754752Sjohnh
24854754Sjohnh #ifdef NULLFS_DIAGNOSTIC
24954754Sjohnh printf("nullfs_statfs(mp = %x, vp = %x->%x)\n", mp,
25054754Sjohnh MOUNTTONULLMOUNT(mp)->nullm_rootvp,
25154893Sheideman NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
25254752Sjohnh );
25354752Sjohnh #endif
25454752Sjohnh
25554752Sjohnh bzero(&mstat, sizeof(mstat));
25654752Sjohnh
25754754Sjohnh error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p);
25854752Sjohnh if (error)
25954752Sjohnh return (error);
26054752Sjohnh
26154752Sjohnh /* now copy across the "interesting" information and fake the rest */
26254752Sjohnh sbp->f_type = mstat.f_type;
26354752Sjohnh sbp->f_flags = mstat.f_flags;
26454752Sjohnh sbp->f_bsize = mstat.f_bsize;
26554752Sjohnh sbp->f_iosize = mstat.f_iosize;
26654752Sjohnh sbp->f_blocks = mstat.f_blocks;
26754752Sjohnh sbp->f_bfree = mstat.f_bfree;
26854752Sjohnh sbp->f_bavail = mstat.f_bavail;
26954752Sjohnh sbp->f_files = mstat.f_files;
27054752Sjohnh sbp->f_ffree = mstat.f_ffree;
27154752Sjohnh if (sbp != &mp->mnt_stat) {
27254752Sjohnh bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
27354752Sjohnh bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
27454752Sjohnh bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
27554752Sjohnh }
27654752Sjohnh return (0);
27754752Sjohnh }
27854752Sjohnh
27954893Sheideman int
nullfs_sync(mp,waitfor,cred,p)28054893Sheideman nullfs_sync(mp, waitfor, cred, p)
28154893Sheideman struct mount *mp;
28254893Sheideman int waitfor;
28354893Sheideman struct ucred *cred;
28454893Sheideman struct proc *p;
28554752Sjohnh {
28654766Sjohnh /*
28754893Sheideman * XXX - Assumes no data cached at null layer.
28854766Sjohnh */
28954752Sjohnh return (0);
29054752Sjohnh }
29154752Sjohnh
29254893Sheideman int
nullfs_vget(mp,ino,vpp)29354893Sheideman nullfs_vget(mp, ino, vpp)
29454752Sjohnh struct mount *mp;
29554893Sheideman ino_t ino;
29654752Sjohnh struct vnode **vpp;
29754752Sjohnh {
29854893Sheideman
29954893Sheideman return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp);
30054752Sjohnh }
30154752Sjohnh
30254893Sheideman int
nullfs_fhtovp(mp,fidp,nam,vpp,exflagsp,credanonp)30354893Sheideman nullfs_fhtovp(mp, fidp, nam, vpp, exflagsp, credanonp)
30454893Sheideman struct mount *mp;
30554893Sheideman struct fid *fidp;
30654893Sheideman struct mbuf *nam;
30754893Sheideman struct vnode **vpp;
30854893Sheideman int *exflagsp;
30954893Sheideman struct ucred**credanonp;
31054893Sheideman {
31154893Sheideman
31254893Sheideman return VFS_FHTOVP(MOUNTTONULLMOUNT(mp)->nullm_vfs, fidp, nam, vpp, exflagsp,credanonp);
31354893Sheideman }
31454893Sheideman
31554893Sheideman int
nullfs_vptofh(vp,fhp)31654754Sjohnh nullfs_vptofh(vp, fhp)
31754752Sjohnh struct vnode *vp;
31854752Sjohnh struct fid *fhp;
31954752Sjohnh {
32054893Sheideman return VFS_VPTOFH(NULLVPTOLOWERVP(vp), fhp);
32154752Sjohnh }
32254752Sjohnh
32368618Smckusick int nullfs_init __P((struct vfsconf *));
32454752Sjohnh
32568618Smckusick #define nullfs_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
32668618Smckusick size_t, struct proc *)))eopnotsupp)
32768618Smckusick
32854754Sjohnh struct vfsops null_vfsops = {
32954754Sjohnh nullfs_mount,
33054754Sjohnh nullfs_start,
33154754Sjohnh nullfs_unmount,
33254754Sjohnh nullfs_root,
33354754Sjohnh nullfs_quotactl,
33454754Sjohnh nullfs_statfs,
33554754Sjohnh nullfs_sync,
33654893Sheideman nullfs_vget,
33754754Sjohnh nullfs_fhtovp,
33854754Sjohnh nullfs_vptofh,
33954754Sjohnh nullfs_init,
34068618Smckusick nullfs_sysctl,
34154752Sjohnh };
342