Do some cleanup of the SDT code. In particular,

* Remove the unused sdt cdev.
* Don't bother keeping a list of probes in struct sdt_prov; it's not needed.
* Invoke sdt_load and sdt_unload from the module handler instead of
  registering separate SYSINITs.
* Keep to within 80 columns.
* Check for errors from dtrace_unregister().
This commit is contained in:
Mark Johnston 2013-10-26 06:23:51 +00:00
parent 4dc4651d73
commit 9c06d5a051
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=257152
2 changed files with 70 additions and 74 deletions

View File

@ -24,6 +24,21 @@
*
*/
/*
* This file contains a reimplementation of the statically-defined tracing (SDT)
* framework for DTrace. Probes and SDT providers are defined using the macros
* in sys/sdt.h, which append all the needed structures to linker sets. When
* this module is loaded, it iterates over all of the loaded modules and
* registers probes and providers with the DTrace framework based on the
* contents of these linker sets.
*
* A list of SDT providers is maintained here since a provider may span multiple
* modules. When a kernel module is unloaded, a provider defined in that module
* is unregistered only if no other modules refer to it. The DTrace framework is
* responsible for destroying individual probes when a kernel module is
* unloaded; in particular, probes may not span multiple kernel modules.
*/
#include "opt_kdtrace.h"
#include <sys/cdefs.h>
@ -53,9 +68,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 d_open_t sdt_open;
static void sdt_load(void *);
static int sdt_unload(void *);
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_kld_load(void *, struct linker_file *);
@ -63,12 +77,6 @@ static void sdt_kld_unload_try(void *, struct linker_file *, int *);
static MALLOC_DEFINE(M_SDT, "SDT", "DTrace SDT providers");
static struct cdevsw sdt_cdevsw = {
.d_version = D_VERSION,
.d_open = sdt_open,
.d_name = "sdt",
};
static dtrace_pattr_t sdt_attr = {
{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
@ -90,8 +98,6 @@ static dtrace_pops_t sdt_pops = {
sdt_destroy,
};
static struct cdev *sdt_cdev;
static TAILQ_HEAD(, sdt_provider) sdt_prov_list;
eventhandler_tag sdt_kld_load_tag;
@ -117,7 +123,6 @@ sdt_create_provider(struct sdt_provider *prov)
newprov = malloc(sizeof(*newprov), M_SDT, M_WAITOK | M_ZERO);
newprov->name = strdup(prov->name, M_SDT);
prov->sdt_refs = newprov->sdt_refs = 1;
TAILQ_INIT(&newprov->probe_list);
TAILQ_INSERT_TAIL(&sdt_prov_list, newprov, prov_entry);
@ -161,12 +166,14 @@ sdt_create_probe(struct sdt_probe *probe)
if (dtrace_probe_lookup(prov->id, mod, func, name) != DTRACE_IDNONE)
return;
TAILQ_INSERT_TAIL(&prov->probe_list, probe, probe_entry);
(void)dtrace_probe_create(prov->id, mod, func, name, 1, probe);
}
/* Probes are created through the SDT module load/unload hook. */
/*
* 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
* requires one of provide_probes and provide_module to be defined.
*/
static void
sdt_provide_probes(void *arg, dtrace_probedesc_t *desc)
{
@ -198,39 +205,39 @@ sdt_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc)
struct sdt_argtype *argtype;
struct sdt_probe *probe = parg;
if (desc->dtargd_ndx < probe->n_args) {
TAILQ_FOREACH(argtype, &probe->argtype_list, argtype_entry) {
if (desc->dtargd_ndx == argtype->ndx) {
desc->dtargd_mapping = desc->dtargd_ndx;
strlcpy(desc->dtargd_native, argtype->type,
sizeof(desc->dtargd_native));
if (argtype->xtype != NULL)
strlcpy(desc->dtargd_xlate,
argtype->xtype,
sizeof(desc->dtargd_xlate));
else
desc->dtargd_xlate[0] = '\0';
}
}
} else
if (desc->dtargd_ndx >= probe->n_args) {
desc->dtargd_ndx = DTRACE_ARGNONE;
return;
}
TAILQ_FOREACH(argtype, &probe->argtype_list, argtype_entry) {
if (desc->dtargd_ndx == argtype->ndx) {
desc->dtargd_mapping = desc->dtargd_ndx;
if (argtype->type == NULL) {
desc->dtargd_native[0] = '\0';
desc->dtargd_xlate[0] = '\0';
continue;
}
strlcpy(desc->dtargd_native, argtype->type,
sizeof(desc->dtargd_native));
if (argtype->xtype != NULL)
strlcpy(desc->dtargd_xlate, argtype->xtype,
sizeof(desc->dtargd_xlate));
}
}
}
static void
sdt_destroy(void *arg, dtrace_id_t id, void *parg)
{
struct sdt_probe *probe;
probe = parg;
TAILQ_REMOVE(&probe->prov->probe_list, probe, probe_entry);
}
/*
* Called from the kernel linker when a module is loaded, before
* dtrace_module_loaded() is called. This is done so that it's possible to
* register new providers when modules are loaded. We cannot do this in the
* provide_module method since it's called with the provider lock held
* and dtrace_register() will try to acquire it again.
* register new providers when modules are loaded. The DTrace framework
* explicitly disallows calling into the framework from the provide_module
* provider method, so we cannot do this there.
*/
static void
sdt_kld_load(void *arg __unused, struct linker_file *lf)
@ -264,14 +271,15 @@ sdt_kld_load(void *arg __unused, struct linker_file *lf)
}
static void
sdt_kld_unload_try(void *arg __unused, struct linker_file *lf, int *error __unused)
sdt_kld_unload_try(void *arg __unused, struct linker_file *lf, int *error)
{
struct sdt_provider *prov, **curr, **begin, **end, *tmp;
if (*error != 0)
/* We already have an error, so don't do anything. */
return;
else if (linker_file_lookup_set(lf, "sdt_providers_set", &begin, &end, NULL))
else if (linker_file_lookup_set(lf, "sdt_providers_set", &begin, &end,
NULL))
/* No DTrace providers are declared in this file. */
return;
@ -281,17 +289,20 @@ sdt_kld_unload_try(void *arg __unused, struct linker_file *lf, int *error __unus
*/
for (curr = begin; curr < end; curr++) {
TAILQ_FOREACH_SAFE(prov, &sdt_prov_list, prov_entry, tmp) {
if (strcmp(prov->name, (*curr)->name) == 0) {
if (prov->sdt_refs == 1) {
TAILQ_REMOVE(&sdt_prov_list, prov,
prov_entry);
dtrace_unregister(prov->id);
free(prov->name, M_SDT);
free(prov, M_SDT);
} else
prov->sdt_refs--;
break;
}
if (strcmp(prov->name, (*curr)->name) != 0)
continue;
if (prov->sdt_refs == 1) {
if (dtrace_unregister(prov->id) != 0) {
*error = 1;
return;
}
TAILQ_REMOVE(&sdt_prov_list, prov, prov_entry);
free(prov->name, M_SDT);
free(prov, M_SDT);
} else
prov->sdt_refs--;
break;
}
}
}
@ -306,15 +317,11 @@ sdt_linker_file_cb(linker_file_t lf, void *arg __unused)
}
static void
sdt_load(void *arg __unused)
sdt_load()
{
TAILQ_INIT(&sdt_prov_list);
/* Create the /dev/dtrace/sdt entry. */
sdt_cdev = make_dev(&sdt_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
"dtrace/sdt");
sdt_probe_func = dtrace_probe;
sdt_kld_load_tag = EVENTHANDLER_REGISTER(kld_load, sdt_kld_load, NULL,
@ -327,9 +334,10 @@ sdt_load(void *arg __unused)
}
static int
sdt_unload(void *arg __unused)
sdt_unload()
{
struct sdt_provider *prov, *tmp;
int ret;
EVENTHANDLER_DEREGISTER(kld_load, sdt_kld_load_tag);
EVENTHANDLER_DEREGISTER(kld_unload_try, sdt_kld_unload_try_tag);
@ -337,18 +345,17 @@ sdt_unload(void *arg __unused)
sdt_probe_func = sdt_probe_stub;
TAILQ_FOREACH_SAFE(prov, &sdt_prov_list, prov_entry, tmp) {
ret = dtrace_unregister(prov->id);
if (ret != 0)
return (ret);
TAILQ_REMOVE(&sdt_prov_list, prov, prov_entry);
dtrace_unregister(prov->id);
free(prov->name, M_SDT);
free(prov, M_SDT);
}
destroy_dev(sdt_cdev);
return (0);
}
/* ARGSUSED */
static int
sdt_modevent(module_t mod __unused, int type, void *data __unused)
{
@ -356,9 +363,11 @@ sdt_modevent(module_t mod __unused, int type, void *data __unused)
switch (type) {
case MOD_LOAD:
sdt_load();
break;
case MOD_UNLOAD:
error = sdt_unload();
break;
case MOD_SHUTDOWN:
@ -372,18 +381,6 @@ sdt_modevent(module_t mod __unused, int type, void *data __unused)
return (error);
}
/* ARGSUSED */
static int
sdt_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused,
struct thread *td __unused)
{
return (0);
}
SYSINIT(sdt_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, sdt_load, NULL);
SYSUNINIT(sdt_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, sdt_unload, NULL);
DEV_MODULE(sdt, sdt_modevent, NULL);
MODULE_VERSION(sdt, 1);
MODULE_DEPEND(sdt, dtrace, 1, 1, 1);

View File

@ -134,7 +134,7 @@ SET_DECLARE(sdt_argtypes_set, struct sdt_argtype);
#define SDT_PROVIDER_DEFINE(prov) \
struct sdt_provider sdt_provider_##prov[1] = { \
{ #prov, { NULL, NULL }, { NULL, NULL }, 0, 0 } \
{ #prov, { NULL, NULL }, 0, 0 } \
}; \
DATA_SET(sdt_providers_set, sdt_provider_##prov);
@ -358,7 +358,6 @@ struct sdt_provider {
char *name; /* Provider name. */
TAILQ_ENTRY(sdt_provider)
prov_entry; /* SDT provider list entry. */
TAILQ_HEAD(probe_list_head, sdt_probe) probe_list;
uintptr_t id; /* DTrace provider ID. */
int sdt_refs; /* Number of module references. */
};