git: 5f6df177758b - main - vfs: validate that vop vectors provide all or none fplookup vops

From: Mateusz Guzik <mjg_at_FreeBSD.org>
Date: Thu, 06 Apr 2023 15:45:35 UTC
The branch main has been updated by mjg:

URL: https://cgit.FreeBSD.org/src/commit/?id=5f6df177758b9dff88e4b6069aeb2359e8b0c493

commit 5f6df177758b9dff88e4b6069aeb2359e8b0c493
Author:     Mateusz Guzik <mjg@FreeBSD.org>
AuthorDate: 2021-11-03 20:26:41 +0000
Commit:     Mateusz Guzik <mjg@FreeBSD.org>
CommitDate: 2023-04-06 15:20:41 +0000

    vfs: validate that vop vectors provide all or none fplookup vops
    
    In order to prevent later susprises.
---
 sys/kern/vfs_cache.c   | 34 ++++++++++++++++++++++++++++++++++
 sys/sys/vnode.h        |  1 +
 sys/tools/vnode_if.awk |  2 ++
 3 files changed, 37 insertions(+)

diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index cc93158078d3..2ffa48f12299 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -3956,6 +3956,40 @@ static int cache_fast_lookup = 1;
 
 #define CACHE_FPL_FAILED	-2020
 
+void
+cache_vop_vector_register(struct vop_vector *v)
+{
+	size_t ops;
+
+	ops = 0;
+	if (v->vop_fplookup_vexec != NULL) {
+		ops++;
+	}
+	if (v->vop_fplookup_symlink != NULL) {
+		ops++;
+	}
+
+	if (ops == 2) {
+		return;
+	}
+
+	if (ops == 0) {
+		v->vop_fplookup_vexec = VOP_PANIC;
+		v->vop_fplookup_symlink = VOP_PANIC;
+		return;
+	}
+
+	printf("%s: invalid vop vector %p -- either all or none fplookup vops "
+	    "need to be provided",  __func__, v);
+	if (v->vop_fplookup_vexec == NULL) {
+		printf("%s: missing vop_fplookup_vexec\n", __func__);
+	}
+	if (v->vop_fplookup_symlink == NULL) {
+		printf("%s: missing vop_fplookup_symlink\n", __func__);
+	}
+	panic("bad vop vector %p", v);
+}
+
 void
 cache_fast_lookup_enabled_recalc(void)
 {
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index a3eb00f0fe7c..2a62c6d1b659 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -650,6 +650,7 @@ int	cache_symlink_resolve(struct cache_fpl *fpl, const char *string,
 void	cache_vop_rename(struct vnode *fdvp, struct vnode *fvp, struct vnode *tdvp,
     struct vnode *tvp, struct componentname *fcnp, struct componentname *tcnp);
 void	cache_vop_rmdir(struct vnode *dvp, struct vnode *vp);
+void	cache_vop_vector_register(struct vop_vector *);
 #ifdef INVARIANTS
 void	cache_validate(struct vnode *dvp, struct vnode *vp,
 	    struct componentname *cnp);
diff --git a/sys/tools/vnode_if.awk b/sys/tools/vnode_if.awk
index 415c33c52420..7fdaca208a9b 100644
--- a/sys/tools/vnode_if.awk
+++ b/sys/tools/vnode_if.awk
@@ -473,6 +473,8 @@ if (cfile) {
 	printc("\t\tpanic(\"%s: vop_vector %p already registered\",")
 	printc("\t\t    __func__, orig_vop);");
 	printc("");
+	printc("\tcache_vop_vector_register(orig_vop);");
+	printc("");
 	for (name in funcarr) {
 		printc("\tvop = orig_vop;");
 		printc("\twhile (vop != NULL && \\");