[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