Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c =================================================================== --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ctldir.c @@ -826,6 +826,7 @@ .vop_pathconf = zfsctl_common_pathconf, .vop_getacl = zfsctl_common_getacl, }; +VFS_VOP_VECTOR_REGISTER(zfsctl_ops_root); static int zfsctl_snapshot_zname(vnode_t *vp, const char *name, int len, char *zname) @@ -1159,6 +1160,7 @@ .vop_pathconf = zfsctl_common_pathconf, .vop_getacl = zfsctl_common_getacl, }; +VFS_VOP_VECTOR_REGISTER(zfsctl_ops_snapdir); static int zfsctl_snapshot_inactive(ap) @@ -1257,6 +1259,7 @@ .vop_advlockpurge = vop_stdadvlockpurge, /* called by vgone */ .vop_print = zfsctl_common_print, }; +VFS_VOP_VECTOR_REGISTER(zfsctl_ops_snapshot); int zfsctl_lookup_objset(vfs_t *vfsp, uint64_t objsetid, zfsvfs_t **zfsvfsp) Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c =================================================================== --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c @@ -5995,6 +5995,7 @@ .vop_unlock = vop_unlock, .vop_islocked = vop_islocked, }; +VFS_VOP_VECTOR_REGISTER(zfs_vnodeops); struct vop_vector zfs_fifoops = { .vop_default = &fifo_specops, @@ -6012,6 +6013,7 @@ .vop_setacl = zfs_freebsd_setacl, .vop_aclcheck = zfs_freebsd_aclcheck, }; +VFS_VOP_VECTOR_REGISTER(zfs_fifoops); /* * special share hidden files vnode operations template @@ -6024,3 +6026,4 @@ .vop_fid = zfs_freebsd_fid, .vop_pathconf = zfs_freebsd_pathconf, }; +VFS_VOP_VECTOR_REGISTER(zfs_shareops); Index: sys/fs/autofs/autofs_vnops.c =================================================================== --- sys/fs/autofs/autofs_vnops.c +++ sys/fs/autofs/autofs_vnops.c @@ -554,6 +554,7 @@ .vop_write = VOP_EOPNOTSUPP, .vop_reclaim = autofs_reclaim, }; +VFS_VOP_VECTOR_REGISTER(autofs_vnodeops); int autofs_node_new(struct autofs_node *parent, struct autofs_mount *amp, Index: sys/fs/cd9660/cd9660_vnops.c =================================================================== --- sys/fs/cd9660/cd9660_vnops.c +++ sys/fs/cd9660/cd9660_vnops.c @@ -906,6 +906,7 @@ .vop_vptofh = cd9660_vptofh, .vop_getpages = cd9660_getpages, }; +VFS_VOP_VECTOR_REGISTER(cd9660_vnodeops); /* * Special device vnode ops @@ -920,3 +921,4 @@ .vop_setattr = cd9660_setattr, .vop_vptofh = cd9660_vptofh, }; +VFS_VOP_VECTOR_REGISTER(cd9660_fifoops); Index: sys/fs/deadfs/dead_vnops.c =================================================================== --- sys/fs/deadfs/dead_vnops.c +++ sys/fs/deadfs/dead_vnops.c @@ -80,6 +80,7 @@ .vop_unset_text = dead_unset_text, .vop_write = dead_write, }; +VFS_VOP_VECTOR_REGISTER(dead_vnodeops); static int dead_getwritemount(struct vop_getwritemount_args *ap) Index: sys/fs/devfs/devfs_vnops.c =================================================================== --- sys/fs/devfs/devfs_vnops.c +++ sys/fs/devfs/devfs_vnops.c @@ -1928,6 +1928,7 @@ .vop_symlink = devfs_symlink, .vop_vptocnp = devfs_vptocnp, }; +VFS_VOP_VECTOR_REGISTER(devfs_vnodeops); /* Vops for VCHR vnodes in /dev. */ static struct vop_vector devfs_specops = { @@ -1965,6 +1966,7 @@ .vop_vptocnp = devfs_vptocnp, .vop_write = dead_write, }; +VFS_VOP_VECTOR_REGISTER(devfs_specops); /* * Our calling convention to the device drivers used to be that we passed Index: sys/fs/ext2fs/ext2_vnops.c =================================================================== --- sys/fs/ext2fs/ext2_vnops.c +++ sys/fs/ext2fs/ext2_vnops.c @@ -182,6 +182,7 @@ #endif /* UFS_ACL */ .vop_vptofh = ext2_vptofh, }; +VFS_VOP_VECTOR_REGISTER(ext2_vnodeops); struct vop_vector ext2_fifoops = { .vop_default = &fifo_specops, @@ -199,6 +200,7 @@ .vop_write = VOP_PANIC, .vop_vptofh = ext2_vptofh, }; +VFS_VOP_VECTOR_REGISTER(ext2_fifoops); /* * A virgin directory (no blushing please). Index: sys/fs/fdescfs/fdesc_vnops.c =================================================================== --- sys/fs/fdescfs/fdesc_vnops.c +++ sys/fs/fdescfs/fdesc_vnops.c @@ -91,6 +91,7 @@ .vop_reclaim = fdesc_reclaim, .vop_setattr = fdesc_setattr, }; +VFS_VOP_VECTOR_REGISTER(fdesc_vnodeops); static void fdesc_insmntque_dtr(struct vnode *, void *); static void fdesc_remove_entry(struct fdescnode *); Index: sys/fs/fifofs/fifo_vnops.c =================================================================== --- sys/fs/fifofs/fifo_vnops.c +++ sys/fs/fifofs/fifo_vnops.c @@ -102,6 +102,7 @@ .vop_symlink = VOP_PANIC, .vop_write = VOP_PANIC, }; +VFS_VOP_VECTOR_REGISTER(fifo_specops); /* * Dispose of fifo resources. Index: sys/fs/fuse/fuse_vnops.c =================================================================== --- sys/fs/fuse/fuse_vnops.c +++ sys/fs/fuse/fuse_vnops.c @@ -174,6 +174,7 @@ .vop_write = VOP_PANIC, .vop_vptofh = fuse_vnop_vptofh, }; +VFS_VOP_VECTOR_REGISTER(fuse_fifoops); struct vop_vector fuse_vnops = { .vop_allocate = VOP_EINVAL, @@ -223,6 +224,7 @@ .vop_print = fuse_vnop_print, .vop_vptofh = fuse_vnop_vptofh, }; +VFS_VOP_VECTOR_REGISTER(fuse_vnops); uma_zone_t fuse_pbuf_zone; Index: sys/fs/msdosfs/msdosfs_vnops.c =================================================================== --- sys/fs/msdosfs/msdosfs_vnops.c +++ sys/fs/msdosfs/msdosfs_vnops.c @@ -1962,3 +1962,4 @@ .vop_write = msdosfs_write, .vop_vptofh = msdosfs_vptofh, }; +VFS_VOP_VECTOR_REGISTER(msdosfs_vnodeops); Index: sys/fs/nfsclient/nfs_clvnops.c =================================================================== --- sys/fs/nfsclient/nfs_clvnops.c +++ sys/fs/nfsclient/nfs_clvnops.c @@ -182,6 +182,7 @@ .vop_getacl = nfs_getacl, .vop_setacl = nfs_setacl, }; +VFS_VOP_VECTOR_REGISTER(newnfs_vnodeops_nosig); static int nfs_vnodeops_bypass(struct vop_generic_args *a) @@ -194,6 +195,7 @@ .vop_default = &default_vnodeops, .vop_bypass = nfs_vnodeops_bypass, }; +VFS_VOP_VECTOR_REGISTER(newnfs_vnodeops); static struct vop_vector newnfs_fifoops_nosig = { .vop_default = &fifo_specops, @@ -209,6 +211,7 @@ .vop_setattr = nfs_setattr, .vop_write = nfsfifo_write, }; +VFS_VOP_VECTOR_REGISTER(newnfs_fifoops_nosig); static int nfs_fifoops_bypass(struct vop_generic_args *a) @@ -221,6 +224,7 @@ .vop_default = &default_vnodeops, .vop_bypass = nfs_fifoops_bypass, }; +VFS_VOP_VECTOR_REGISTER(newnfs_fifoops); static int nfs_mknodrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, struct vattr *vap); Index: sys/fs/nullfs/null_vnops.c =================================================================== --- sys/fs/nullfs/null_vnops.c +++ sys/fs/nullfs/null_vnops.c @@ -943,3 +943,4 @@ .vop_vptofh = null_vptofh, .vop_add_writecount = null_add_writecount, }; +VFS_VOP_VECTOR_REGISTER(null_vnodeops); Index: sys/fs/pseudofs/pseudofs_vnops.c =================================================================== --- sys/fs/pseudofs/pseudofs_vnops.c +++ sys/fs/pseudofs/pseudofs_vnops.c @@ -1095,3 +1095,4 @@ .vop_write = pfs_write, /* XXX I've probably forgotten a few that need VOP_EOPNOTSUPP */ }; +VFS_VOP_VECTOR_REGISTER(pfs_vnodeops); Index: sys/fs/smbfs/smbfs_vnops.c =================================================================== --- sys/fs/smbfs/smbfs_vnops.c +++ sys/fs/smbfs/smbfs_vnops.c @@ -114,6 +114,7 @@ .vop_symlink = smbfs_symlink, .vop_write = smbfs_write, }; +VFS_VOP_VECTOR_REGISTER(smbfs_vnodeops); static int smbfs_access(ap) Index: sys/fs/tmpfs/tmpfs_fifoops.c =================================================================== --- sys/fs/tmpfs/tmpfs_fifoops.c +++ sys/fs/tmpfs/tmpfs_fifoops.c @@ -75,3 +75,4 @@ .vop_pathconf = tmpfs_pathconf, .vop_print = tmpfs_print, }; +VFS_VOP_VECTOR_REGISTER(tmpfs_fifoop_entries); Index: sys/fs/tmpfs/tmpfs_vnops.c =================================================================== --- sys/fs/tmpfs/tmpfs_vnops.c +++ sys/fs/tmpfs/tmpfs_vnops.c @@ -1636,6 +1636,7 @@ .vop_unlock = vop_unlock, .vop_islocked = vop_islocked, }; +VFS_VOP_VECTOR_REGISTER(tmpfs_vnodeop_entries); /* * Same vector for mounts which do not use namecache. @@ -1644,3 +1645,4 @@ .vop_default = &tmpfs_vnodeop_entries, .vop_lookup = tmpfs_lookup, }; +VFS_VOP_VECTOR_REGISTER(tmpfs_vnodeop_nonc_entries); Index: sys/fs/udf/udf_vnops.c =================================================================== --- sys/fs/udf/udf_vnops.c +++ sys/fs/udf/udf_vnops.c @@ -97,6 +97,7 @@ .vop_strategy = udf_strategy, .vop_vptofh = udf_vptofh, }; +VFS_VOP_VECTOR_REGISTER(udf_vnodeops); struct vop_vector udf_fifoops = { .vop_default = &fifo_specops, @@ -108,6 +109,7 @@ .vop_setattr = udf_setattr, .vop_vptofh = udf_vptofh, }; +VFS_VOP_VECTOR_REGISTER(udf_fifoops); static MALLOC_DEFINE(M_UDFFID, "udf_fid", "UDF FileId structure"); static MALLOC_DEFINE(M_UDFDS, "udf_ds", "UDF Dirstream structure"); Index: sys/fs/unionfs/union_vnops.c =================================================================== --- sys/fs/unionfs/union_vnops.c +++ sys/fs/unionfs/union_vnops.c @@ -2556,3 +2556,4 @@ .vop_vptofh = unionfs_vptofh, .vop_add_writecount = unionfs_add_writecount, }; +VFS_VOP_VECTOR_REGISTER(unionfs_vnodeops); Index: sys/kern/uipc_mqueue.c =================================================================== --- sys/kern/uipc_mqueue.c +++ sys/kern/uipc_mqueue.c @@ -2690,6 +2690,7 @@ .vop_mkdir = VOP_EOPNOTSUPP, .vop_rmdir = VOP_EOPNOTSUPP }; +VFS_VOP_VECTOR_REGISTER(mqfs_vnodeops); static struct vfsops mqfs_vfsops = { .vfs_init = mqfs_init, Index: sys/kern/vfs_default.c =================================================================== --- sys/kern/vfs_default.c +++ sys/kern/vfs_default.c @@ -146,6 +146,7 @@ .vop_add_writecount = vop_stdadd_writecount, .vop_copy_file_range = vop_stdcopy_file_range, }; +VFS_VOP_VECTOR_REGISTER(default_vnodeops); /* * Series of placeholder functions for various error returns for Index: sys/kern/vfs_lookup.c =================================================================== --- sys/kern/vfs_lookup.c +++ sys/kern/vfs_lookup.c @@ -139,6 +139,10 @@ .vop_lock1 = crossmp_vop_lock1, .vop_unlock = crossmp_vop_unlock, }; +/* + * VFS_VOP_VECTOR_REGISTER(crossmp_vnodeops) is not used here since the vnode + * gets allocated early. See nameiinit for the direct call below. + */ struct nameicap_tracker { struct vnode *dp; @@ -156,6 +160,7 @@ UMA_ALIGN_PTR, 0); nt_zone = uma_zcreate("rentr", sizeof(struct nameicap_tracker), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); + vfs_vector_op_register(&crossmp_vnodeops); getnewvnode("crossmp", NULL, &crossmp_vnodeops, &vp_crossmp); } SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nameiinit, NULL); Index: sys/kern/vfs_subr.c =================================================================== --- sys/kern/vfs_subr.c +++ sys/kern/vfs_subr.c @@ -1558,6 +1558,10 @@ int error __unused; CTR3(KTR_VFS, "%s: mp %p with tag %s", __func__, mp, tag); + + KASSERT(vops->registered, + ("%s: not registered vector op %p\n", __func__, vops)); + vp = NULL; td = curthread; if (td->td_vp_reserv > 0) { @@ -4502,6 +4506,7 @@ .vop_unlock = vop_stdunlock, /* unlock */ .vop_islocked = vop_stdislocked, /* islocked */ }; +VFS_VOP_VECTOR_REGISTER(sync_vnodeops); /* * Create a new filesystem syncer vnode for the specified mount point. Index: sys/sys/vnode.h =================================================================== --- sys/sys/vnode.h +++ sys/sys/vnode.h @@ -954,6 +954,14 @@ void vn_fsid(struct vnode *vp, struct vattr *va); +#include + +#define VFS_VOP_VECTOR_REGISTER(vnodeops) \ + SYSINIT(vfs_vector_##vnodeops##_f, SI_SUB_VFS, SI_ORDER_ANY, \ + vfs_vector_op_register, &vnodeops) + +void vfs_vector_op_register(struct vop_vector *vop); + #endif /* _KERNEL */ #endif /* !_SYS_VNODE_H_ */ Index: sys/tools/vnode_if.awk =================================================================== --- sys/tools/vnode_if.awk +++ sys/tools/vnode_if.awk @@ -323,6 +323,7 @@ } if (cfile) { + funcarr[name] = 1; # Print out the vop_F_vp_offsets structure. This all depends # on naming conventions and nothing else. printc("static int " name "_vp_offsets[] = {"); @@ -361,9 +362,6 @@ printc(""); printc("\tVNASSERT(a->a_gen.a_desc == &" name "_desc, a->a_" args[0]","); printc("\t (\"Wrong a_desc in " name "(%p, %p)\", a->a_" args[0]", a));"); - printc("\twhile(vop != NULL && \\"); - printc("\t vop->"name" == NULL && vop->vop_bypass == NULL)") - printc("\t\tvop = vop->vop_default;") printc("\tVNASSERT(vop != NULL, a->a_" args[0]", (\"No "name"(%p, %p)\", a->a_" args[0]", a));") printc("\tSDT_PROBE2(vfs, vop, " name ", entry, a->a_" args[0] ", a);\n"); for (i = 0; i < numargs; ++i) @@ -422,9 +420,44 @@ printc("};\n"); } } - -if (pfile) + +if (cfile) { + printc("void"); + printc("vfs_vector_op_register(struct vop_vector *orig_vop)"); + printc("{"); + printc("\tstruct vop_vector *vop;"); + printc(""); + printc("\tif (orig_vop->registered)"); + printc("\t\tpanic(\"%s: vop_vector %p already registered\",") + printc("\t\t __func__, orig_vop);"); + printc(""); + for (name in funcarr) { + printc("\tvop = orig_vop;"); + printc("\twhile (vop != NULL && \\"); + printc("\t vop->"name" == NULL && vop->vop_bypass == NULL)") + printc("\t\tvop = vop->vop_default;") + printc("\tif (vop != NULL)"); + printc("\t\torig_vop->"name" = vop->"name";"); + printc(""); + } + printc("\tvop = orig_vop;"); + printc("\twhile (vop != NULL && vop->vop_bypass == NULL)") + printc("\t\tvop = vop->vop_default;") + printc("\tif (vop != NULL)"); + printc("\t\torig_vop->vop_bypass = vop->vop_bypass;"); + printc(""); + printc("\torig_vop->registered = true;"); + printc("}") +} + +if (hfile) { + printh("void vfs_vector_op_register(struct vop_vector *orig_vop);"); +} + +if (pfile) { + printp("\tbool\tregistered;") printp("};") +} if (hfile) close(hfile); Index: sys/ufs/ffs/ffs_vnops.c =================================================================== --- sys/ufs/ffs/ffs_vnops.c +++ sys/ufs/ffs/ffs_vnops.c @@ -140,6 +140,7 @@ .vop_write = ffs_write, .vop_vptofh = ffs_vptofh, }; +VFS_VOP_VECTOR_REGISTER(ffs_vnodeops1); struct vop_vector ffs_fifoops1 = { .vop_default = &ufs_fifoops, @@ -148,6 +149,7 @@ .vop_lock1 = ffs_lock, .vop_vptofh = ffs_vptofh, }; +VFS_VOP_VECTOR_REGISTER(ffs_fifoops1); /* Global vfs data structures for ufs. */ struct vop_vector ffs_vnodeops2 = { @@ -168,6 +170,7 @@ .vop_setextattr = ffs_setextattr, .vop_vptofh = ffs_vptofh, }; +VFS_VOP_VECTOR_REGISTER(ffs_vnodeops2); struct vop_vector ffs_fifoops2 = { .vop_default = &ufs_fifoops, @@ -184,6 +187,7 @@ .vop_setextattr = ffs_setextattr, .vop_vptofh = ffs_vptofh, }; +VFS_VOP_VECTOR_REGISTER(ffs_fifoops2); /* * Synch an open file. Index: sys/ufs/ufs/ufs_vnops.c =================================================================== --- sys/ufs/ufs/ufs_vnops.c +++ sys/ufs/ufs/ufs_vnops.c @@ -2771,6 +2771,7 @@ .vop_aclcheck = ufs_aclcheck, #endif }; +VFS_VOP_VECTOR_REGISTER(ufs_vnodeops); struct vop_vector ufs_fifoops = { .vop_default = &fifo_specops, @@ -2801,3 +2802,4 @@ .vop_aclcheck = ufs_aclcheck, #endif }; +VFS_VOP_VECTOR_REGISTER(ufs_fifoops);