git: 9a6ba186e0ca - main - sdt: Initialize probes in two passes
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 28 Jul 2025 20:33:04 UTC
The branch main has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=9a6ba186e0ca4269021d8843dbc8409ea78da4a6
commit 9a6ba186e0ca4269021d8843dbc8409ea78da4a6
Author: Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2025-07-28 19:30:37 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2025-07-28 20:32:39 +0000
sdt: Initialize probes in two passes
Suppose a kernel module A defines an SDT provider and probes, and kernel
linker file B, dependant on A, contains tracepoints for those probes.
When sdt.ko is loaded, it iterates over all loaded KLDs to initialize
probe structures and register them with dtrace. In particular it uses
linker_file_foreach(), which is not sorted; in the above scenario, B may
be visited before A. Thus, it's possible for sdt_kld_load_probes() to
try to add tracepoints to an uninitialized SDT probe.
An example of the above arises when pfsync, pf, and sdt are loaded in
that exact order after commit 4bb3b36577645.
Fix this by initializing probe structures in the first pass over loaded
KLDs. Then, the second pass can safely add tracepoints to any probe
structure.
Note that the scenario where B and A are loaded after sdt.ko is already
handled properly, as there, the kld_load eventhandler is responsible for
registering probes with dtrace, and that eventhandler fires for
dependencies before it does for the dependent KLD. This presumes,
however, that there are no cycles in the dependency graph.
Reported by: jenkins
MFC after: 2 weeks
---
sys/cddl/dev/sdt/sdt.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/sys/cddl/dev/sdt/sdt.c b/sys/cddl/dev/sdt/sdt.c
index a8da618204af..0a9059104671 100644
--- a/sys/cddl/dev/sdt/sdt.c
+++ b/sys/cddl/dev/sdt/sdt.c
@@ -72,6 +72,7 @@ static void sdt_load(void);
static int sdt_unload(void);
static void sdt_create_provider(struct sdt_provider *);
static void sdt_create_probe(struct sdt_probe *);
+static void sdt_init_probe(struct sdt_probe *, linker_file_t);
static void sdt_kld_load(void *, struct linker_file *);
static void sdt_kld_unload_try(void *, struct linker_file *, int *);
@@ -204,6 +205,14 @@ sdt_create_probe(struct sdt_probe *probe)
(void)dtrace_probe_create(prov->id, mod, func, name, aframes, probe);
}
+static void
+sdt_init_probe(struct sdt_probe *probe, linker_file_t lf)
+{
+ probe->sdtp_lf = lf;
+ TAILQ_INIT(&probe->argtype_list);
+ STAILQ_INIT(&probe->tracepoint_list);
+}
+
/*
* Probes are created through the SDT module load/unload hook, so this function
* has nothing to do. It only exists because the DTrace provider framework
@@ -361,12 +370,19 @@ static void
sdt_kld_load_providers(struct linker_file *lf)
{
struct sdt_provider **prov, **begin, **end;
+ struct sdt_probe **p_begin, **p_end;
if (linker_file_lookup_set(lf, "sdt_providers_set", &begin, &end,
NULL) == 0) {
for (prov = begin; prov < end; prov++)
sdt_create_provider(*prov);
}
+
+ if (linker_file_lookup_set(lf, "sdt_probes_set", &p_begin, &p_end,
+ NULL) == 0) {
+ for (struct sdt_probe **probe = p_begin; probe < p_end; probe++)
+ sdt_init_probe(*probe, lf);
+ }
}
static void
@@ -378,13 +394,8 @@ sdt_kld_load_probes(struct linker_file *lf)
if (linker_file_lookup_set(lf, "sdt_probes_set", &p_begin, &p_end,
NULL) == 0) {
- for (struct sdt_probe **probe = p_begin; probe < p_end;
- probe++) {
- (*probe)->sdtp_lf = lf;
+ for (struct sdt_probe **probe = p_begin; probe < p_end; probe++)
sdt_create_probe(*probe);
- TAILQ_INIT(&(*probe)->argtype_list);
- STAILQ_INIT(&(*probe)->tracepoint_list);
- }
}
if (linker_file_lookup_set(lf, "sdt_argtypes_set", &a_begin, &a_end,