Instead of only iterating over the set of known SDT probes when sdt.ko is
loaded and unloaded, also have sdt.ko register callbacks with kern_sdt.c that will be called when a newly loaded KLD module adds more probes or a module with probes is unloaded. This fixes two issues: first, if a module with SDT probes was loaded after sdt.ko was loaded, those new probes would not be available in DTrace. Second, if a module with SDT probes was unloaded while sdt.ko was loaded, the kernel would panic the next time DTrace had cause to try and do anything with the no-longer-existent probes. This makes it possible to create SDT probes in KLD modules, although there are still two caveats: first, any SDT probes in a KLD module must be part of a DTrace provider that is defined in that module. At present DTrace only destroys probes when the provider is destroyed, so you can still panic the system if a KLD module creates new probes in a provider from a different module(including the kernel) and then unload the the first module. Second, the system will panic if you unload a module containing SDT probes while there is an active D script that has enabled those probes. MFC after: 1 month
This commit is contained in:
parent
250a191260
commit
9742410797
@ -52,6 +52,8 @@ static void sdt_destroy(void *, dtrace_id_t, void *);
|
||||
static void sdt_enable(void *, dtrace_id_t, void *);
|
||||
static void sdt_disable(void *, dtrace_id_t, void *);
|
||||
static void sdt_load(void *);
|
||||
static int sdt_provider_unreg_callback(struct sdt_provider *prov,
|
||||
void *arg);
|
||||
|
||||
static struct cdevsw sdt_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
@ -190,7 +192,8 @@ sdt_load(void *dummy)
|
||||
|
||||
sdt_probe_func = dtrace_probe;
|
||||
|
||||
(void) sdt_provider_listall(sdt_provider_reg_callback, NULL);
|
||||
sdt_register_callbacks(sdt_provider_reg_callback, NULL,
|
||||
sdt_provider_unreg_callback, NULL, sdt_probe_callback, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -206,7 +209,7 @@ sdt_unload()
|
||||
|
||||
sdt_probe_func = sdt_probe_stub;
|
||||
|
||||
(void) sdt_provider_listall(sdt_provider_unreg_callback, NULL);
|
||||
sdt_deregister_callbacks();
|
||||
|
||||
destroy_dev(sdt_cdev);
|
||||
|
||||
|
@ -59,6 +59,16 @@ static struct sx sdt_sx;
|
||||
*/
|
||||
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
|
||||
@ -85,6 +95,9 @@ sdt_provider_register(void *arg)
|
||||
|
||||
TAILQ_INIT(&prov->probe_list);
|
||||
|
||||
if (sdt_provider_register_func != NULL)
|
||||
sdt_provider_register_func(prov, sdt_provider_register_arg);
|
||||
|
||||
sx_xunlock(&sdt_sx);
|
||||
}
|
||||
|
||||
@ -100,6 +113,9 @@ sdt_provider_deregister(void *arg)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -128,6 +144,9 @@ sdt_probe_register(void *arg)
|
||||
|
||||
probe->state = SDT_INIT;
|
||||
|
||||
if (sdt_probe_register_func != NULL)
|
||||
sdt_probe_register_func(probe, sdt_provider_register_arg);
|
||||
|
||||
sx_xunlock(&sdt_sx);
|
||||
}
|
||||
|
||||
@ -203,20 +222,31 @@ 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)
|
||||
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_xlock(&sdt_sx);
|
||||
sx_assert(&sdt_sx, SX_XLOCKED);
|
||||
|
||||
TAILQ_FOREACH(prov, &sdt_provider_list, prov_entry) {
|
||||
if ((error = callback_func(prov, arg)) != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
sx_xunlock(&sdt_sx);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -271,3 +301,39 @@ sdt_argtype_listall(struct sdt_probe *probe,
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -258,6 +258,10 @@ int sdt_argtype_listall(struct sdt_probe *, sdt_argtype_listall_func_t, void *);
|
||||
int sdt_probe_listall(struct sdt_provider *, sdt_probe_listall_func_t, void *);
|
||||
int sdt_provider_listall(sdt_provider_listall_func_t,void *);
|
||||
|
||||
void sdt_register_callbacks(sdt_provider_listall_func_t, void *,
|
||||
sdt_provider_listall_func_t, void *, sdt_probe_listall_func_t, void *);
|
||||
void sdt_deregister_callbacks(void);
|
||||
|
||||
#endif /* KDTRACE_HOOKS */
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
Loading…
Reference in New Issue
Block a user