[DTrace-devel] [PATCH 11/20] libdtrace: cache missing kernel CTF archives until paths change

Kris Van Hees kris.van.hees at oracle.com
Fri Oct 30 19:36:47 UTC 2026


---
 libdtrace/dt_impl.h        |  1 +
 libdtrace/dt_module.c      | 16 +++++++++++--
 libdtrace/dt_options.c     |  3 +++
 test/triggers/Build        |  1 +
 test/triggers/shared-ctf.c | 49 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
index 972fceaf..5487bfcf 100644
--- a/libdtrace/dt_impl.h
+++ b/libdtrace/dt_impl.h
@@ -310,6 +310,7 @@ struct dtrace_hdl {
 	dt_list_t dt_modlist;	/* linked list of dt_module_t's */
 	dt_htab_t *dt_mods;	/* hash table of dt_module_t's */
 	dt_htab_t *dt_kernsyms; /* htab of kernel symbol names */
+	int dt_ctfa_missing;	/* cached ENOENT/ENOTDIR for the archive */
 	char *dt_ctfa_path;	/* path to vmlinux.ctfa */
 	ctf_archive_t *dt_ctfa; /* ctf archive for the entire kernel tree */
 	void *dt_ctfa_data;	/* backing data for dt_ctfa */
diff --git a/libdtrace/dt_module.c b/libdtrace/dt_module.c
index ad43e815..f381bdcd 100644
--- a/libdtrace/dt_module.c
+++ b/libdtrace/dt_module.c
@@ -1329,16 +1329,28 @@ dt_kern_module_find_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
 		if (dtp->dt_ctfa_path == NULL) {
 			ctfa_name = malloc(strlen(dtp->dt_module_path) +
 			    strlen("/kernel/vmlinux.ctfa") + 1);
+			if (ctfa_name == NULL) {
+				dt_set_errno(dtp, EDT_NOMEM);
+				return;
+			}
 			to = stpcpy(ctfa_name, dtp->dt_module_path);
 			stpcpy(to, "/kernel/vmlinux.ctfa");
 		} else
 			ctfa_name = dtp->dt_ctfa_path;
 
+		/* Cache absence, but retry allocation, permission, and I/O errors. */
+		if (dtp->dt_ctfa_missing)
+			dtp->dt_ctferr = dtp->dt_ctfa_missing;
+		else {
 #ifdef HAVE_LIBCTF
-		dtp->dt_ctfa = dt_ctfa_open(dtp, ctfa_name);
+			dtp->dt_ctfa = dt_ctfa_open(dtp, ctfa_name);
 #else
-		dtp->dt_ctfa = ctf_arc_open(ctfa_name, &dtp->dt_ctferr);
+			dtp->dt_ctfa = ctf_arc_open(ctfa_name, &dtp->dt_ctferr);
 #endif
+			if (dtp->dt_ctfa == NULL &&
+			    (dtp->dt_ctferr == ENOENT || dtp->dt_ctferr == ENOTDIR))
+				dtp->dt_ctfa_missing = dtp->dt_ctferr;
+		}
 		if (dtp->dt_ctfa != NULL) {
 			/*
 			 * Load in the shared CTF immediately.
diff --git a/libdtrace/dt_options.c b/libdtrace/dt_options.c
index 78ff23e5..2b75d3c0 100644
--- a/libdtrace/dt_options.c
+++ b/libdtrace/dt_options.c
@@ -320,6 +320,7 @@ dt_opt_btf_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 
 	free(dtp->dt_btf_path);
 	dtp->dt_btf_path = btf;
+	dtp->dt_ctfa_missing = 0;
 
 	return 0;
 }
@@ -340,6 +341,7 @@ dt_opt_ctfa_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 
 	free(dtp->dt_ctfa_path);
 	dtp->dt_ctfa_path = ctfa;
+	dtp->dt_ctfa_missing = 0;
 
 	return 0;
 }
@@ -425,6 +427,7 @@ dt_opt_module_path(dtrace_hdl_t *dtp, const char *arg, uintptr_t option)
 
 	free(dtp->dt_module_path);
 	dtp->dt_module_path = proc;
+	dtp->dt_ctfa_missing = 0;
 
 	return 0;
 }
diff --git a/test/triggers/Build b/test/triggers/Build
index 607ea00b..8d648bab 100644
--- a/test/triggers/Build
+++ b/test/triggers/Build
@@ -267,6 +267,7 @@ module-discovery_LIBS := $(objdir)/build-libdtrace.a $(objdir)/build-libproc.a \
     $(objdir)/build-libcommon.a $(objdir)/build-libport.a $(libdtrace_LIBS)
 
 # Exercise shared dictionary ownership using libdtrace's private module APIs.
+shared-ctf_LDFLAGS := -Wl,--wrap=open64
 shared-ctf_CFLAGS := -Ilibproc -Ilibdtrace -Ilibcommon -Wno-pedantic
 shared-ctf_DEPS := build-libdtrace.a build-libproc.a libcommon.a libport.a
 shared-ctf_LIBS := $(objdir)/build-libdtrace.a $(objdir)/build-libproc.a \
diff --git a/test/triggers/shared-ctf.c b/test/triggers/shared-ctf.c
index 79aeeda5..74c55c44 100644
--- a/test/triggers/shared-ctf.c
+++ b/test/triggers/shared-ctf.c
@@ -4,6 +4,8 @@
  * http://oss.oracle.com/licenses/upl.
  */
 
+#include <errno.h>
+#include <stdarg.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -12,6 +14,34 @@
 #include <dt_module.h>
 #include <dt_kernel_module.h>
 
+static const char *watched_archive;
+static int archive_opens, archive_io_error;
+
+extern int __real_open64(const char *, int, ...);
+
+int
+__wrap_open64(const char *path, int flags, ...)
+{
+	mode_t mode = 0;
+
+	if (flags & O_CREAT) {
+		va_list ap;
+
+		va_start(ap, flags);
+		mode = va_arg(ap, int);
+		va_end(ap);
+	}
+	if (watched_archive && strcmp(path, watched_archive) == 0) {
+		archive_opens++;
+		if (archive_io_error) {
+			archive_io_error = 0;
+			errno = EIO;
+			return -1;
+		}
+	}
+	return __real_open64(path, flags, mode);
+}
+
 #ifdef HAVE_LIBCTF
 #define CHECK(expr) do { \
 	if (!(expr)) { \
@@ -227,7 +257,26 @@ check_embedded(const char *missing, const char *embedded)
 	dtp->dt_kernpaths = NULL;
 	CHECK(dt_kern_path_create(dtp, strdup("shared_ctf_test"), strdup(missing)) != NULL);
 	CHECK((shared = dt_module_create(dtp, "shared_ctf")) != NULL);
+	/* Transient errors retry; confirmed absence is cached until a path changes. */
+	watched_archive = missing;
+	archive_opens = 0;
+	archive_io_error = 1;
+	CHECK(dt_module_getctf(dtp, shared) == NULL);
+	CHECK(archive_opens == 1);
+	CHECK(dt_module_getctf(dtp, shared) == NULL);
+	CHECK(archive_opens == 2);
+	CHECK(dt_module_getctf(dtp, shared) == NULL);
+	CHECK(archive_opens == 2);
+	CHECK(dtrace_setopt(dtp, "ctfpath", missing) == 0);
+	CHECK(dt_module_getctf(dtp, shared) == NULL);
+	CHECK(archive_opens == 3);
+	CHECK(dtrace_setopt(dtp, "btfpath", "none") == 0);
+	CHECK(dt_module_getctf(dtp, shared) == NULL);
+	CHECK(archive_opens == 4);
+	CHECK(dtrace_setopt(dtp, "modpath", dtp->dt_module_path) == 0);
 	CHECK(dt_module_getctf(dtp, shared) == NULL);
+	CHECK(archive_opens == 5);
+	watched_archive = NULL;
 	CHECK(dtrace_errno(dtp) == EDT_NOCTF);
 	CHECK(dt_module_shared_ctf(dtp) == NULL);
 
-- 
2.52.0




More information about the DTrace-devel mailing list