summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_sdt.c
diff options
context:
space:
mode:
authormarkj <markj@FreeBSD.org>2013-08-13 03:10:39 +0000
committermarkj <markj@FreeBSD.org>2013-08-13 03:10:39 +0000
commit5a3f78714c72773b5d7b845e2cfa02dd8e9b2d94 (patch)
tree46930cccd981ff368016d8ab6113a94632ab865f /sys/kern/kern_sdt.c
parent5423ffaa89a66236a476ec84f1919e37b14210dc (diff)
downloadFreeBSD-src-5a3f78714c72773b5d7b845e2cfa02dd8e9b2d94.zip
FreeBSD-src-5a3f78714c72773b5d7b845e2cfa02dd8e9b2d94.tar.gz
FreeBSD's DTrace implementation has a few problems with respect to handling
probes declared in a kernel module when that module is unloaded. In particular, * Unloading a module with active SDT probes will cause a panic. [1] * A module's (FBT/SDT) probes aren't destroyed when the module is unloaded; trying to use them after the fact will generally cause a panic. This change fixes both problems by porting the DTrace module load/unload handlers from illumos and registering them with the corresponding EVENTHANDLER(9) handlers. This allows the DTrace framework to destroy all probes defined in a module when that module is unloaded, and to prevent a module unload from proceeding if some of its probes are active. The latter problem has already been fixed for FBT probes by checking lf->nenabled in kern_kldunload(), but moving the check into the DTrace framework generalizes it to all kernel providers and also fixes a race in the current implementation (since a probe may be activated between the check and the call to linker_file_unload()). Additionally, the SDT implementation has been reworked to define SDT providers/probes/argtypes in linker sets rather than using SYSINIT/SYSUNINIT to create and destroy SDT probes when a module is loaded or unloaded. This simplifies things quite a bit since it means that pretty much all of the SDT code can live in sdt.ko, and since it becomes easier to integrate SDT with the DTrace framework. Furthermore, this allows FreeBSD to be quite flexible in that SDT providers spanning multiple modules can be created on the fly when a module is loaded; at the moment it looks like illumos' SDT implementation requires all SDT probes to be statically defined in a single kernel table. PR: 166927, 166926, 166928 Reported by: davide [1] Reviewed by: avg, trociny (earlier version) MFC after: 1 month
Diffstat (limited to 'sys/kern/kern_sdt.c')
-rw-r--r--sys/kern/kern_sdt.c298
1 files changed, 5 insertions, 293 deletions
diff --git a/sys/kern/kern_sdt.c b/sys/kern/kern_sdt.c
index ee4adde..c8e1940 100644
--- a/sys/kern/kern_sdt.c
+++ b/sys/kern/kern_sdt.c
@@ -23,317 +23,29 @@
* SUCH DAMAGE.
*
* $FreeBSD$
- *
- * Backend for the Statically Defined Tracing (SDT) kernel support. This is
- * required to allow a module to load even though DTrace kernel support may
- * not be present. A module may be built with SDT probes in it which are
- * registered and deregistered via SYSINIT/SYSUNINIT.
- *
*/
#include "opt_kdtrace.h"
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/linker.h>
-#include <sys/lock.h>
-#include <sys/proc.h>
-#include <sys/sx.h>
#include <sys/sdt.h>
/*
- * This is the list of statically defined tracing providers.
- */
-static TAILQ_HEAD(sdt_provider_list_head, sdt_provider) sdt_provider_list;
-
-/*
- * Mutex to serialise access to the SDT provider list.
- */
-static struct sx sdt_sx;
-
-/*
- * Hook for the DTrace probe function. The 'sdt' provider will set this
- * to dtrace_probe when it loads.
+ * Hook for the DTrace probe function. The SDT provider will set this to
+ * dtrace_probe() when it loads.
*/
sdt_probe_func_t sdt_probe_func = sdt_probe_stub;
-static sdt_provider_listall_func_t sdt_provider_register_func = NULL;
-static sdt_provider_listall_func_t sdt_provider_deregister_func = NULL;
-static sdt_probe_listall_func_t sdt_probe_register_func = NULL;
-
-static void *sdt_provider_register_arg;
-static void *sdt_provider_deregister_arg;
-static void *sdt_probe_register_arg;
-
-static int sdt_provider_listall_locked(sdt_provider_listall_func_t, void *);
-
/*
* This is a stub for probe calls in case kernel DTrace support isn't
- * compiled in. It should never get called because there is no DTrace
- * support to enable it.
+ * enabled. It should never get called because there is no DTrace support
+ * to enable it.
*/
void
sdt_probe_stub(uint32_t id, uintptr_t arg0, uintptr_t arg1,
uintptr_t arg2, uintptr_t arg3, uintptr_t arg4)
{
- printf("sdt_probe_stub: Why did this get called?\n");
-}
-
-/*
- * Called from SYSINIT to register a provider.
- */
-void
-sdt_provider_register(void *arg)
-{
- struct sdt_provider *prov = arg;
-
- sx_xlock(&sdt_sx);
-
- TAILQ_INSERT_TAIL(&sdt_provider_list, prov, prov_entry);
-
- TAILQ_INIT(&prov->probe_list);
-
- if (sdt_provider_register_func != NULL)
- sdt_provider_register_func(prov, sdt_provider_register_arg);
-
- sx_xunlock(&sdt_sx);
-}
-
-/*
- * Called from SYSUNINIT to de-register a provider.
- */
-void
-sdt_provider_deregister(void *arg)
-{
- struct sdt_provider *prov = arg;
-
- sx_xlock(&sdt_sx);
-
- TAILQ_REMOVE(&sdt_provider_list, prov, prov_entry);
-
- if (sdt_provider_deregister_func != NULL)
- sdt_provider_deregister_func(prov, sdt_provider_deregister_arg);
-
- sx_xunlock(&sdt_sx);
-}
-
-/*
- * Called from SYSINIT to register a statically defined trace probe.
- */
-void
-sdt_probe_register(void *arg)
-{
- struct sdt_probe *probe = arg;
-
- /*
- * Check the reference structure version. Only version 1 is
- * supported at the moment.
- */
- if (probe->version != sizeof(struct sdt_probe)) {
- printf("%s:%s:%s has version %d when %d required\n", probe->mod, probe->func, probe->name, probe->version, (int) sizeof(struct sdt_probe));
- return;
- }
-
- sx_xlock(&sdt_sx);
-
- TAILQ_INSERT_TAIL(&probe->prov->probe_list, probe, probe_entry);
-
- TAILQ_INIT(&probe->argtype_list);
-
- probe->state = SDT_INIT;
-
- if (sdt_probe_register_func != NULL)
- sdt_probe_register_func(probe, sdt_provider_register_arg);
-
- sx_xunlock(&sdt_sx);
-}
-
-/*
- * Called from SYSUNINIT to de-register a statically defined trace probe.
- */
-void
-sdt_probe_deregister(void *arg)
-{
- struct sdt_probe *probe = arg;
-
- sx_xlock(&sdt_sx);
-
- if (probe->state == SDT_INIT) {
- TAILQ_REMOVE(&probe->prov->probe_list, probe, probe_entry);
- probe->state = SDT_UNINIT;
- }
-
- sx_xunlock(&sdt_sx);
-}
-
-/*
- * Called from SYSINIT to register a statically defined trace probe argument.
- */
-void
-sdt_argtype_register(void *arg)
-{
- struct sdt_argtype *argtype = arg;
-
- sx_xlock(&sdt_sx);
-
- TAILQ_INSERT_TAIL(&argtype->probe->argtype_list, argtype, argtype_entry);
-
- argtype->probe->n_args++;
-
- sx_xunlock(&sdt_sx);
-}
-
-/*
- * Called from SYSUNINIT to de-register a statically defined trace probe argument.
- */
-void
-sdt_argtype_deregister(void *arg)
-{
- struct sdt_argtype *argtype = arg;
-
- sx_xlock(&sdt_sx);
-
- TAILQ_REMOVE(&argtype->probe->argtype_list, argtype, argtype_entry);
-
- sx_xunlock(&sdt_sx);
-}
-
-static void
-sdt_init(void *arg)
-{
- sx_init_flags(&sdt_sx, "Statically Defined Tracing", SX_NOWITNESS);
-
- TAILQ_INIT(&sdt_provider_list);
-}
-
-SYSINIT(sdt, SI_SUB_KDTRACE, SI_ORDER_FIRST, sdt_init, NULL);
-
-static void
-sdt_uninit(void *arg)
-{
- sx_destroy(&sdt_sx);
-}
-
-SYSUNINIT(sdt, SI_SUB_KDTRACE, SI_ORDER_FIRST, sdt_uninit, NULL);
-
-/*
- * List statically defined tracing providers.
- */
-int
-sdt_provider_listall(sdt_provider_listall_func_t callback_func, void *arg)
-{
- int error;
-
- sx_xlock(&sdt_sx);
- error = sdt_provider_listall_locked(callback_func, arg);
- sx_xunlock(&sdt_sx);
-
- return (error);
-}
-
-static int
-sdt_provider_listall_locked(sdt_provider_listall_func_t callback_func,
- void *arg)
-{
- int error = 0;
- struct sdt_provider *prov;
-
- sx_assert(&sdt_sx, SX_XLOCKED);
-
- TAILQ_FOREACH(prov, &sdt_provider_list, prov_entry) {
- if ((error = callback_func(prov, arg)) != 0)
- break;
- }
-
- return (error);
-}
-
-/*
- * List statically defined tracing probes.
- */
-int
-sdt_probe_listall(struct sdt_provider *prov,
- sdt_probe_listall_func_t callback_func,void *arg)
-{
- int error = 0;
- int locked;
- struct sdt_probe *probe;
-
- locked = sx_xlocked(&sdt_sx);
- if (!locked)
- sx_xlock(&sdt_sx);
-
- TAILQ_FOREACH(probe, &prov->probe_list, probe_entry) {
- if ((error = callback_func(probe, arg)) != 0)
- break;
- }
-
- if (!locked)
- sx_xunlock(&sdt_sx);
-
- return (error);
-}
-
-/*
- * List statically defined tracing probe arguments.
- */
-int
-sdt_argtype_listall(struct sdt_probe *probe,
- sdt_argtype_listall_func_t callback_func,void *arg)
-{
- int error = 0;
- int locked;
- struct sdt_argtype *argtype;
-
- locked = sx_xlocked(&sdt_sx);
- if (!locked)
- sx_xlock(&sdt_sx);
- TAILQ_FOREACH(argtype, &probe->argtype_list, argtype_entry) {
- if ((error = callback_func(argtype, arg)) != 0)
- break;
- }
-
- if (!locked)
- sx_xunlock(&sdt_sx);
-
- return (error);
-}
-
-void sdt_register_callbacks(sdt_provider_listall_func_t register_prov,
- void *reg_prov_arg, sdt_provider_listall_func_t deregister_prov,
- void *dereg_prov_arg, sdt_probe_listall_func_t register_probe,
- void * reg_probe_arg)
-{
-
- sx_xlock(&sdt_sx);
- sdt_provider_register_func = register_prov;
- sdt_provider_deregister_func = deregister_prov;
- sdt_probe_register_func = register_probe;
-
- sdt_provider_register_arg = reg_prov_arg;
- sdt_provider_deregister_arg = dereg_prov_arg;
- sdt_probe_register_arg = reg_probe_arg;
-
- sdt_provider_listall_locked(register_prov, reg_prov_arg);
- sx_xunlock(&sdt_sx);
-}
-
-void sdt_deregister_callbacks(void)
-{
-
- sx_xlock(&sdt_sx);
- sdt_provider_listall_locked(sdt_provider_deregister_func,
- sdt_provider_deregister_arg);
-
- sdt_provider_register_func = NULL;
- sdt_provider_deregister_func = NULL;
- sdt_probe_register_func = NULL;
-
- sdt_provider_register_arg = NULL;
- sdt_provider_deregister_arg = NULL;
- sdt_probe_register_arg = NULL;
- sx_xunlock(&sdt_sx);
+ printf("sdt_probe_stub: Why did this get called?\n");
}
OpenPOWER on IntegriCloud