summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorTed Unangst <tedu@cvs.openbsd.org>2003-05-12 21:00:40 +0000
committerTed Unangst <tedu@cvs.openbsd.org>2003-05-12 21:00:40 +0000
commit104c9cee2b7581512ef5cf06fb24402ea5fa56c5 (patch)
tree5fdd84bbcbd97d421bf48dc5260bc924bb1f0abb /sys
parenta4037f6b4fd1ba42f6428bea41cfc9ff22c44528 (diff)
most of the fixes for nullfs. use the new common layer stuff in genfs.
Diffstat (limited to 'sys')
-rw-r--r--sys/miscfs/nullfs/null.h81
-rw-r--r--sys/miscfs/nullfs/null_vfsops.c364
-rw-r--r--sys/miscfs/nullfs/null_vnops.c640
3 files changed, 267 insertions, 818 deletions
diff --git a/sys/miscfs/nullfs/null.h b/sys/miscfs/nullfs/null.h
index 5b91a2f2ce9..b58e3040098 100644
--- a/sys/miscfs/nullfs/null.h
+++ b/sys/miscfs/nullfs/null.h
@@ -1,5 +1,38 @@
-/* $OpenBSD: null.h,v 1.11 2002/03/14 01:27:08 millert Exp $ */
-/* $NetBSD: null.h,v 1.7 1996/05/17 20:53:11 gwr Exp $ */
+/* $OpenBSD: null.h,v 1.12 2003/05/12 21:00:39 tedu Exp $ */
+/* $NetBSD: null.h,v 1.13 2001/11/07 04:56:09 enami Exp $ */
+
+/*
+ * Copyright (c) 1999 National Aeronautics & Space Administration
+ * All rights reserved.
+ *
+ * This software was written by William Studenmund of the
+ * Numerical Aerospace Simulation Facility, NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the National Aeronautics & Space Administration
+ * nor the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB-
+ * UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
/*
* Copyright (c) 1992, 1993
@@ -40,42 +73,58 @@
* @(#)null.h 8.2 (Berkeley) 1/21/94
*/
+#include <miscfs/genfs/layer.h>
+
struct null_args {
- char *target; /* Target of loopback */
+ struct layer_args la; /* generic layerfs args */
};
+#define nulla_target la.target
+#define nulla_export la.export
+#ifdef _KERNEL
struct null_mount {
- struct mount *nullm_vfs;
- struct vnode *nullm_rootvp; /* Reference to root null_node */
+ struct layer_mount lm; /* generic layerfs mount stuff */
};
+#define nullm_vfs lm.layerm_vfs
+#define nullm_rootvp lm.layerm_rootvp
+#define nullm_export lm.layerm_export
+#define nullm_flags lm.layerm_flags
+#define nullm_size lm.layerm_size
+#define nullm_tag lm.layerm_tag
+#define nullm_bypass lm.layerm_bypass
+#define nullm_alloc lm.layerm_alloc
+#define nullm_vnodeop_p lm.layerm_vnodeop_p
+#define nullm_node_hashtbl lm.layerm_node_hashtbl
+#define nullm_node_hash lm.layerm_node_hash
+#define nullm_hashlock lm.layerm_hashlock
-#ifdef _KERNEL
/*
* A cache of vnode references
*/
struct null_node {
- LIST_ENTRY(null_node) null_hash; /* Hash list */
- struct vnode *null_lowervp; /* VREFed once */
- struct vnode *null_vnode; /* Back pointer */
+ struct layer_node ln;
};
+#define null_hash ln.layer_hash
+#define null_lowervp ln.layer_lowervp
+#define null_vnode ln.layer_vnode
+#define null_flags ln.layer_flags
-extern int null_node_create(struct mount *mp, struct vnode *target, struct vnode **vpp, int lockit);
+int null_node_create(struct mount *, struct vnode *,
+ struct vnode **, int);
#define MOUNTTONULLMOUNT(mp) ((struct null_mount *)((mp)->mnt_data))
#define VTONULL(vp) ((struct null_node *)(vp)->v_data)
#define NULLTOV(xp) ((xp)->null_vnode)
#ifdef NULLFS_DIAGNOSTIC
-extern struct vnode *null_checkvp(struct vnode *vp, char *fil, int lno);
-#define NULLVPTOLOWERVP(vp) null_checkvp((vp), __FILE__, __LINE__)
+struct vnode *layer_checkvp(struct vnode *, char *, int);
+#define NULLVPTOLOWERVP(vp) layer_checkvp((vp), __FILE__, __LINE__)
#else
#define NULLVPTOLOWERVP(vp) (VTONULL(vp)->null_lowervp)
#endif
-extern int (**null_vnodeop_p)(void *);
-extern struct vfsops null_vfsops;
+extern int (**nullfs_vnodeop_p)(void *);
+extern struct vfsops nullfs_vfsops;
int nullfs_init(struct vfsconf *);
-int null_bypass(void *);
-
#endif /* _KERNEL */
diff --git a/sys/miscfs/nullfs/null_vfsops.c b/sys/miscfs/nullfs/null_vfsops.c
index a9f7d0f8ad0..8c3d37ac542 100644
--- a/sys/miscfs/nullfs/null_vfsops.c
+++ b/sys/miscfs/nullfs/null_vfsops.c
@@ -1,8 +1,40 @@
-/* $OpenBSD: null_vfsops.c,v 1.14 2003/02/24 22:32:46 tedu Exp $ */
-/* $NetBSD: null_vfsops.c,v 1.11 1996/05/10 22:50:56 jtk Exp $ */
+/* $OpenBSD: null_vfsops.c,v 1.15 2003/05/12 21:00:39 tedu Exp $ */
+/* $NetBSD: null_vfsops.c,v 1.38 2002/09/21 18:09:29 christos Exp $ */
/*
- * Copyright (c) 1992, 1993
+ * Copyright (c) 1999 National Aeronautics & Space Administration
+ * All rights reserved.
+ *
+ * This software was written by William Studenmund of the
+ * Numerical Aerospace Simulation Facility, NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the National Aeronautics & Space Administration
+ * nor the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB-
+ * UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1992, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software donated to Berkeley by
@@ -38,7 +70,7 @@
*
* from: Id: lofs_vfsops.c,v 1.9 1992/05/30 10:26:24 jsp Exp
* from: @(#)lofs_vfsops.c 1.2 (Berkeley) 6/18/92
- * @(#)null_vfsops.c 8.2 (Berkeley) 1/21/94
+ * @(#)null_vfsops.c 8.7 (Berkeley) 5/14/95
*/
/*
@@ -46,29 +78,23 @@
* (See null_vnops.c for a description of what this does.)
*/
+
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/proc.h>
#include <sys/time.h>
-#include <sys/types.h>
+#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/malloc.h>
+
#include <miscfs/nullfs/null.h>
+#include <miscfs/genfs/layer_extern.h>
int nullfs_mount(struct mount *, const char *, void *,
- struct nameidata *, struct proc *);
-int nullfs_start(struct mount *, int, struct proc *);
+ struct nameidata *, struct proc *);
int nullfs_unmount(struct mount *, int, struct proc *);
-int nullfs_root(struct mount *, struct vnode **);
-int nullfs_quotactl(struct mount *, int, uid_t, caddr_t,
- struct proc *);
-int nullfs_statfs(struct mount *, struct statfs *, struct proc *);
-int nullfs_sync(struct mount *, int, struct ucred *, struct proc *);
-int nullfs_vget(struct mount *, ino_t, struct vnode **);
-int nullfs_fhtovp(struct mount *, struct fid *, struct vnode **);
-int nullfs_vptofh(struct vnode *, struct fid *);
+
/*
* Mount null layer
*/
@@ -80,37 +106,50 @@ nullfs_mount(mp, path, data, ndp, p)
struct nameidata *ndp;
struct proc *p;
{
- int error = 0;
struct null_args args;
struct vnode *lowerrootvp, *vp;
- struct vnode *nullm_rootvp;
- struct null_mount *xmp;
+ struct null_mount *nmp;
+ struct layer_mount *lmp;
size_t size;
+ int error = 0;
#ifdef NULLFS_DIAGNOSTIC
printf("nullfs_mount(mp = %p)\n", mp);
#endif
-
- /*
- * Update is a no-op
- */
- if (mp->mnt_flag & MNT_UPDATE) {
- return (EOPNOTSUPP);
- /* return VFS_MOUNT(MOUNTTONULLMOUNT(mp)->nullm_vfs, path, data, ndp, p);*/
+#if 0
+ if (mp->mnt_flag & MNT_GETARGS) {
+ lmp = MOUNTTOLAYERMOUNT(mp);
+ if (lmp == NULL)
+ return EIO;
+ args.la.target = NULL;
+ vfs_showexport(mp, &args.la.export, &lmp->layerm_export);
+ return copyout(&args, data, sizeof(args));
}
-
+#endif
/*
* Get argument
*/
- error = copyin(data, &args, sizeof(struct null_args));
+ error = copyin(data, (caddr_t)&args, sizeof(struct null_args));
if (error)
return (error);
/*
+ * Update only does export updating.
+ */
+ if (mp->mnt_flag & MNT_UPDATE) {
+ lmp = MOUNTTOLAYERMOUNT(mp);
+ if (args.nulla_target == NULL)
+ return (vfs_export(mp, &lmp->layerm_export,
+ &args.la.export));
+ else
+ return (EOPNOTSUPP);
+ }
+
+ /*
* Find lower node
*/
- NDINIT(ndp, LOOKUP, FOLLOW|WANTPARENT|LOCKLEAF,
- UIO_USERSPACE, args.target, p);
+ NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF,
+ UIO_USERSPACE, args.la.target, p);
if ((error = namei(ndp)) != 0)
return (error);
@@ -119,81 +158,70 @@ nullfs_mount(mp, path, data, ndp, p)
*/
lowerrootvp = ndp->ni_vp;
- vrele(ndp->ni_dvp);
- ndp->ni_dvp = NULL;
-
- if (lowerrootvp->v_type != VDIR) {
- vput(lowerrootvp);
- return (EINVAL);
- }
-
- xmp = (struct null_mount *) malloc(sizeof(struct null_mount),
- M_MISCFSMNT, M_WAITOK);
-
/*
- * Save reference to underlying FS
+ * First cut at fixing up upper mount point
*/
- xmp->nullm_vfs = lowerrootvp->v_mount;
+ nmp = (struct null_mount *) malloc(sizeof(struct null_mount),
+ M_UFSMNT, M_WAITOK); /* XXX */
+ memset((caddr_t)nmp, 0, sizeof(struct null_mount));
+
+ mp->mnt_data = (qaddr_t)nmp;
+ nmp->nullm_vfs = lowerrootvp->v_mount;
+ if (nmp->nullm_vfs->mnt_flag & MNT_LOCAL)
+ mp->mnt_flag |= MNT_LOCAL;
/*
- * Save reference. Each mount also holds
- * a reference on the root vnode.
+ * Make sure that the mount point is sufficiently initialized
+ * that the node create call will work.
*/
- error = null_node_create(mp, lowerrootvp, &vp, 1);
+ vfs_getnewfsid(mp);
+
+ nmp->nullm_size = sizeof(struct null_node);
+ nmp->nullm_tag = VT_NULL;
+ nmp->nullm_bypass = layer_bypass;
+ nmp->nullm_alloc = layer_node_alloc; /* the default alloc is fine */
+ nmp->nullm_vnodeop_p = nullfs_vnodeop_p;
+ simple_lock_init(&nmp->nullm_hashlock);
+ nmp->nullm_node_hashtbl = hashinit(desiredvnodes, M_CACHE,
+ M_WAITOK, &nmp->nullm_node_hash);
+
/*
- * Unlock the node (either the lower or the alias)
+ * Fix up null node for root vnode
*/
- VOP_UNLOCK(vp, 0, p);
+ error = layer_node_create(mp, lowerrootvp, &vp);
/*
- * Make sure the node alias worked
+ * Make sure the fixup worked
*/
if (error) {
- vrele(lowerrootvp);
- free(xmp, M_MISCFSMNT);
+ vput(lowerrootvp);
+ free(nmp->nullm_node_hashtbl, M_CACHE);
return (error);
}
+ /*
+ * Unlock the node
+ */
+ VOP_UNLOCK(vp, 0, p);
/*
* Keep a held reference to the root vnode.
* It is vrele'd in nullfs_unmount.
*/
- nullm_rootvp = vp;
- nullm_rootvp->v_flag |= VROOT;
- xmp->nullm_rootvp = nullm_rootvp;
- if (NULLVPTOLOWERVP(nullm_rootvp)->v_mount->mnt_flag & MNT_LOCAL)
- mp->mnt_flag |= MNT_LOCAL;
- mp->mnt_data = (qaddr_t) xmp;
- vfs_getnewfsid(mp);
+ vp->v_flag |= VROOT;
+ nmp->nullm_rootvp = vp;
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
- bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
- (void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
- &size);
- bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
+ memset(mp->mnt_stat.f_mntonname + size, 0, MNAMELEN - size);
+ (void) copyinstr(args.la.target, mp->mnt_stat.f_mntfromname,
+ MNAMELEN - 1, &size);
+ memset(mp->mnt_stat.f_mntfromname + size, 0, MNAMELEN - size);
#ifdef NULLFS_DIAGNOSTIC
printf("nullfs_mount: lower %s, alias at %s\n",
- mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
+ mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
#endif
return (0);
}
/*
- * VFS start. Nothing needed here - the start routine
- * on the underlying filesystem will have been called
- * when that filesystem was mounted.
- */
-int
-nullfs_start(mp, flags, p)
- struct mount *mp;
- int flags;
- struct proc *p;
-{
-
- return (0);
- /* return VFS_START(MOUNTTONULLMOUNT(mp)->nullm_vfs, flags, p); */
-}
-
-/*
* Free reference to null layer
*/
int
@@ -202,7 +230,8 @@ nullfs_unmount(mp, mntflags, p)
int mntflags;
struct proc *p;
{
- struct vnode *nullm_rootvp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
+ struct null_mount *nmp = MOUNTTONULLMOUNT(mp);
+ struct vnode *null_rootvp = nmp->nullm_rootvp;
int error;
int flags = 0;
@@ -210,9 +239,8 @@ nullfs_unmount(mp, mntflags, p)
printf("nullfs_unmount(mp = %p)\n", mp);
#endif
- if (mntflags & MNT_FORCE) {
+ if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- }
/*
* Clear out buffer cache. I don't think we
@@ -220,172 +248,56 @@ nullfs_unmount(mp, mntflags, p)
* moment, but who knows...
*/
#if 0
- mntflushbuf(mp, 0);
+ mntflushbuf(mp, 0);
if (mntinvalbuf(mp, 1))
return (EBUSY);
#endif
- if (nullm_rootvp->v_usecount > 1)
+ if (null_rootvp->v_usecount > 1)
return (EBUSY);
- if ((error = vflush(mp, nullm_rootvp, flags)) != 0)
+ if ((error = vflush(mp, null_rootvp, flags)) != 0)
return (error);
#ifdef NULLFS_DIAGNOSTIC
- vprint("alias root of lower", nullm_rootvp);
-#endif
+ vprint("alias root of lower", null_rootvp);
+#endif
/*
* Release reference on underlying root vnode
*/
- vrele(nullm_rootvp);
+ vrele(null_rootvp);
+
/*
* And blow it away for future re-use
*/
- vgone(nullm_rootvp);
+ vgone(null_rootvp);
+
/*
* Finally, throw away the null_mount structure
*/
+ free(nmp->nullm_node_hashtbl, M_CACHE);
free(mp->mnt_data, M_MISCFSMNT);
- mp->mnt_data = 0;
+ mp->mnt_data = NULL;
return 0;
}
-int
-nullfs_root(mp, vpp)
- struct mount *mp;
- struct vnode **vpp;
-{
- struct vnode *vp;
- struct proc *p = curproc;
-
-#ifdef NULLFS_DIAGNOSTIC
- printf("nullfs_root(mp = %p, vp = %p->%p)\n", mp,
- MOUNTTONULLMOUNT(mp)->nullm_rootvp,
- NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
- );
-#endif
-
- /*
- * Return locked reference to root.
- */
- vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
- VREF(vp);
- vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
- *vpp = vp;
- return 0;
-}
-
-int
-nullfs_quotactl(mp, cmd, uid, arg, p)
- struct mount *mp;
- int cmd;
- uid_t uid;
- caddr_t arg;
- struct proc *p;
-{
+extern const struct vnodeopv_desc nullfs_vnodeop_opv_desc;
- return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, p);
-}
-
-int
-nullfs_statfs(mp, sbp, p)
- struct mount *mp;
- struct statfs *sbp;
- struct proc *p;
-{
- int error;
- struct statfs mstat;
-
-#ifdef NULLFS_DIAGNOSTIC
- printf("nullfs_statfs(mp = %p, vp = %p->%p)\n", mp,
- MOUNTTONULLMOUNT(mp)->nullm_rootvp,
- NULLVPTOLOWERVP(MOUNTTONULLMOUNT(mp)->nullm_rootvp)
- );
-#endif
-
- bzero(&mstat, sizeof(mstat));
-
- error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, p);
- if (error)
- return (error);
-
- /* now copy across the "interesting" information and fake the rest */
- sbp->f_flags = mstat.f_flags;
- sbp->f_bsize = mstat.f_bsize;
- sbp->f_iosize = mstat.f_iosize;
- sbp->f_blocks = mstat.f_blocks;
- sbp->f_bfree = mstat.f_bfree;
- sbp->f_bavail = mstat.f_bavail;
- sbp->f_files = mstat.f_files;
- sbp->f_ffree = mstat.f_ffree;
- if (sbp != &mp->mnt_stat) {
- bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
- bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
- bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
- }
- strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
- return (0);
-}
-
-int
-nullfs_sync(mp, waitfor, cred, p)
- struct mount *mp;
- int waitfor;
- struct ucred *cred;
- struct proc *p;
-{
-
- /*
- * XXX - Assumes no data cached at null layer.
- */
- return (0);
-}
-
-int
-nullfs_vget(mp, ino, vpp)
- struct mount *mp;
- ino_t ino;
- struct vnode **vpp;
-{
-
- return VFS_VGET(MOUNTTONULLMOUNT(mp)->nullm_vfs, ino, vpp);
-}
-
-int
-nullfs_fhtovp(mp, fidp, vpp)
- struct mount *mp;
- struct fid *fidp;
- struct vnode **vpp;
-{
-
- return (EOPNOTSUPP);
-}
-
-int
-nullfs_vptofh(vp, fhp)
- struct vnode *vp;
- struct fid *fhp;
-{
-
- return (EOPNOTSUPP);
-}
-
-#define nullfs_sysctl ((int (*)(int *, u_int, void *, size_t *, void *, \
- size_t, struct proc *))eopnotsupp)
-
-#define nullfs_checkexp ((int (*)(struct mount *, struct mbuf *, \
- int *, struct ucred **))eopnotsupp)
+const struct vnodeopv_desc * const nullfs_vnodeopv_descs[] = {
+ &nullfs_vnodeop_opv_desc,
+ NULL,
+};
-struct vfsops null_vfsops = {
+struct vfsops nullfs_vfsops = {
nullfs_mount,
- nullfs_start,
+ layerfs_start,
nullfs_unmount,
- nullfs_root,
- nullfs_quotactl,
- nullfs_statfs,
- nullfs_sync,
- nullfs_vget,
- nullfs_fhtovp,
- nullfs_vptofh,
- nullfs_init,
- nullfs_sysctl,
- nullfs_checkexp
+ layerfs_root,
+ layerfs_quotactl,
+ layerfs_statfs,
+ layerfs_sync,
+ layerfs_vget,
+ layerfs_fhtovp,
+ layerfs_vptofh,
+ layerfs_init,
+ layerfs_sysctl,
+ layerfs_checkexp
};
diff --git a/sys/miscfs/nullfs/null_vnops.c b/sys/miscfs/nullfs/null_vnops.c
index 7df52de9f75..d8953a55ab9 100644
--- a/sys/miscfs/nullfs/null_vnops.c
+++ b/sys/miscfs/nullfs/null_vnops.c
@@ -1,7 +1,39 @@
-/* $OpenBSD: null_vnops.c,v 1.16 2002/10/27 15:27:18 brad Exp $ */
-/* $NetBSD: null_vnops.c,v 1.7 1996/05/10 22:51:01 jtk Exp $ */
+/* $OpenBSD: null_vnops.c,v 1.17 2003/05/12 21:00:39 tedu Exp $ */
+/* $NetBSD: null_vnops.c,v 1.26 2002/09/10 02:52:40 jtk Exp $ */
/*
+ * Copyright (c) 1999 National Aeronautics & Space Administration
+ * All rights reserved.
+ *
+ * This software was written by William Studenmund of the
+ * Numerical Aerospace Simulation Facility, NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the National Aeronautics & Space Administration
+ * nor the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NATIONAL AERONAUTICS & SPACE ADMINISTRATION
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ADMINISTRATION OR CONTRIB-
+ * UTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -36,602 +68,58 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)null_vnops.c 8.1 (Berkeley) 6/10/93
+ * @(#)null_vnops.c 8.6 (Berkeley) 5/27/95
*
* Ancestors:
* @(#)lofs_vnops.c 1.2 (Berkeley) 6/18/92
- * Id: lofs_vnops.c,v 1.11 1992/05/30 10:05:43 jsp Exp
+ * Id: lofs_vnops.c,v 1.11 1992/05/30 10:05:43 jsp Exp jsp
* ...and...
* @(#)null_vnodeops.c 1.20 92/07/07 UCLA Ficus project
*/
/*
- * Null Layer
- *
- * (See mount_null(8) for more information.)
- *
- * The null layer duplicates a portion of the file system
- * name space under a new name. In this respect, it is
- * similar to the loopback file system. It differs from
- * the loopback fs in two respects: it is implemented using
- * a stackable layers techniques, and its "null-node"s stack above
- * all lower-layer vnodes, not just over directory vnodes.
- *
- * The null layer has two purposes. First, it serves as a demonstration
- * of layering by providing a layer which does nothing. (It actually
- * does everything the loopback file system does, which is slightly
- * more than nothing.) Second, the null layer can serve as a prototype
- * layer. Since it provides all necessary layer framework,
- * new file system layers can be created very easily by starting
- * with a null layer.
- *
- * The remainder of this man page examines the null layer as a basis
- * for constructing new layers.
- *
- *
- * INSTANTIATING NEW NULL LAYERS
- *
- * New null layers are created with mount_null(8).
- * Mount_null(8) takes two arguments, the pathname
- * of the lower vfs (target-pn) and the pathname where the null
- * layer will appear in the namespace (alias-pn). After
- * the null layer is put into place, the contents
- * of target-pn subtree will be aliased under alias-pn.
- *
- *
- * OPERATION OF A NULL LAYER
- *
- * The null layer is the minimum file system layer,
- * simply bypassing all possible operations to the lower layer
- * for processing there. The majority of its activity centers
- * on the bypass routine, though which nearly all vnode operations
- * pass.
- *
- * The bypass routine accepts arbitrary vnode operations for
- * handling by the lower layer. It begins by examining vnode
- * operation arguments and replacing any null-nodes by their
- * lower-layer equivalents. It then invokes the operation
- * on the lower layer. Finally, it replaces the null-nodes
- * in the arguments and, if a vnode is returned by the operation,
- * stacks a null-node on top of the returned vnode.
- *
- * Although bypass handles most operations,
- * vop_getattr, _inactive, _reclaim, and _print are not bypassed.
- * Vop_getattr must change the fsid being returned.
- * Vop_lock and vop_unlock must handle any locking for the
- * current vnode as well as pass the lock request down.
- * Vop_inactive and vop_reclaim are not bypassed so that
- * they can handle freeing null-layer specific data. Vop_print
- * is not bypassed to avoid excessive debugging information.
- * Also, certain vnode operations change the locking state within
- * the operation (create, mknod, remove, link, rename, mkdir, rmdir,
- * and symlink). Ideally, these operations should not change the
- * lock state, but should be changed to let the caller of the
- * function unlock them. Otherwise all intermediate vnode layers
- * (such as union, umapfs, etc) must catch these functions
- * to the necessary locking at their layer
- *
- *
- * INSTANTIATING VNODE STACKS
- *
- * Mounting associates the null layer with a lower layer,
- * in effect stacking two VFSes. Vnode stacks are instead
- * created on demand as files are accessed.
- *
- * The initial mount creates a single vnode stack for the
- * root of the new null layer. All other vnode stacks
- * are created as a result of vnode operations on
- * this or other null vnode stacks.
- *
- * New vnode stacks come into existence as a result of
- * an operation which returns a vnode.
- * The bypass routine stacks a null-node above the new
- * vnode before returning it to the caller.
- *
- * For example, imagine mounting a null layer with
- * "mount_null /usr/include /dev/layer/null".
- * Changing directory to /dev/layer/null will assign
- * the root null-node (which was created when the null layer was mounted).
- * Now consider opening "sys". A vop_lookup would be
- * done on the root null-node. This operation would bypass through
- * to the lower layer which would return a vnode representing
- * the UFS "sys". Null_bypass then builds a null-node
- * aliasing the UFS "sys" and returns this to the caller.
- * Later operations on the null-node "sys" will repeat this
- * process when constructing other vnode stacks.
- *
- *
- * CREATING OTHER FILE SYSTEM LAYERS
- *
- * One of the easiest ways to construct new file system layers is to make
- * a copy of the null layer, rename all files and variables, and
- * then begin modifing the copy. sed(1) can be used to easily rename
- * all variables.
- *
- * The umap layer is an example of a layer descended from the
- * null layer.
- *
- *
- * INVOKING OPERATIONS ON LOWER LAYERS
- *
- * There are two techniques to invoke operations on a lower layer
- * when the operation cannot be completely bypassed. Each method
- * is appropriate in different situations. In both cases,
- * it is the responsibility of the aliasing layer to make
- * the operation arguments "correct" for the lower layer
- * by mapping an vnode arguments to the lower layer.
- *
- * The first approach is to call the aliasing layer's bypass routine.
- * This method is most suitable when you wish to invoke the operation
- * currently being handled on the lower layer. It has the advantage
- * that the bypass routine already must do argument mapping.
- * An example of this is null_getattrs in the null layer.
- *
- * A second approach is to directly invoke vnode operations on
- * the lower layer with the VOP_OPERATIONNAME interface.
- * The advantage of this method is that it is easy to invoke
- * arbitrary operations on the lower layer. The disadvantage
- * is that vnode arguments must be manually mapped.
- *
+ * See miscfs/genfs/layer_vnops.c and mount_null(8) for a
+ * description of the null file system.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/time.h>
-#include <sys/types.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#include <miscfs/nullfs/null.h>
-
-
-int null_bug_bypass = 0; /* for debugging: enables bypass printf'ing */
-
-int null_getattr(void *);
-int null_inactive(void *);
-int null_reclaim(void *);
-int null_print(void *);
-int null_strategy(void *);
-int null_bwrite(void *);
-int null_lock(void *);
-int null_unlock(void *);
-int null_islocked(void *);
-int null_lookup(void *);
-int null_open(void *);
-
-/*
- * This is the 10-Apr-92 bypass routine.
- * This version has been optimized for speed, throwing away some
- * safety checks. It should still always work, but it's not as
- * robust to programmer errors.
- * Define SAFETY to include some error checking code.
- *
- * In general, we map all vnodes going down and unmap them on the way back.
- * As an exception to this, vnodes can be marked "unmapped" by setting
- * the Nth bit in operation's vdesc_flags.
- *
- * Also, some BSD vnode operations have the side effect of vrele'ing
- * their arguments. With stacking, the reference counts are held
- * by the upper node, not the lower one, so we must handle these
- * side-effects here. This is not of concern in Sun-derived systems
- * since there are no such side-effects.
- *
- * This makes the following assumptions:
- * - only one returned vpp
- * - no INOUT vpp's (Sun's vop_open has one of these)
- * - the vnode operation vector of the first vnode should be used
- * to determine what implementation of the op should be invoked
- * - all mapped vnodes are of our vnode-type (NEEDSWORK:
- * problems on rmdir'ing mount points and renaming?)
- */
-int
-null_bypass(v)
- void *v;
-{
- struct vop_generic_args /* {
- struct vnodeop_desc *a_desc;
- <other random data follows, presumably>
- } */ *ap = v;
- register struct vnode **this_vp_p;
- int error;
- struct vnode *old_vps[VDESC_MAX_VPS];
- struct vnode **vps_p[VDESC_MAX_VPS];
- struct vnode ***vppp;
- struct vnodeop_desc *descp = ap->a_desc;
- int reles, i;
-
- if (null_bug_bypass)
- printf ("null_bypass: %s\n", descp->vdesc_name);
-
-#ifdef SAFETY
- /*
- * We require at least one vp.
- */
- if (descp->vdesc_vp_offsets == NULL ||
- descp->vdesc_vp_offsets[0] == VDESC_NO_OFFSET)
- panic ("null_bypass: no vp's in map.");
-#endif
-
- /*
- * Map the vnodes going in.
- * Later, we'll invoke the operation based on
- * the first mapped vnode's operation vector.
- */
- reles = descp->vdesc_flags;
- for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
- if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
- break; /* bail out at end of list */
- vps_p[i] = this_vp_p =
- VOPARG_OFFSETTO(struct vnode**,descp->vdesc_vp_offsets[i],ap);
- /*
- * We're not guaranteed that any but the first vnode
- * are of our type. Check for and don't map any
- * that aren't. (We must always map first vp or vclean fails.)
- */
- if (i && (*this_vp_p == NULLVP ||
- (*this_vp_p)->v_op != null_vnodeop_p)) {
- old_vps[i] = NULLVP;
- } else {
- old_vps[i] = *this_vp_p;
- *(vps_p[i]) = NULLVPTOLOWERVP(*this_vp_p);
- /*
- * XXX - Several operations have the side effect
- * of vrele'ing their vp's. We must account for
- * that. (This should go away in the future.)
- */
- if (reles & 1)
- VREF(*this_vp_p);
- }
-
- }
-
- /*
- * Call the operation on the lower layer
- * with the modified argument structure.
- */
- error = VCALL(*(vps_p[0]), descp->vdesc_offset, ap);
-
- /*
- * Maintain the illusion of call-by-value
- * by restoring vnodes in the argument structure
- * to their original value.
- */
- reles = descp->vdesc_flags;
- for (i = 0; i < VDESC_MAX_VPS; reles >>= 1, i++) {
- if (descp->vdesc_vp_offsets[i] == VDESC_NO_OFFSET)
- break; /* bail out at end of list */
- if (old_vps[i] != NULLVP) {
- *(vps_p[i]) = old_vps[i];
- if (reles & 1) {
- vrele(*(vps_p[i]));
- }
- }
-
- /*
- * Map the possible out-going vpp
- * (Assumes that the lower layer always returns
- * a VREF'ed vpp unless it gets an error.)
- */
- if (descp->vdesc_vpp_offset != VDESC_NO_OFFSET &&
- !(descp->vdesc_flags & VDESC_NOMAP_VPP) &&
- !error) {
- /*
- * XXX - even though some ops have vpp returned vp's,
- * several ops actually vrele this before returning.
- * We must avoid these ops.
- * (This should go away when these ops are regularized.)
- */
- if (descp->vdesc_flags & VDESC_VPP_WILLRELE)
- goto out;
- vppp = VOPARG_OFFSETTO(struct vnode***,
- descp->vdesc_vpp_offset,ap);
- /*
- * This assumes that **vppp is a locked vnode (it is always
- * so as of this writing, NetBSD-current 1995/02/16)
- *
- * (don't want to lock it if being called on behalf
- * of lookup--it plays weird locking games depending
- * on whether or not it's looking up ".", "..", etc.
- */
- error = null_node_create(old_vps[0]->v_mount, **vppp, *vppp,
- descp == &vop_lookup_desc ? 0 : 1);
- }
- }
-
- out:
- return (error);
-
-}
-
-/*
- * We handle getattr only to change the fsid.
- */
-int
-null_getattr(v)
- void *v;
-{
- struct vop_getattr_args /* {
- struct vnode *a_vp;
- struct vattr *a_vap;
- struct ucred *a_cred;
- struct proc *a_p;
- } */ *ap = v;
- int error;
- if ((error = null_bypass(ap)) != NULL)
- return (error);
- /* Requires that arguments be restored. */
- ap->a_vap->va_fsid = ap->a_vp->v_mount->mnt_stat.f_fsid.val[0];
- return (0);
-}
-
-/*
- * We must handle open to be able to catch MNT_NODEV and friends.
- */
-int
-null_open(v)
- void *v;
-{
- struct vop_open_args *ap = v;
- struct vnode *vp = ap->a_vp;
- enum vtype lower_type = VTONULL(vp)->null_lowervp->v_type;
-
-
- if (((lower_type == VBLK) || (lower_type == VCHR)) &&
- (vp->v_mount->mnt_flag & MNT_NODEV))
- return ENXIO;
-
- return null_bypass(ap);
-}
-
-int
-null_inactive(v)
- void *v;
-{
- struct vop_inactive_args *ap = v;
-
- /*
- * Do nothing (and _don't_ bypass).
- * Wait to vrele lowervp until reclaim,
- * so that until then our null_node is in the
- * cache and reusable.
- *
- * NEEDSWORK: Someday, consider inactive'ing
- * the lowervp and then trying to reactivate it
- * with capabilities (v_id)
- * like they do in the name lookup cache code.
- * That's too much work for now.
- */
- VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
-
- return (0);
-}
-
-int
-null_reclaim(v)
- void *v;
-{
- struct vop_reclaim_args /* {
- struct vnode *a_vp;
- } */ *ap = v;
- struct vnode *vp = ap->a_vp;
- struct null_node *xp = VTONULL(vp);
- struct vnode *lowervp = xp->null_lowervp;
-
- /*
- * Note: in vop_reclaim, vp->v_op == dead_vnodeop_p,
- * so we can't call VOPs on ourself.
- */
- /* After this assignment, this node will not be re-used. */
- xp->null_lowervp = NULL;
- LIST_REMOVE(xp, null_hash);
- FREE(vp->v_data, M_TEMP);
- vp->v_data = NULL;
- vrele (lowervp);
- return (0);
-}
-
-
-int
-null_print(v)
- void *v;
-{
- struct vop_print_args /* {
- struct vnode *a_vp;
- } */ *ap = v;
- register struct vnode *vp = ap->a_vp;
-
- printf ("\ttag VT_NULLFS, vp=%p, lowervp=%p\n", vp, NULLVPTOLOWERVP(vp));
- vprint("nullfs lowervp", NULLVPTOLOWERVP(vp));
- return (0);
-}
-
-
-/*
- * XXX - vop_strategy must be hand coded because it has no
- * vnode in its arguments.
- */
-int
-null_strategy(v)
- void *v;
-{
- struct vop_strategy_args /* {
- struct buf *a_bp;
- } */ *ap = v;
- struct buf *bp = ap->a_bp;
- int error;
- struct vnode *savedvp;
-
- savedvp = bp->b_vp;
- bp->b_vp = NULLVPTOLOWERVP(bp->b_vp);
-
- error = VOP_STRATEGY(bp);
-
- bp->b_vp = savedvp;
-
- return (error);
-}
-
-
-/*
- * XXX - like vop_strategy, vop_bwrite must be hand coded because it has no
- * vnode in its arguments.
- */
-int
-null_bwrite(v)
- void *v;
-{
- struct vop_bwrite_args /* {
- struct buf *a_bp;
- } */ *ap = v;
- struct buf *bp = ap->a_bp;
- int error;
- struct vnode *savedvp;
-
- savedvp = bp->b_vp;
- bp->b_vp = NULLVPTOLOWERVP(bp->b_vp);
-
- error = VOP_BWRITE(bp);
-
- bp->b_vp = savedvp;
-
- return (error);
-}
-
-/*
- * We need a separate null lock routine, to avoid deadlocks at reclaim time.
- * If a process holds the lower-vnode locked when it tries to reclaim
- * the null upper-vnode, _and_ null_bypass is used as the locking operation,
- * then a process can end up locking against itself.
- * This has been observed when a null mount is set up to "tunnel" beneath a
- * union mount (that setup is useful if you still wish to be able to access
- * the non-union version of either the above or below union layer)
- */
-int
-null_lock(v)
- void *v;
-{
- struct vop_lock_args *ap = v;
-
-#if 0
- vop_generic_lock(ap);
-#endif
- if ((ap->a_flags & LK_TYPE_MASK) == LK_DRAIN)
- return (0);
- ap->a_flags &= ~LK_INTERLOCK;
-
- return (null_bypass((struct vop_generic_args *)ap));
-}
-
-int
-null_unlock(v)
- void *v;
-{
- struct vop_unlock_args *ap = v;
-#if 0
- vop_generic_unlock(ap);
-#endif
- ap->a_flags &= ~LK_INTERLOCK;
-
- return (null_bypass((struct vop_generic_args *)ap));
-}
-
-int
-null_islocked(v)
- void *v;
-{
- /* XXX */
- return (0);
-}
-
-int
-null_lookup(v)
- void *v;
-{
- register struct vop_lookup_args /* {
- struct vnodeop_desc *a_desc;
- struct vnode *a_dvp;
- struct vnode **a_vpp;
- struct componentname *a_cnp;
- } */ *ap = v;
- register int error;
- int flags = ap->a_cnp->cn_flags;
- struct componentname *cnp = ap->a_cnp;
-#if 0
- register struct vnode *dvp, *vp;
- struct proc *p = cnp->cn_proc;
- struct vop_unlock_args unlockargs;
- struct vop_lock_args lockargs;
-#endif
-
-#ifdef NULLFS_DIAGNOSTIC
- printf("null_lookup: dvp=%lx, name='%s'\n",
- ap->a_dvp, cnp->cn_nameptr);
-#endif
-
- if ((flags & ISLASTCN) && (ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY) &&
- (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
- return (EROFS);
- error = null_bypass((struct vop_generic_args *)ap);
- if (error == EJUSTRETURN && (flags & ISLASTCN) &&
- (ap->a_dvp->v_mount->mnt_flag & MNT_RDONLY) &&
- (cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME))
- error = EROFS;
-
-#if 0
- /*
- * We must do the same locking and unlocking at this layer as
- * is done in the layers below us. We could figure this out
- * based on the error return and the LASTCN, LOCKPARENT, and
- * LOCKLEAF flags. However, it is more expidient to just find
- * out the state of the lower level vnodes and set ours to the
- * same state.
- */
- dvp = ap->a_dvp;
- vp = *ap->a_vpp;
- if (dvp == vp)
- return (error);
- if (!VOP_ISLOCKED(dvp)) {
- unlockargs.a_vp = dvp;
- unlockargs.a_flags = 0;
- unlockargs.a_p = p;
- vop_generic_unlock(&unlockargs);
- }
- if (vp != NULLVP && VOP_ISLOCKED(vp)) {
- lockargs.a_vp = vp;
- lockargs.a_flags = LK_SHARED;
- lockargs.a_p = p;
- vop_generic_lock(&lockargs);
- }
-#endif
- return (error);
-}
+#include <miscfs/genfs/layer_extern.h>
/*
* Global vfs data structures
*/
-int (**null_vnodeop_p)(void *);
-struct vnodeopv_entry_desc null_vnodeop_entries[] = {
- { &vop_default_desc, null_bypass },
-
- { &vop_getattr_desc, null_getattr },
- { &vop_inactive_desc, null_inactive },
- { &vop_reclaim_desc, null_reclaim },
- { &vop_print_desc, null_print },
-
- { &vop_open_desc, null_open }, /* mount option handling */
-
- { &vop_lock_desc, null_lock },
- { &vop_unlock_desc, null_unlock },
- { &vop_islocked_desc, null_islocked },
- { &vop_lookup_desc, null_lookup }, /* special locking frob */
-
- { &vop_strategy_desc, null_strategy },
- { &vop_bwrite_desc, null_bwrite },
-
- { NULL, NULL }
+int (**nullfs_vnodeop_p)(void *);
+struct vnodeopv_entry_desc nullfs_vnodeop_entries[] = {
+ { &vop_default_desc, layer_bypass },
+
+ { &vop_lookup_desc, layer_lookup },
+ { &vop_setattr_desc, layer_setattr },
+ { &vop_getattr_desc, layer_getattr },
+ { &vop_access_desc, layer_access },
+ { &vop_lock_desc, layer_lock },
+ { &vop_unlock_desc, layer_unlock },
+ { &vop_islocked_desc, layer_islocked },
+ { &vop_fsync_desc, layer_fsync },
+ { &vop_inactive_desc, layer_inactive },
+ { &vop_reclaim_desc, layer_reclaim },
+ { &vop_print_desc, layer_print },
+
+ { &vop_open_desc, layer_open }, /* mount option handling */
+
+ { &vop_strategy_desc, layer_strategy },
+ { &vop_bwrite_desc, layer_bwrite },
+ { &vop_bmap_desc, layer_bmap },
+
+ { NULL, NULL }
};
-struct vnodeopv_desc null_vnodeop_opv_desc =
- { &null_vnodeop_p, null_vnodeop_entries };
+const struct vnodeopv_desc nullfs_vnodeop_opv_desc =
+ { &nullfs_vnodeop_p, nullfs_vnodeop_entries };