summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorThordur I. Bjornsson <thib@cvs.openbsd.org>2010-09-06 23:44:12 +0000
committerThordur I. Bjornsson <thib@cvs.openbsd.org>2010-09-06 23:44:12 +0000
commit87f3d58d3064a78c9b29faa668f1d98225f01e71 (patch)
treebbc6c4fb3c1748ac72b8b1b8bab76b4e91896fd0 /sys/kern
parenta41bd31e53cce764c5bc6861ce6be4074cc59551 (diff)
End the VOP experiment. Instead of the ridicolusly complicated operation
vector setup that has questionable features (that have, as far as I can tell never been used in practice, atleast not in OpenBSD), remove all the gunk and favor a simple struct full of function pointers that get set directly by each of the filesystems. Removes gobs of ugly code and makes things simpler by a magnitude. The only downside of this is that we loose the vnoperate feature so the spec/fifo operations of the filesystems need to be kept in sync with specfs and fifofs, this is no big deal as the API it self is pretty static. Many thanks to armani@ who pulled an earlier version of this diff to current after c2k10 and Gabriel Kihlman on tech@ for testing. Liked by many. "come on, find your balls" deraadt@.
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/Makefile8
-rw-r--r--sys/kern/spec_vnops.c88
-rw-r--r--sys/kern/vfs_conf.c92
-rw-r--r--sys/kern/vfs_init.c158
-rw-r--r--sys/kern/vfs_subr.c11
-rw-r--r--sys/kern/vfs_sync.c40
-rw-r--r--sys/kern/vfs_vops.c595
7 files changed, 660 insertions, 332 deletions
diff --git a/sys/kern/Makefile b/sys/kern/Makefile
index 5c22814b01f..c4e910b2918 100644
--- a/sys/kern/Makefile
+++ b/sys/kern/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.24 2010/07/01 17:30:25 tedu Exp $
+# $OpenBSD: Makefile,v 1.25 2010/09/06 23:44:10 thib Exp $
# Makefile for kernel tags files, init_sysent, etc.
@@ -8,16 +8,12 @@ ARCH= alpha amd64 armish aviion beagle hp300 \
mvme88k mvmeppc palm sgi socppc \
solbourne sparc sparc64 vax zaurus
-all: init_sysent.c vnode_if.c
+all: init_sysent.c
SYSCALLSRC = makesyscalls.sh syscalls.conf syscalls.master
init_sysent.c syscalls.c ../sys/syscall.h ../sys/syscallargs.h: ${SYSCALLSRC}
sh makesyscalls.sh syscalls.conf syscalls.master
-VNODEIFSRC = vnode_if.sh vnode_if.src
-vnode_if.c ../sys/vnode_if.h: ${VNODEIFSRC}
- sh vnode_if.sh vnode_if.src
-
# Kernel tags:
# tags files are built in the top-level directory for each architecture.
# Links to the correct tags file are placed in each source directory.
diff --git a/sys/kern/spec_vnops.c b/sys/kern/spec_vnops.c
index 11fde4c819b..2b613924840 100644
--- a/sys/kern/spec_vnops.c
+++ b/sys/kern/spec_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: spec_vnops.c,v 1.58 2010/07/26 01:56:27 guenther Exp $ */
+/* $OpenBSD: spec_vnops.c,v 1.59 2010/09/06 23:44:10 thib Exp $ */
/* $NetBSD: spec_vnops.c,v 1.29 1996/04/22 01:42:38 christos Exp $ */
/*
@@ -56,56 +56,44 @@
struct vnode *speclisth[SPECHSZ];
-int (**spec_vnodeop_p)(void *);
-struct vnodeopv_entry_desc spec_vnodeop_entries[] = {
- { &vop_default_desc, eopnotsupp },
- { &vop_lookup_desc, vop_generic_lookup },
- { &vop_create_desc, spec_badop },
- { &vop_mknod_desc, spec_badop },
- { &vop_open_desc, spec_open },
- { &vop_close_desc, spec_close },
- { &vop_access_desc, spec_access },
- { &vop_getattr_desc, spec_getattr },
- { &vop_setattr_desc, spec_setattr },
- { &vop_read_desc, spec_read },
- { &vop_write_desc, spec_write },
- { &vop_ioctl_desc, spec_ioctl },
- { &vop_poll_desc, spec_poll },
- { &vop_kqfilter_desc, spec_kqfilter },
- { &vop_revoke_desc, vop_generic_revoke },
- { &vop_fsync_desc, spec_fsync },
- { &vop_remove_desc, spec_badop },
- { &vop_link_desc, spec_badop },
- { &vop_rename_desc, spec_badop },
- { &vop_mkdir_desc, spec_badop },
- { &vop_rmdir_desc, spec_badop },
- { &vop_symlink_desc, spec_badop },
- { &vop_readdir_desc, spec_badop },
- { &vop_readlink_desc, spec_badop },
- { &vop_abortop_desc, spec_badop },
- { &vop_inactive_desc, spec_inactive },
- { &vop_reclaim_desc, nullop },
- { &vop_lock_desc, vop_generic_lock },
- { &vop_unlock_desc, vop_generic_unlock },
- { &vop_bmap_desc, vop_generic_bmap },
- { &vop_strategy_desc, spec_strategy },
- { &vop_print_desc, spec_print },
- { &vop_islocked_desc, vop_generic_islocked },
- { &vop_pathconf_desc, spec_pathconf },
- { &vop_advlock_desc, spec_advlock },
- { &vop_bwrite_desc, vop_generic_bwrite },
- { NULL, NULL }
+struct vops spec_vops = {
+ .vop_default = eopnotsupp,
+ .vop_lookup = vop_generic_lookup,
+ .vop_create = spec_badop,
+ .vop_mknod = spec_badop,
+ .vop_open = spec_open,
+ .vop_close = spec_close,
+ .vop_access = spec_access,
+ .vop_getattr = spec_getattr,
+ .vop_setattr = spec_setattr,
+ .vop_read = spec_read,
+ .vop_write = spec_write,
+ .vop_ioctl = spec_ioctl,
+ .vop_poll = spec_poll,
+ .vop_kqfilter = spec_kqfilter,
+ .vop_revoke = vop_generic_revoke,
+ .vop_fsync = spec_fsync,
+ .vop_remove = spec_badop,
+ .vop_link = spec_badop,
+ .vop_rename = spec_badop,
+ .vop_mkdir = spec_badop,
+ .vop_rmdir = spec_badop,
+ .vop_symlink = spec_badop,
+ .vop_readdir = spec_badop,
+ .vop_readlink = spec_badop,
+ .vop_abortop = spec_badop,
+ .vop_inactive = spec_inactive,
+ .vop_reclaim = nullop,
+ .vop_lock = vop_generic_lock,
+ .vop_unlock = vop_generic_unlock,
+ .vop_islocked = vop_generic_islocked,
+ .vop_bmap = vop_generic_bmap,
+ .vop_strategy = spec_strategy,
+ .vop_print = spec_print,
+ .vop_pathconf = spec_pathconf,
+ .vop_advlock = spec_advlock,
+ .vop_bwrite = vop_generic_bwrite,
};
-struct vnodeopv_desc spec_vnodeop_opv_desc =
- { &spec_vnodeop_p, spec_vnodeop_entries };
-
-int
-spec_vnoperate(void *v)
-{
- struct vop_generic_args *ap = v;
-
- return (VOCALL(spec_vnodeop_p, ap->a_desc->vdesc_offset, ap));
-}
/*
* Open a special file.
diff --git a/sys/kern/vfs_conf.c b/sys/kern/vfs_conf.c
index 00b00c24939..793881754af 100644
--- a/sys/kern/vfs_conf.c
+++ b/sys/kern/vfs_conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_conf.c,v 1.37 2010/04/20 22:05:43 tedu Exp $ */
+/* $OpenBSD: vfs_conf.c,v 1.38 2010/09/06 23:44:10 thib Exp $ */
/* $NetBSD: vfs_conf.c,v 1.21.4.1 1995/11/01 00:06:26 jtc Exp $ */
/*
@@ -186,93 +186,3 @@ static struct vfsconf vfsconflist[] = {
*/
int maxvfsconf = sizeof(vfsconflist) / sizeof(struct vfsconf);
struct vfsconf *vfsconf = vfsconflist;
-
-
-/*
- * vfs_opv_descs enumerates the list of vnode classes, each with its own
- * vnode operation vector. It is consulted at system boot to build operation
- * vectors. It is NULL terminated.
- */
-extern struct vnodeopv_desc sync_vnodeop_opv_desc;
-extern struct vnodeopv_desc ffs_vnodeop_opv_desc;
-extern struct vnodeopv_desc ffs_specop_opv_desc;
-extern struct vnodeopv_desc ffs_fifoop_opv_desc;
-extern struct vnodeopv_desc mfs_vnodeop_opv_desc;
-extern struct vnodeopv_desc dead_vnodeop_opv_desc;
-extern struct vnodeopv_desc fifo_vnodeop_opv_desc;
-extern struct vnodeopv_desc spec_vnodeop_opv_desc;
-extern struct vnodeopv_desc nfsv2_vnodeop_opv_desc;
-extern struct vnodeopv_desc spec_nfsv2nodeop_opv_desc;
-extern struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc;
-extern struct vnodeopv_desc portal_vnodeop_opv_desc;
-extern struct vnodeopv_desc procfs_vnodeop_opv_desc;
-extern struct vnodeopv_desc cd9660_vnodeop_opv_desc;
-extern struct vnodeopv_desc cd9660_specop_opv_desc;
-extern struct vnodeopv_desc cd9660_fifoop_opv_desc;
-extern struct vnodeopv_desc msdosfs_vnodeop_opv_desc;
-extern struct vnodeopv_desc ext2fs_vnodeop_opv_desc;
-extern struct vnodeopv_desc ext2fs_specop_opv_desc;
-extern struct vnodeopv_desc ext2fs_fifoop_opv_desc;
-extern struct vnodeopv_desc nnpfs_vnodeop_opv_desc;
-extern struct vnodeopv_desc ntfs_vnodeop_opv_desc;
-extern struct vnodeopv_desc udf_vnodeop_opv_desc;
-
-struct vnodeopv_desc *vfs_opv_descs[] = {
- &sync_vnodeop_opv_desc,
-#ifdef FFS
- &ffs_vnodeop_opv_desc,
- &ffs_specop_opv_desc,
-#ifdef FIFO
- &ffs_fifoop_opv_desc,
-#endif
-#endif
- &dead_vnodeop_opv_desc,
-#ifdef FIFO
- &fifo_vnodeop_opv_desc,
-#endif
- &spec_vnodeop_opv_desc,
-#ifdef MFS
- &mfs_vnodeop_opv_desc,
-#endif
-#ifdef NFSCLIENT
- &nfsv2_vnodeop_opv_desc,
- &spec_nfsv2nodeop_opv_desc,
-#ifdef FIFO
- &fifo_nfsv2nodeop_opv_desc,
-#endif
-#endif
-#ifdef PORTAL
- &portal_vnodeop_opv_desc,
-#endif
-#ifdef PROCFS
- &procfs_vnodeop_opv_desc,
-#endif
-#ifdef CD9660
- &cd9660_vnodeop_opv_desc,
- &cd9660_specop_opv_desc,
-#ifdef FIFO
- &cd9660_fifoop_opv_desc,
-#endif
-#endif
-#ifdef MSDOSFS
- &msdosfs_vnodeop_opv_desc,
-#endif
-#ifdef EXT2FS
- &ext2fs_vnodeop_opv_desc,
- &ext2fs_specop_opv_desc,
-#ifdef FIFO
- &ext2fs_fifoop_opv_desc,
-#endif
-#endif
-#ifdef NNPFS
- &nnpfs_vnodeop_opv_desc,
-#endif
-#ifdef NTFS
- &ntfs_vnodeop_opv_desc,
-#endif
-#ifdef UDF
- &udf_vnodeop_opv_desc,
-#endif
-
- NULL
-};
diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c
index 523aa8d4a55..34680ef087a 100644
--- a/sys/kern/vfs_init.c
+++ b/sys/kern/vfs_init.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_init.c,v 1.25 2010/01/14 23:12:11 schwarze Exp $ */
+/* $OpenBSD: vfs_init.c,v 1.26 2010/09/06 23:44:10 thib Exp $ */
/* $NetBSD: vfs_init.c,v 1.6 1996/02/09 19:00:58 christos Exp $ */
/*
@@ -50,150 +50,9 @@
#include <sys/pool.h>
#include <sys/systm.h>
-/* a list of lists of vnodeops defns */
-extern struct vnodeopv_desc *vfs_opv_descs[];
-
-/* and the operations they perform */
-extern struct vnodeop_desc *vfs_op_descs[];
-
struct pool namei_pool;
-/*
- * This code doesn't work if the defn is **vnodop_defns with cc.
- * The problem is because of the compiler sometimes putting in an
- * extra level of indirection for arrays. It's an interesting
- * "feature" of C.
- */
-int vfs_opv_numops;
-
-typedef int (*PFI)(void *);
-
-/*
- * vfs_init.c
- *
- * Allocate and fill in operations vectors.
- *
- * An undocumented feature of this approach to defining operations is that
- * there can be multiple entries in vfs_opv_descs for the same operations
- * vector. This allows third parties to extend the set of operations
- * supported by another layer in a binary compatible way. For example,
- * assume that NFS needed to be modified to support Ficus. NFS has an entry
- * (probably nfs_vnopdeop_decls) declaring all the operations NFS supports by
- * default. Ficus could add another entry (ficus_nfs_vnodeop_decl_entensions)
- * listing those new operations Ficus adds to NFS, all without modifying the
- * NFS code. (Of course, the OTW NFS protocol still needs to be munged, but
- * that is a(whole)nother story.) This is a feature.
- */
-
-/*
- * Allocate and init the vector, if it needs it.
- * Also handle backwards compatibility.
- */
-void
-vfs_opv_init_explicit(struct vnodeopv_desc *vfs_opv_desc)
-{
- int (**opv_desc_vector)(void *);
- struct vnodeopv_entry_desc *opve_descp;
-
- opv_desc_vector = *(vfs_opv_desc->opv_desc_vector_p);
-
- if (opv_desc_vector == NULL) {
- /* XXX - shouldn't be M_VNODE */
- opv_desc_vector = malloc(vfs_opv_numops * sizeof(PFI),
- M_VNODE, M_WAITOK|M_ZERO);
- *(vfs_opv_desc->opv_desc_vector_p) = opv_desc_vector;
- }
-
- for (opve_descp = vfs_opv_desc->opv_desc_ops;
- opve_descp->opve_op; opve_descp++) {
- /*
- * Sanity check: is this operation listed
- * in the list of operations? We check this
- * by seeing if its offset is zero. Since
- * the default routine should always be listed
- * first, it should be the only one with a zero
- * offset. Any other operation with a zero
- * offset is probably not listed in
- * vfs_op_descs, and so is probably an error.
- *
- * A panic here means the layer programmer
- * has committed the all-too common bug
- * of adding a new operation to the layer's
- * list of vnode operations but
- * not adding the operation to the system-wide
- * list of supported operations.
- */
- if (opve_descp->opve_op->vdesc_offset == 0 &&
- opve_descp->opve_op != VDESC(vop_default)) {
- printf("operation %s not listed in %s.\n",
- opve_descp->opve_op->vdesc_name, "vfs_op_descs");
- panic ("vfs_opv_init: bad operation");
- }
-
- /*
- * Fill in this entry.
- */
- opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
- opve_descp->opve_impl;
- }
-}
-
-void
-vfs_opv_init_default(struct vnodeopv_desc *vfs_opv_desc)
-{
- int j;
- int (**opv_desc_vector)(void *);
-
- opv_desc_vector = *(vfs_opv_desc->opv_desc_vector_p);
-
- /*
- * Force every operations vector to have a default routine.
- */
- if (opv_desc_vector[VOFFSET(vop_default)] == NULL)
- panic("vfs_opv_init: operation vector without default routine.");
-
- for (j = 0; j < vfs_opv_numops; j++)
- if (opv_desc_vector[j] == NULL)
- opv_desc_vector[j] =
- opv_desc_vector[VOFFSET(vop_default)];
-}
-
-/* Initialize known vnode operations vectors. */
-void
-vfs_op_init(void)
-{
- int i;
-
- /* Set all vnode vectors to a well known value. */
- for (i = 0; vfs_opv_descs[i]; i++)
- *(vfs_opv_descs[i]->opv_desc_vector_p) = NULL;
-
- /*
- * Figure out how many ops there are by counting the table,
- * and assign each its offset.
- */
- for (vfs_opv_numops = 0, i = 0; vfs_op_descs[i]; i++) {
- vfs_op_descs[i]->vdesc_offset = vfs_opv_numops;
- vfs_opv_numops++;
- }
-
- /* Allocate the dynamic vectors and fill them in. */
- for (i = 0; vfs_opv_descs[i]; i++)
- vfs_opv_init_explicit(vfs_opv_descs[i]);
-
- /*
- * Finally, go back and replace unfilled routines
- * with their default.
- */
- for (i = 0; vfs_opv_descs[i]; i++)
- vfs_opv_init_default(vfs_opv_descs[i]);
-
-}
-
-
-/*
- * Initialize the vnode structures and initialize each file system type.
- */
+/* Initialize the vnode structures and initialize each file system type. */
void
vfsinit(void)
{
@@ -204,18 +63,11 @@ vfsinit(void)
pool_init(&namei_pool, MAXPATHLEN, 0, 0, 0, "namei",
&pool_allocator_nointr);
- /*
- * Initialize the vnode table
- */
+ /* Initialize the vnode table. */
vntblinit();
- /*
- * Initialize the vnode name cache
- */
+
+ /* Initialize the vnode name cache. */
nchinit();
- /*
- * Build vnode operation vectors.
- */
- vfs_op_init();
/*
* Stop using vfsconf and maxvfsconf as a temporary storage,
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 9de92d955a1..f8b89c02730 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_subr.c,v 1.189 2010/08/12 15:00:17 oga Exp $ */
+/* $OpenBSD: vfs_subr.c,v 1.190 2010/09/06 23:44:10 thib Exp $ */
/* $NetBSD: vfs_subr.c,v 1.53 1996/04/22 01:39:13 christos Exp $ */
/*
@@ -301,14 +301,13 @@ vattr_null(struct vattr *vap)
/*
* Routines having to do with the management of the vnode table.
*/
-extern int (**dead_vnodeop_p)(void *);
long numvnodes;
/*
* Return the next vnode from the free list.
*/
int
-getnewvnode(enum vtagtype tag, struct mount *mp, int (**vops)(void *),
+getnewvnode(enum vtagtype tag, struct mount *mp, struct vops *vops,
struct vnode **vpp)
{
struct proc *p = curproc;
@@ -464,7 +463,7 @@ getdevvp(dev_t dev, struct vnode **vpp, enum vtype type)
*vpp = NULLVP;
return (0);
}
- error = getnewvnode(VT_NON, NULL, spec_vnodeop_p, &nvp);
+ error = getnewvnode(VT_NON, NULL, &spec_vops, &nvp);
if (error) {
*vpp = NULLVP;
return (error);
@@ -861,7 +860,7 @@ vflush_vnode(struct vnode *vp, void *arg) {
vgonel(vp, p);
} else {
vclean(vp, 0, p);
- vp->v_op = spec_vnodeop_p;
+ vp->v_op = &spec_vops;
insmntque(vp, (struct mount *)0);
}
return (0);
@@ -967,7 +966,7 @@ vclean(struct vnode *vp, int flags, struct proc *p)
/*
* Done with purge, notify sleepers of the grim news.
*/
- vp->v_op = dead_vnodeop_p;
+ vp->v_op = &dead_vops;
VN_KNOTE(vp, NOTE_REVOKE);
vp->v_tag = VT_NON;
vp->v_flag &= ~VXLOCK;
diff --git a/sys/kern/vfs_sync.c b/sys/kern/vfs_sync.c
index fe8b76f987e..180d6a22d42 100644
--- a/sys/kern/vfs_sync.c
+++ b/sys/kern/vfs_sync.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vfs_sync.c,v 1.46 2010/07/03 03:45:16 thib Exp $ */
+/* $OpenBSD: vfs_sync.c,v 1.47 2010/09/06 23:44:10 thib Exp $ */
/*
* Portions of this code are:
@@ -254,33 +254,21 @@ speedup_syncer(void)
return 0;
}
-/*
- * Routine to create and manage a filesystem syncer vnode.
- */
-#define sync_close nullop
+/* Routine to create and manage a filesystem syncer vnode. */
int sync_fsync(void *);
int sync_inactive(void *);
-#define sync_reclaim nullop
-#define sync_lock vop_generic_lock
-#define sync_unlock vop_generic_unlock
int sync_print(void *);
-#define sync_islocked vop_generic_islocked
-
-int (**sync_vnodeop_p)(void *);
-struct vnodeopv_entry_desc sync_vnodeop_entries[] = {
- { &vop_default_desc, eopnotsupp },
- { &vop_close_desc, sync_close },
- { &vop_fsync_desc, sync_fsync },
- { &vop_inactive_desc, sync_inactive },
- { &vop_reclaim_desc, sync_reclaim },
- { &vop_lock_desc, sync_lock },
- { &vop_unlock_desc, sync_unlock },
- { &vop_print_desc, sync_print },
- { &vop_islocked_desc, sync_islocked },
- { (struct vnodeop_desc*)NULL, (int(*)(void *))NULL }
-};
-struct vnodeopv_desc sync_vnodeop_opv_desc = {
- &sync_vnodeop_p, sync_vnodeop_entries
+
+struct vops sync_vops = {
+ .vop_default = eopnotsupp,
+ .vop_close = nullop,
+ .vop_fsync = sync_fsync,
+ .vop_inactive = sync_inactive,
+ .vop_reclaim = nullop,
+ .vop_lock = vop_generic_lock,
+ .vop_unlock = vop_generic_unlock,
+ .vop_islocked = vop_generic_islocked,
+ .vop_print = sync_print
};
/*
@@ -294,7 +282,7 @@ vfs_allocate_syncvnode(struct mount *mp)
int error;
/* Allocate a new vnode */
- if ((error = getnewvnode(VT_VFS, mp, sync_vnodeop_p, &vp)) != 0) {
+ if ((error = getnewvnode(VT_VFS, mp, &sync_vops, &vp)) != 0) {
mp->mnt_syncer = NULL;
return (error);
}
diff --git a/sys/kern/vfs_vops.c b/sys/kern/vfs_vops.c
new file mode 100644
index 00000000000..07b854b9ea0
--- /dev/null
+++ b/sys/kern/vfs_vops.c
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 2010 Thordur I. Bjornsson <thib@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * 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 University 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 REGENTS AND CONTRIBUTORS 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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+
+#ifdef VFSDEBUG
+#define ASSERT_VP_ISLOCKED(vp) do { \
+ if (((vp)->v_flag & VLOCKSWORK) && !VOP_ISLOCKED(vp)) \
+ VOP_PRINT(vp); \
+ panic("vp not locked"); \
+} while (0)
+#else
+#define ASSERT_VP_ISLOCKED(vp) /* nothing */
+#endif
+
+int
+VOP_ISLOCKED(struct vnode *vp)
+{
+ struct vop_islocked_args a;
+ a.a_vp = vp;
+
+ if (vp->v_op->vop_islocked == NULL)
+ return ((vp->v_op->vop_default)(&a));
+
+ return ((vp->v_op->vop_islocked)(&a));
+}
+
+int
+VOP_LOOKUP(struct vnode *dvp, struct vnode **vpp,
+ struct componentname *cnp)
+{
+ struct vop_lookup_args a;
+ a.a_dvp = dvp;
+ a.a_vpp = vpp;
+ a.a_cnp = cnp;
+
+ if (dvp->v_op->vop_lookup == NULL)
+ return ((dvp->v_op->vop_default)(&a));
+
+ return ((dvp->v_op->vop_lookup)(&a));
+}
+
+int
+VOP_CREATE(struct vnode *dvp, struct vnode **vpp,
+ struct componentname *cnp, struct vattr *vap)
+{
+ struct vop_create_args a;
+ a.a_dvp = dvp;
+ a.a_vpp = vpp;
+ a.a_cnp = cnp;
+ a.a_vap = vap;
+
+ ASSERT_VP_ISLOCKED(dvp);
+
+ if (dvp->v_op->vop_create == NULL)
+ return ((dvp->v_op->vop_default)(&a));
+ return ((dvp->v_op->vop_create)(&a));
+}
+
+int
+VOP_MKNOD(struct vnode *dvp, struct vnode **vpp,
+ struct componentname *cnp, struct vattr *vap)
+{
+ struct vop_mknod_args a;
+ a.a_dvp = dvp;
+ a.a_vpp = vpp;
+ a.a_cnp = cnp;
+ a.a_vap = vap;
+
+ ASSERT_VP_ISLOCKED(dvp);
+
+ if (dvp->v_op->vop_mknod == NULL)
+ return ((dvp->v_op->vop_default)(&a));
+ return ((dvp->v_op->vop_mknod)(&a));
+}
+
+int
+VOP_OPEN(struct vnode *vp, int mode, struct ucred *cred, struct proc *p)
+{
+ struct vop_open_args a;
+ a.a_vp = vp;
+ a.a_mode = mode;
+ a.a_cred = cred;
+ a.a_p = p;
+
+ if (vp->v_op->vop_open == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_open)(&a));
+}
+
+int
+VOP_CLOSE(struct vnode *vp, int fflag, struct ucred *cred, struct proc *p)
+{
+ struct vop_close_args a;
+ a.a_vp = vp;
+ a.a_fflag = fflag;
+ a.a_cred = cred;
+ a.a_p = p;
+
+ ASSERT_VP_ISLOCKED(vp);
+
+ if (vp->v_op->vop_close == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_close)(&a));
+}
+
+int
+VOP_ACCESS(struct vnode *vp, int mode, struct ucred *cred, struct proc *p)
+{
+ struct vop_access_args a;
+ a.a_vp = vp;
+ a.a_mode = mode;
+ a.a_cred = cred;
+ a.a_p = p;
+
+ ASSERT_VP_ISLOCKED(vp);
+
+ if (vp->v_op->vop_access == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_access)(&a));
+}
+
+int
+VOP_GETATTR(struct vnode *vp, struct vattr *vap, struct ucred *cred,
+ struct proc *p)
+{
+ struct vop_getattr_args a;
+ a.a_vp = vp;
+ a.a_vap = vap;
+ a.a_cred = cred;
+ a.a_p = p;
+
+ if (vp->v_op->vop_getattr == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_getattr)(&a));
+}
+
+int
+VOP_SETATTR(struct vnode *vp, struct vattr *vap, struct ucred *cred,
+ struct proc *p)
+{
+ struct vop_setattr_args a;
+ a.a_vp = vp;
+ a.a_vap = vap;
+ a.a_cred = cred;
+ a.a_p = p;
+
+ ASSERT_VP_ISLOCKED(vp);
+
+ if (vp->v_op->vop_setattr == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_setattr)(&a));
+}
+
+int
+VOP_READ(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred)
+{
+ struct vop_read_args a;
+ a.a_vp = vp;
+ a.a_uio = uio;
+ a.a_ioflag = ioflag;
+ a.a_cred = cred;
+
+ ASSERT_VP_ISLOCKED(vp);
+
+ if (vp->v_op->vop_read == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_read)(&a));
+}
+
+int
+VOP_WRITE(struct vnode *vp, struct uio *uio, int ioflag,
+ struct ucred *cred)
+{
+ struct vop_write_args a;
+ a.a_vp = vp;
+ a.a_uio = uio;
+ a.a_ioflag = ioflag;
+ a.a_cred = cred;
+
+ ASSERT_VP_ISLOCKED(vp);
+
+ if (vp->v_op->vop_write == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_write)(&a));
+}
+
+int
+VOP_IOCTL(struct vnode *vp, u_long command, void *data, int fflag,
+ struct ucred *cred, struct proc *p)
+{
+ struct vop_ioctl_args a;
+ a.a_vp = vp;
+ a.a_command = command;
+ a.a_data = data;
+ a.a_fflag = fflag;
+ a.a_cred = cred;
+ a.a_p = p;
+
+ if (vp->v_op->vop_ioctl == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_ioctl)(&a));
+}
+
+int
+VOP_POLL(struct vnode *vp, int events, struct proc *p)
+{
+ struct vop_poll_args a;
+ a.a_vp = vp;
+ a.a_events = events;
+ a.a_p = p;
+
+ if (vp->v_op->vop_poll == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_poll)(&a));
+}
+
+int
+VOP_KQFILTER(struct vnode *vp, struct knote *kn)
+{
+ struct vop_kqfilter_args a;
+ a.a_vp = vp;
+ a.a_kn = kn;
+
+ if (vp->v_op->vop_kqfilter == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_kqfilter)(&a));
+}
+
+int
+VOP_REVOKE(struct vnode *vp, int flags)
+{
+ struct vop_revoke_args a;
+ a.a_vp = vp;
+ a.a_flags = flags;
+
+ if (vp->v_op->vop_revoke == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_revoke)(&a));
+}
+
+int
+VOP_FSYNC(struct vnode *vp, struct ucred *cred, int waitfor,
+ struct proc *p)
+{
+ struct vop_fsync_args a;
+ a.a_vp = vp;
+ a.a_cred = cred;
+ a.a_waitfor = waitfor;
+ a.a_p = p;
+
+ ASSERT_VP_ISLOCKED(vp);
+
+ if (vp->v_op->vop_fsync == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_fsync)(&a));
+}
+
+int
+VOP_REMOVE(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
+{
+ struct vop_remove_args a;
+ a.a_dvp = dvp;
+ a.a_vp = vp;
+ a.a_cnp = cnp;
+
+ ASSERT_VP_ISLOCKED(dvp);
+ ASSERT_VP_ISLOCKED(vp);
+
+ if (dvp->v_op->vop_remove == NULL)
+ return ((dvp->v_op->vop_default)(&a));
+ return ((dvp->v_op->vop_remove)(&a));
+}
+
+int
+VOP_LINK(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
+{
+ struct vop_link_args a;
+ a.a_dvp = dvp;
+ a.a_vp = vp;
+ a.a_cnp = cnp;
+
+ ASSERT_VP_ISLOCKED(dvp);
+
+ if (dvp->v_op->vop_link == NULL)
+ return ((dvp->v_op->vop_default)(&a));
+ return ((dvp->v_op->vop_link)(&a));
+}
+
+int
+VOP_RENAME(struct vnode *fdvp, struct vnode *fvp,
+ struct componentname *fcnp, struct vnode *tdvp, struct vnode *tvp,
+ struct componentname *tcnp)
+{
+ struct vop_rename_args a;
+ a.a_fdvp = fdvp;
+ a.a_fvp = fvp;
+ a.a_fcnp = fcnp;
+ a.a_tdvp = tdvp;
+ a.a_tvp = tvp;
+ a.a_tcnp = tcnp;
+
+ ASSERT_VP_ISLOCKED(tdvp);
+
+ if (fdvp->v_op->vop_rename == NULL)
+ return ((fdvp->v_op->vop_default)(&a));
+ return ((fdvp->v_op->vop_rename)(&a));
+}
+
+int
+VOP_MKDIR(struct vnode *dvp, struct vnode **vpp,
+ struct componentname *cnp, struct vattr *vap)
+{
+ struct vop_mkdir_args a;
+ a.a_dvp = dvp;
+ a.a_vpp = vpp;
+ a.a_cnp = cnp;
+ a.a_vap = vap;
+
+ ASSERT_VP_ISLOCKED(dvp);
+
+ if (dvp->v_op->vop_mkdir == NULL)
+ return ((dvp->v_op->vop_default)(&a));
+ return ((dvp->v_op->vop_mkdir)(&a));
+}
+
+int
+VOP_RMDIR(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
+{
+ struct vop_rmdir_args a;
+ a.a_dvp = dvp;
+ a.a_vp = vp;
+ a.a_cnp = cnp;
+
+ ASSERT_VP_ISLOCKED(dvp);
+ ASSERT_VP_ISLOCKED(vp);
+
+ if (dvp->v_op->vop_rmdir == NULL)
+ return ((dvp->v_op->vop_default)(&a));
+ return ((dvp->v_op->vop_rmdir)(&a));
+}
+
+int
+VOP_SYMLINK(struct vnode *dvp, struct vnode **vpp,
+ struct componentname *cnp, struct vattr *vap, char *target)
+{
+ struct vop_symlink_args a;
+ a.a_dvp = dvp;
+ a.a_vpp = vpp;
+ a.a_cnp = cnp;
+ a.a_vap = vap;
+ a.a_target = target;
+
+ ASSERT_VP_ISLOCKED(dvp);
+
+ if (dvp->v_op->vop_symlink == NULL)
+ return ((dvp->v_op->vop_default)(&a));
+ return ((dvp->v_op->vop_symlink)(&a));
+}
+
+int
+VOP_READDIR(struct vnode *vp, struct uio *uio, struct ucred *cred,
+ int *eofflag, int *ncookies, u_long **cookies)
+{
+ struct vop_readdir_args a;
+ a.a_vp = vp;
+ a.a_uio = uio;
+ a.a_cred = cred;
+ a.a_eofflag = eofflag;
+ a.a_ncookies = ncookies;
+ a.a_cookies = cookies;
+
+ ASSERT_VP_ISLOCKED(vp);
+
+ if (vp->v_op->vop_readdir == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_readdir)(&a));
+}
+
+int
+VOP_READLINK(struct vnode *vp, struct uio *uio, struct ucred *cred)
+{
+ struct vop_readlink_args a;
+ a.a_vp = vp;
+ a.a_uio = uio;
+ a.a_cred = cred;
+
+ ASSERT_VP_ISLOCKED(vp);
+
+ if (vp->v_op->vop_readlink == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_readlink)(&a));
+}
+
+int
+VOP_ABORTOP(struct vnode *dvp, struct componentname *cnp)
+{
+ struct vop_abortop_args a;
+ a.a_dvp = dvp;
+ a.a_cnp = cnp;
+
+ if (dvp->v_op->vop_abortop == NULL)
+ return ((dvp->v_op->vop_default)(&a));
+ return ((dvp->v_op->vop_abortop)(&a));
+}
+
+int
+VOP_INACTIVE(struct vnode *vp, struct proc *p)
+{
+ struct vop_inactive_args a;
+ a.a_vp = vp;
+ a.a_p = p;
+
+ ASSERT_VP_ISLOCKED(vp);
+
+ if (vp->v_op->vop_inactive == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_inactive)(&a));
+}
+
+int
+VOP_RECLAIM(struct vnode *vp, struct proc *p)
+{
+ struct vop_reclaim_args a;
+ a.a_vp = vp;
+ a.a_p = p;
+
+ if (vp->v_op->vop_reclaim == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_reclaim)(&a));
+}
+
+int
+VOP_LOCK(struct vnode *vp, int flags, struct proc *p)
+{
+ struct vop_lock_args a;
+ a.a_vp = vp;
+ a.a_flags = flags;
+ a.a_p = p;
+
+ if (vp->v_op->vop_lock == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_lock)(&a));
+}
+
+int
+VOP_UNLOCK(struct vnode *vp, int flags, struct proc *p)
+{
+ struct vop_unlock_args a;
+ a.a_vp = vp;
+ a.a_flags = flags;
+ a.a_p = p;
+
+ if (vp->v_op->vop_unlock == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_unlock)(&a));
+}
+
+int
+VOP_BMAP(struct vnode *vp, daddr64_t bn, struct vnode **vpp,
+ daddr64_t *bnp, int *runp)
+{
+ struct vop_bmap_args a;
+ a.a_vp = vp;
+ a.a_bn = bn;
+ a.a_vpp = vpp;
+ a.a_bnp = bnp;
+ a.a_runp = runp;
+
+ ASSERT_VP_ISLOCKED(vp);
+
+ if (vp->v_op->vop_bmap == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_bmap)(&a));
+}
+
+int
+VOP_PRINT(struct vnode *vp)
+{
+ struct vop_print_args a;
+ a.a_vp = vp;
+
+ if (vp->v_op->vop_print == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_print)(&a));
+}
+
+int
+VOP_PATHCONF(struct vnode *vp, int name, register_t *retval)
+{
+ struct vop_pathconf_args a;
+ a.a_vp = vp;
+ a.a_name = name;
+ a.a_retval = retval;
+
+ ASSERT_VP_ISLOCKED(vp);
+
+ if (vp->v_op->vop_pathconf == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_pathconf)(&a));
+}
+
+int
+VOP_ADVLOCK(struct vnode *vp, void *id, int op, struct flock *fl, int flags)
+{
+ struct vop_advlock_args a;
+ a.a_vp = vp;
+ a.a_id = id;
+ a.a_op = op;
+ a.a_fl = fl;
+ a.a_flags = flags;
+
+ if (vp->v_op->vop_advlock == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_advlock)(&a));
+}
+
+int
+VOP_REALLOCBLKS(struct vnode *vp, struct cluster_save *buflist)
+{
+ struct vop_reallocblks_args a;
+ a.a_vp = vp;
+ a.a_buflist = buflist;
+
+ ASSERT_VP_ISLOCKED(vp);
+
+ if (vp->v_op->vop_reallocblks == NULL)
+ return ((vp->v_op->vop_default)(&a));
+ return ((vp->v_op->vop_reallocblks)(&a));
+}
+
+int
+VOP_STRATEGY(struct buf *bp)
+{
+ struct vop_strategy_args a;
+ a.a_bp = bp;
+
+ if (bp->b_vp->v_op->vop_strategy == NULL)
+ return ((bp->b_vp->v_op->vop_default)(&a));
+ return ((bp->b_vp->v_op->vop_strategy)(&a));
+}
+
+int
+VOP_BWRITE(struct buf *bp)
+{
+ struct vop_bwrite_args a;
+ a.a_bp = bp;
+
+ if (bp->b_vp->v_op->vop_bwrite == NULL)
+ return ((bp->b_vp->v_op->vop_default)(&a));
+ return ((bp->b_vp->v_op->vop_bwrite)(&a));
+}
+/* End of special cases. */