PERFORCE change 133377 for review
John Birrell
jb at FreeBSD.org
Tue Jan 15 16:53:57 PST 2008
http://perforce.freebsd.org/chv.cgi?CH=133377
Change 133377 by jb at jb_freebsd1 on 2008/01/16 00:53:50
A big change to the design of the Statically Defined Probe (sdt)
provider.
This utilises the SYSINIT/SYSINIT to keep a list of sdt providers
and sub-lists of sdt probes, all statically defined and just linked
via queue(3) so that they can be recursed.
Since the sdt.h header is included thoroughout the kernel source
where static probes are defined, it has to be BSD licensed. This
means a complete departure from the sdt design in Solaris. Readers
are encouraged to compare the unenabled probe overhead in this
implementation with that in the Solaris design. :-)
Note that the presence of the KDTRACE_HOOKS kernel option causes
the kern_sdt.c file to be compiled in, so that the SYSINIT/SYSUNINIT
routines are called even if the DTrace modules aren't loaded. This
is necessary so that if the DTrace modules are loaded later, they
have an up-to-date set of data to use. The overhead is minimal.
Affected files ...
.. //depot/projects/dtrace/src/sys/cddl/dev/sdt/sdt.c#8 edit
.. //depot/projects/dtrace/src/sys/kern/kern_sdt.c#5 add
.. //depot/projects/dtrace/src/sys/sys/sdt.h#10 add
Differences ...
==== //depot/projects/dtrace/src/sys/cddl/dev/sdt/sdt.c#8 (text+ko) ====
@@ -18,67 +18,39 @@
*
* CDDL HEADER END
*
- * Portions Copyright 2006 John Birrell jb at freebsd.org
+ * Portions Copyright 2006-2008 John Birrell jb at freebsd.org
*
* $FreeBSD$
*
*/
-/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
+#ifndef KDTRACE_HOOKS
+#define KDTRACE_HOOKS
+#endif
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/bus.h>
#include <sys/conf.h>
-#include <sys/cpuvar.h>
-#include <sys/fcntl.h>
-#include <sys/filio.h>
-#include <sys/kdb.h>
#include <sys/kernel.h>
-#include <sys/kmem.h>
-#include <sys/kthread.h>
#include <sys/limits.h>
+#include <sys/lock.h>
#include <sys/linker.h>
-#include <sys/lock.h>
-#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
-#include <sys/pcpu.h>
-#include <sys/poll.h>
-#include <sys/proc.h>
-#include <sys/selinfo.h>
-#include <sys/smp.h>
-#include <sys/syscall.h>
-#include <sys/sysctl.h>
-#include <sys/sysent.h>
-#include <sys/sysproto.h>
-#include <sys/uio.h>
-#include <sys/unistd.h>
-#include <machine/stdarg.h>
-#include <contrib/opensolaris/uts/common/sys/dtrace_impl.h>
-#include <contrib/opensolaris/uts/common/sys/sdt_impl.h>
+#include <sys/dtrace.h>
+#include <sys/sdt.h>
-MALLOC_DECLARE(M_SDT);
-MALLOC_DEFINE(M_SDT, "sdt", "Static Dtrace Tracing");
-
-#define SDT_PATCHVAL 0xf0
-#define SDT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & sdt_probetab_mask)
-#define SDT_PROBETAB_SIZE 0x1000/* 4k entries -- 16K total */
+#define SDT_ADDR2NDX(addr) (((uintptr_t)(addr)) >> 4)
static d_open_t sdt_open;
static int sdt_unload(void);
-static void sdt_provide_module(void *, modctl_t *);
+static void sdt_provide_probes(void *, dtrace_probedesc_t *);
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 void sdt_suspend(void *, dtrace_id_t, void *);
-static void sdt_resume(void *, dtrace_id_t, void *);
static struct cdevsw sdt_cdevsw = {
.d_version = D_VERSION,
@@ -86,339 +58,127 @@
.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 },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
+};
+
static dtrace_pops_t sdt_pops = {
+ sdt_provide_probes,
NULL,
- sdt_provide_module,
sdt_enable,
sdt_disable,
- sdt_suspend,
- sdt_resume,
- sdt_getargdesc,
+ NULL,
+ NULL,
+ NULL,
NULL,
NULL,
sdt_destroy
};
static struct cdev *sdt_cdev;
-static sdt_probe_t **sdt_probetab;
-static int sdt_probetab_size;
-static int sdt_probetab_mask;
-static int sdt_verbose = 0;
static int
-sdt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t rval)
+sdt_probe_callback(struct sdt_probe *probe, void *arg __unused)
{
- struct pcpu *cpu = pcpu_find(curcpu);
- uintptr_t stack0, stack1, stack2, stack3, stack4;
- sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(addr)];
+ struct sdt_provider *prov = probe->prov;
+ char mod[64];
+ char func[64];
+ char name[64];
+
+ /*
+ * Unfortunately this is necessary because the Solaris DTrace
+ * code mixes consts and non-consts with casts to override
+ * the incompatibilies. On FreeBSD, we use strict warnings
+ * in gcc, so we have to respect const vs non-const.
+ */
+ strlcpy(mod, probe->mod, sizeof(mod));
+ strlcpy(func, probe->func, sizeof(func));
+ strlcpy(name, probe->name, sizeof(name));
- for (; sdt != NULL; sdt = sdt->sdp_hashnext) {
- if ((uintptr_t)sdt->sdp_patchpoint == addr) {
- int i = 0;
- /*
- * When accessing the arguments on the stack,
- * we must protect against accessing beyond
- * the stack. We can safely set NOFAULT here
- * -- we know that interrupts are already
- * disabled.
- */
- DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
- cpu->pc_dtrace_caller = addr;
- stack0 = stack[i++];
- stack1 = stack[i++];
- stack2 = stack[i++];
- stack3 = stack[i++];
- stack4 = stack[i++];
- DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT |
- CPU_DTRACE_BADADDR);
+ if (dtrace_probe_lookup(prov->id, mod, func, name) != 0)
+ return (0);
- dtrace_probe(sdt->sdp_id, stack0, stack1,
- stack2, stack3, stack4);
- return (DTRACE_INVOP_NOP);
- }
- }
+ (void) dtrace_probe_create(prov->id, probe->mod, probe->func,
+ probe->name, 0, probe);
- return (0);
+ return (0);
}
static int
-sdt_create_module_probes(linker_file_t lf, char *modname)
-{
- sdt_probedesc_t *sdpd;
- sdt_probe_t *sdp, *old;
- sdt_provider_t *prov;
- int len;
-
- /*
- * One for all, and all for one: if we haven't yet registered all of
- * our providers, we'll refuse to provide anything.
- */
- for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) {
- if (prov->sdtp_id == DTRACE_PROVNONE)
- return (0);
- }
-
- if (lf->sdt_nprobes != 0 || (sdpd = lf->sdt_probes) == NULL)
- return (0);
-
- for (; sdpd != NULL; sdpd = sdpd->sdpd_next) {
- char *name = sdpd->sdpd_name, *nname;
- int i, j;
- sdt_provider_t *prov;
- dtrace_id_t id;
-
- for (prov = sdt_providers; prov->sdtp_prefix != NULL; prov++) {
- char *prefix = prov->sdtp_prefix;
-
- if (strncmp(name, prefix, strlen(prefix)) == 0) {
- name += strlen(prefix);
- break;
- }
- }
-
- while (*name != '\0') {
- if (*name <= '9' && *name>='0')
- name++;
- else
- break;
- }
-
- nname = malloc(len = strlen(name) + 1, M_SDT, M_WAITOK);
-
- for (i = 0, j = 0; name[j] != '\0'; i++) {
- if (name[j] == '_' && name[j + 1] == '_') {
- nname[i] = '-';
- j += 2;
- } else {
- nname[i] = name[j++];
- }
- }
-
- nname[i] = '\0';
-
- sdp = malloc(sizeof (sdt_probe_t), M_SDT, M_WAITOK | M_ZERO);
- sdp->sdp_loadcnt = lf->loadcnt;
- sdp->sdp_ctl = lf;
- sdp->sdp_name = nname;
- sdp->sdp_namelen = len;
- sdp->sdp_provider = prov;
-
- /*
- * We have our provider. Now create the probe.
- */
- if ((id = dtrace_probe_lookup(prov->sdtp_id, modname,
- NULL, nname)) != DTRACE_IDNONE) {
- old = dtrace_probe_arg(prov->sdtp_id, id);
- ASSERT(old != NULL);
-
- sdp->sdp_next = old->sdp_next;
- sdp->sdp_id = id;
- old->sdp_next = sdp;
- } else {
- sdp->sdp_id = dtrace_probe_create(prov->sdtp_id,
- modname, NULL, nname, 3, sdp);
-
- lf->sdt_nprobes++;
- }
-
- sdp->sdp_hashnext =
- sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)];
- sdt_probetab[SDT_ADDR2NDX(sdpd->sdpd_offset)] = sdp;
-
- sdp->sdp_patchval = SDT_PATCHVAL;
- sdp->sdp_patchpoint = (uint8_t *)sdpd->sdpd_offset;
- sdp->sdp_savedval = *sdp->sdp_patchpoint;
- }
- return (0);
+sdt_provider_entry(struct sdt_provider *prov, void *arg)
+{
+ return (sdt_probe_listall(prov, sdt_probe_callback, NULL));
}
-/*ARGSUSED*/
static void
-sdt_provide_module(void *arg, modctl_t *lf)
+sdt_provide_probes(void *arg, dtrace_probedesc_t *desc)
{
- char modname[MAXPATHLEN];
- size_t len;
+ if (desc != NULL)
+ return;
- strlcpy(modname, lf->filename, sizeof(modname));
- len = strlen(modname);
- if (len > 3 && strcmp(modname + len - 3, ".ko") == 0)
- modname[len - 3] = '\0';
-
- sdt_create_module_probes(lf, modname);
+ (void) sdt_provider_listall(sdt_provider_entry, NULL);
}
-/* ARGSUSED */
static void
sdt_destroy(void *arg, dtrace_id_t id, void *parg)
{
- sdt_probe_t *sdt = parg, *next, *hash, *last;
- modctl_t *ctl = sdt->sdp_ctl;
- int ndx;
-
- if (ctl->loadcnt == sdt->sdp_loadcnt)
- ctl->sdt_nprobes--;
-
- do {
- /*
- * Now we need to remove this probe from the sdt_probetab.
- */
- ndx = SDT_ADDR2NDX(sdt->sdp_patchpoint);
- last = NULL;
- hash = sdt_probetab[ndx];
-
- while (hash != sdt) {
- ASSERT(hash != NULL);
- last = hash;
- hash = hash->sdp_hashnext;
- }
-
- if (last != NULL) {
- last->sdp_hashnext = sdt->sdp_hashnext;
- } else {
- sdt_probetab[ndx] = sdt->sdp_hashnext;
- }
-
- free(sdt->sdp_name, M_SDT);
- next = sdt->sdp_next;
- free(sdt, M_SDT);
-
- sdt = next;
- } while (sdt != NULL);
+ /* Nothing to do here. */
}
-/* ARGSUSED */
static void
sdt_enable(void *arg, dtrace_id_t id, void *parg)
{
- sdt_probe_t *sdt = parg;
- modctl_t *ctl = sdt->sdp_ctl;
+ struct sdt_probe *probe = parg;
- ctl->nenabled++;
-
- /*
- * Now check that our modctl has the expected load count. If it
- * doesn't, this module must have been unloaded and reloaded -- and
- * we're not going to touch it.
- */
- if (ctl->loadcnt != sdt->sdp_loadcnt) {
- if (sdt_verbose) {
- printf("sdt is failing for probe %s "
- "(module %s reloaded)",
- sdt->sdp_name, ctl->filename);
- }
-
- return;
- }
-
- for (; sdt != NULL; sdt = sdt->sdp_next) {
- if (sdt_verbose)
- printf("sdt_enable %s\n",sdt->sdp_name);
- *sdt->sdp_patchpoint = sdt->sdp_patchval;
- }
+ probe->id = id;
}
-/* ARGSUSED */
static void
sdt_disable(void *arg, dtrace_id_t id, void *parg)
{
- sdt_probe_t *sdt = parg;
- modctl_t *ctl = sdt->sdp_ctl;
+ struct sdt_probe *probe = parg;
- ASSERT(ctl->nenabled > 0);
- ctl->nenabled--;
-
- if ((ctl->loadcnt != sdt->sdp_loadcnt))
- return;
-
- for (; sdt != NULL; sdt = sdt->sdp_next)
- *sdt->sdp_patchpoint = sdt->sdp_savedval;
+ probe->id = 0;
}
-/*ARGSUSED*/
-static void
-sdt_suspend(void *arg, dtrace_id_t id, void *parg)
+static int
+sdt_provider_reg_callback(struct sdt_provider *prov, void *arg __unused)
{
- sdt_probe_t *sdt = parg;
- modctl_t *ctl = sdt->sdp_ctl;
-
- ASSERT(ctl->nenabled > 0);
-
- if ((ctl->loadcnt != sdt->sdp_loadcnt))
- return;
-
- for (; sdt != NULL; sdt = sdt->sdp_next)
- *sdt->sdp_patchpoint = sdt->sdp_savedval;
+ return (dtrace_register(prov->name, &sdt_attr, DTRACE_PRIV_USER,
+ NULL, &sdt_pops, NULL, (dtrace_provider_id_t *) &prov->id));
}
-/*ARGSUSED*/
static void
-sdt_resume(void *arg, dtrace_id_t id, void *parg)
+sdt_load(void *dummy)
{
- sdt_probe_t *sdt = parg;
- modctl_t *ctl = sdt->sdp_ctl;
+ /* Create the /dev/dtrace/sdt entry. */
+ sdt_cdev = make_dev(&sdt_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
+ "dtrace/sdt");
- ASSERT(ctl->nenabled > 0);
+ sdt_probe_func = dtrace_probe;
- if ((ctl->loadcnt != sdt->sdp_loadcnt))
- return;
-
- for (; sdt != NULL; sdt = sdt->sdp_next)
- *sdt->sdp_patchpoint = sdt->sdp_patchval;
+ (void) sdt_provider_listall(sdt_provider_reg_callback, NULL);
}
-static void
-sdt_load(void *dummy)
+static int
+sdt_provider_unreg_callback(struct sdt_provider *prov, void *arg __unused)
{
- sdt_provider_t *prov;
-
- /* Default the probe table size if not specified. */
- if (sdt_probetab_size == 0)
- sdt_probetab_size = SDT_PROBETAB_SIZE;
-
- /* Choose the hash mask for the probe table. */
- sdt_probetab_mask = sdt_probetab_size - 1;
-
- /* Allocate memory for the probe table. */
- sdt_probetab = malloc(sdt_probetab_size * sizeof
- (sdt_probe_t *), M_SDT, M_WAITOK | M_ZERO);
-
- dtrace_invop_add(sdt_invop);
-
- for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) {
- if (dtrace_register(prov->sdtp_name, prov->sdtp_attr,
- DTRACE_PRIV_USER, NULL,
- &sdt_pops, prov, &prov->sdtp_id) != 0) {
- printf("failed to register sdt provider %s",
- prov->sdtp_name);
- }
- }
+ return (dtrace_unregister(prov->id));
}
-
static int
sdt_unload()
{
int error = 0;
- sdt_provider_t *prov;
-
- /* De-register the invalid opcode handler. */
- dtrace_invop_remove(sdt_invop);
+
+ sdt_probe_func = sdt_probe_stub;
- /* De-register this DTrace provider. */
- for (prov = sdt_providers; prov->sdtp_name != NULL; prov++) {
- if ((error = dtrace_unregister(prov->sdtp_id)) != 0) {
- return (error);
- }
- else {
- prov->sdtp_id = 0;
- }
- }
+ (void) sdt_provider_listall(sdt_provider_unreg_callback, NULL);
- /* Free the probe table. */
- free(sdt_probetab, M_SDT);
- sdt_probetab = NULL;
- sdt_probetab_mask = 0;
-
destroy_dev(sdt_cdev);
return (error);
@@ -432,13 +192,9 @@
switch (type) {
case MOD_LOAD:
- /* Create the /dev/dtrace/sdt entry. */
- sdt_cdev = make_dev(&sdt_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
- "dtrace/sdt");
break;
case MOD_UNLOAD:
- error = sdt_unload();
break;
case MOD_SHUTDOWN:
@@ -460,8 +216,10 @@
return (0);
}
-SYSINIT(sdt_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, sdt_load, NULL)
+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);
+MODULE_DEPEND(sdt, opensolaris, 1, 1, 1);
More information about the p4-projects
mailing list