Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 21 Sep 2013 16:46:34 +0000 (UTC)
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   svn commit: r255763 - in stable/9/sys: cddl/contrib/opensolaris/uts/common/dtrace cddl/contrib/opensolaris/uts/common/sys cddl/dev/dtrace cddl/dev/fbt cddl/dev/sdt kern netinet sys
Message-ID:  <201309211646.r8LGkYbF032233@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: markj
Date: Sat Sep 21 16:46:34 2013
New Revision: 255763
URL: http://svnweb.freebsd.org/changeset/base/255763

Log:
  MFC r252894:
  Add SDT_PROBE_DEFINE0 for consistency with SDT_PROBE0.
  
  MFC r253022:
  Also define SDT_PROBE_DEFINE0 for the !KDTRACE_HOOKS case.
  
  MFC r254266:
  Add event handlers for module load and unload events. The load handlers are
  called after the module has been loaded, and the unload handlers are called
  before the module is unloaded. Moreover, the module unload handlers may
  return an error to prevent the unload from proceeding.
  
  MFC r254267:
  Remove some unused fields from struct linker_file. They were added in
  r172862 for use by the DTrace SDT framework but don't seem to have ever
  been used.
  
  MFC r254268:
  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.
  
  MFC r254309:
  Use kld_{load,unload} instead of mod_{load,unload} for the linker file load
  and unload event handlers added in r254266.
  
  MFC r254350:
  Specify SDT probe argument types in the probe definition itself rather than
  using SDT_PROBE_ARGTYPE(). This will make it easy to extend the SDT(9) API
  to allow probes with dynamically-translated types.

Modified:
  stable/9/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
  stable/9/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h
  stable/9/sys/cddl/dev/dtrace/dtrace_load.c
  stable/9/sys/cddl/dev/dtrace/dtrace_unload.c
  stable/9/sys/cddl/dev/fbt/fbt.c
  stable/9/sys/cddl/dev/sdt/sdt.c
  stable/9/sys/kern/kern_exec.c
  stable/9/sys/kern/kern_exit.c
  stable/9/sys/kern/kern_fork.c
  stable/9/sys/kern/kern_linker.c
  stable/9/sys/kern/kern_proc.c
  stable/9/sys/kern/kern_sdt.c
  stable/9/sys/kern/kern_sig.c
  stable/9/sys/kern/kern_timeout.c
  stable/9/sys/kern/vfs_syscalls.c
  stable/9/sys/netinet/sctp_dtrace_define.h
  stable/9/sys/sys/eventhandler.h
  stable/9/sys/sys/linker.h
  stable/9/sys/sys/sdt.h
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/cddl/contrib/opensolaris/   (props changed)
  stable/9/sys/sys/   (props changed)

Modified: stable/9/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
==============================================================================
--- stable/9/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c	Sat Sep 21 14:23:20 2013	(r255762)
+++ stable/9/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c	Sat Sep 21 16:46:34 2013	(r255763)
@@ -115,6 +115,7 @@
 #if !defined(sun)
 #include <sys/callout.h>
 #include <sys/ctype.h>
+#include <sys/eventhandler.h>
 #include <sys/limits.h>
 #include <sys/kdb.h>
 #include <sys/kernel.h>
@@ -239,6 +240,8 @@ int		dtrace_in_probe;	/* non-zero if exe
 #if defined(__i386__) || defined(__amd64__)
 uintptr_t	dtrace_in_probe_addr;	/* Address of invop when already in probe */
 #endif
+static eventhandler_tag	dtrace_kld_load_tag;
+static eventhandler_tag	dtrace_kld_unload_tag;
 #endif
 
 /*
@@ -8035,19 +8038,6 @@ dtrace_probe_description(const dtrace_pr
 	(void) strncpy(pdp->dtpd_name, prp->dtpr_name, DTRACE_NAMELEN - 1);
 }
 
-#if !defined(sun)
-static int
-dtrace_probe_provide_cb(linker_file_t lf, void *arg)
-{
-	dtrace_provider_t *prv = (dtrace_provider_t *) arg;
-
-	prv->dtpv_pops.dtps_provide_module(prv->dtpv_arg, lf);
-
-	return(0);
-}
-#endif
-
-
 /*
  * Called to indicate that a probe -- or probes -- should be provided by a
  * specfied provider.  If the specified description is NULL, the provider will
@@ -8101,8 +8091,6 @@ dtrace_probe_provide(dtrace_probedesc_t 
 			prv->dtpv_pops.dtps_provide_module(prv->dtpv_arg, ctl);
 
 		} while ((ctl = ctl->mod_next) != &modules);
-#else
-		(void) linker_file_foreach(dtrace_probe_provide_cb, prv);
 #endif
 
 		mutex_exit(&mod_lock);
@@ -15121,7 +15109,6 @@ dtrace_helpers_duplicate(proc_t *from, p
 		dtrace_helper_provider_register(to, newhelp, NULL);
 }
 
-#if defined(sun)
 /*
  * DTrace Hook Functions
  */
@@ -15133,7 +15120,9 @@ dtrace_module_loaded(modctl_t *ctl)
 	mutex_enter(&dtrace_provider_lock);
 	mutex_enter(&mod_lock);
 
+#if defined(sun)
 	ASSERT(ctl->mod_busy);
+#endif
 
 	/*
 	 * We're going to call each providers per-module provide operation
@@ -15179,17 +15168,46 @@ dtrace_module_loaded(modctl_t *ctl)
 }
 
 static void
+#if defined(sun)
 dtrace_module_unloaded(modctl_t *ctl)
+#else
+dtrace_module_unloaded(modctl_t *ctl, int *error)
+#endif
 {
 	dtrace_probe_t template, *probe, *first, *next;
 	dtrace_provider_t *prov;
+#if !defined(sun)
+	char modname[DTRACE_MODNAMELEN];
+	size_t len;
+#endif
 
+#if defined(sun)
 	template.dtpr_mod = ctl->mod_modname;
+#else
+	/* Handle the fact that ctl->filename may end in ".ko". */
+	strlcpy(modname, ctl->filename, sizeof(modname));
+	len = strlen(ctl->filename);
+	if (len > 3 && strcmp(modname + len - 3, ".ko") == 0)
+		modname[len - 3] = '\0';
+	template.dtpr_mod = modname;
+#endif
 
 	mutex_enter(&dtrace_provider_lock);
 	mutex_enter(&mod_lock);
 	mutex_enter(&dtrace_lock);
 
+#if !defined(sun)
+	if (ctl->nenabled > 0) {
+		/* Don't allow unloads if a probe is enabled. */
+		mutex_exit(&dtrace_provider_lock);
+		mutex_exit(&dtrace_lock);
+		*error = -1;
+		printf(
+	"kldunload: attempt to unload module that has DTrace probes enabled\n");
+		return;
+	}
+#endif
+
 	if (dtrace_bymod == NULL) {
 		/*
 		 * The DTrace module is loaded (obviously) but not attached;
@@ -15219,8 +15237,13 @@ dtrace_module_unloaded(modctl_t *ctl)
 			 * probe, either.
 			 */
 			if (dtrace_err_verbose) {
+#if defined(sun)
 				cmn_err(CE_WARN, "unloaded module '%s' had "
 				    "enabled probes", ctl->mod_modname);
+#else
+				cmn_err(CE_WARN, "unloaded module '%s' had "
+				    "enabled probes", modname);
+#endif
 			}
 
 			return;
@@ -15263,7 +15286,11 @@ dtrace_module_unloaded(modctl_t *ctl)
 		kmem_free(probe->dtpr_mod, strlen(probe->dtpr_mod) + 1);
 		kmem_free(probe->dtpr_func, strlen(probe->dtpr_func) + 1);
 		kmem_free(probe->dtpr_name, strlen(probe->dtpr_name) + 1);
+#if defined(sun)
 		vmem_free(dtrace_arena, (void *)(uintptr_t)probe->dtpr_id, 1);
+#else
+		free_unr(dtrace_arena, probe->dtpr_id);
+#endif
 		kmem_free(probe, sizeof (dtrace_probe_t));
 	}
 
@@ -15272,6 +15299,26 @@ dtrace_module_unloaded(modctl_t *ctl)
 	mutex_exit(&dtrace_provider_lock);
 }
 
+#if !defined(sun)
+static void
+dtrace_kld_load(void *arg __unused, linker_file_t lf)
+{
+
+	dtrace_module_loaded(lf);
+}
+
+static void
+dtrace_kld_unload(void *arg __unused, linker_file_t lf, int *error)
+{
+
+	if (*error != 0)
+		/* We already have an error, so don't do anything. */
+		return;
+	dtrace_module_unloaded(lf, error);
+}
+#endif
+
+#if defined(sun)
 static void
 dtrace_suspend(void)
 {

Modified: stable/9/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h
==============================================================================
--- stable/9/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h	Sat Sep 21 14:23:20 2013	(r255762)
+++ stable/9/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h	Sat Sep 21 16:46:34 2013	(r255763)
@@ -2287,8 +2287,10 @@ extern void dtrace_membar_producer(void)
 extern void dtrace_membar_consumer(void);
 
 extern void (*dtrace_cpu_init)(processorid_t);
+#if defined(sun)
 extern void (*dtrace_modload)(modctl_t *);
 extern void (*dtrace_modunload)(modctl_t *);
+#endif
 extern void (*dtrace_helpers_cleanup)(void);
 extern void (*dtrace_helpers_fork)(proc_t *parent, proc_t *child);
 extern void (*dtrace_cpustart_init)(void);

Modified: stable/9/sys/cddl/dev/dtrace/dtrace_load.c
==============================================================================
--- stable/9/sys/cddl/dev/dtrace/dtrace_load.c	Sat Sep 21 14:23:20 2013	(r255762)
+++ stable/9/sys/cddl/dev/dtrace/dtrace_load.c	Sat Sep 21 16:46:34 2013	(r255763)
@@ -56,6 +56,12 @@ dtrace_load(void *dummy)
 	/* Hang our hook for exceptions. */
 	dtrace_invop_init();
 
+	/* Register callbacks for linker file load and unload events. */
+	dtrace_kld_load_tag = EVENTHANDLER_REGISTER(kld_load,
+	    dtrace_kld_load, NULL, EVENTHANDLER_PRI_ANY);
+	dtrace_kld_unload_tag = EVENTHANDLER_REGISTER(kld_unload,
+	    dtrace_kld_unload, NULL, EVENTHANDLER_PRI_ANY);
+
 	/*
 	 * XXX This is a short term hack to avoid having to comment
 	 * out lots and lots of lock/unlock calls.

Modified: stable/9/sys/cddl/dev/dtrace/dtrace_unload.c
==============================================================================
--- stable/9/sys/cddl/dev/dtrace/dtrace_unload.c	Sat Sep 21 14:23:20 2013	(r255762)
+++ stable/9/sys/cddl/dev/dtrace/dtrace_unload.c	Sat Sep 21 16:46:34 2013	(r255763)
@@ -67,6 +67,8 @@ dtrace_unload()
 	}
 
 	dtrace_provider = NULL;
+	EVENTHANDLER_DEREGISTER(kld_load, dtrace_kld_load_tag);
+	EVENTHANDLER_DEREGISTER(kld_unload, dtrace_kld_unload_tag);
 
 	if ((state = dtrace_anon_grab()) != NULL) {
 		/*

Modified: stable/9/sys/cddl/dev/fbt/fbt.c
==============================================================================
--- stable/9/sys/cddl/dev/fbt/fbt.c	Sat Sep 21 14:23:20 2013	(r255762)
+++ stable/9/sys/cddl/dev/fbt/fbt.c	Sat Sep 21 16:46:34 2013	(r255763)
@@ -1329,6 +1329,15 @@ fbt_getargdesc(void *arg __unused, dtrac
 	return;
 }
 
+static int
+fbt_linker_file_cb(linker_file_t lf, void *arg)
+{
+
+	fbt_provide_module(arg, lf);
+
+	return (0);
+}
+
 static void
 fbt_load(void *dummy)
 {
@@ -1353,8 +1362,10 @@ fbt_load(void *dummy)
 	if (dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_USER,
 	    NULL, &fbt_pops, NULL, &fbt_id) != 0)
 		return;
-}
 
+	/* Create probes for the kernel and already-loaded modules. */
+	linker_file_foreach(fbt_linker_file_cb, NULL);
+}
 
 static int
 fbt_unload()

Modified: stable/9/sys/cddl/dev/sdt/sdt.c
==============================================================================
--- stable/9/sys/cddl/dev/sdt/sdt.c	Sat Sep 21 14:23:20 2013	(r255762)
+++ stable/9/sys/cddl/dev/sdt/sdt.c	Sat Sep 21 16:46:34 2013	(r255763)
@@ -24,36 +24,44 @@
  *
  */
 
-#ifndef KDTRACE_HOOKS
-#define KDTRACE_HOOKS
-#endif
+#include "opt_kdtrace.h"
 
 #include <sys/cdefs.h>
 #include <sys/param.h>
 #include <sys/systm.h>
+
 #include <sys/conf.h>
+#include <sys/eventhandler.h>
 #include <sys/kernel.h>
 #include <sys/limits.h>
-#include <sys/lock.h>
 #include <sys/linker.h>
+#include <sys/linker_set.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
 #include <sys/module.h>
 #include <sys/mutex.h>
-
-#include <sys/dtrace.h>
+#include <sys/queue.h>
 #include <sys/sdt.h>
 
-#define SDT_ADDR2NDX(addr) (((uintptr_t)(addr)) >> 4)
+#include <sys/dtrace.h>
+#include <sys/dtrace_bsd.h>
 
-static d_open_t sdt_open;
-static int	sdt_unload(void);
+/* DTrace methods. */
 static void	sdt_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_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 d_open_t	sdt_open;
 static void	sdt_load(void *);
-static int	sdt_provider_unreg_callback(struct sdt_provider *prov, 
-		    void *arg);
+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 *);
+static void	sdt_kld_unload(void *, struct linker_file *, int *);
+
+static MALLOC_DEFINE(M_SDT, "SDT", "DTrace SDT providers");
 
 static struct cdevsw sdt_cdevsw = {
 	.d_version	= D_VERSION,
@@ -79,141 +87,261 @@ static dtrace_pops_t sdt_pops = {
 	sdt_getargdesc,
 	NULL,
 	NULL,
-	sdt_destroy
+	sdt_destroy,
 };
 
-static struct cdev		*sdt_cdev;
+static struct cdev	*sdt_cdev;
 
-static int
-sdt_argtype_callback(struct sdt_argtype *argtype, void *arg)
-{
-	dtrace_argdesc_t *desc = arg;
+static TAILQ_HEAD(, sdt_provider) sdt_prov_list;
 
-	if (desc->dtargd_ndx == argtype->ndx) {
-		desc->dtargd_mapping = desc->dtargd_ndx; /* XXX */
-		strlcpy(desc->dtargd_native, argtype->type,
-		    sizeof(desc->dtargd_native));
-		desc->dtargd_xlate[0] = '\0'; /* XXX */
-	}
-
-	return (0);
-}
+eventhandler_tag	sdt_kld_load_tag;
+eventhandler_tag	sdt_kld_unload_tag;
 
 static void
-sdt_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc)
+sdt_create_provider(struct sdt_provider *prov)
 {
-	struct sdt_probe *probe = parg;
+	struct sdt_provider *curr, *newprov;
 
-	if (desc->dtargd_ndx < probe->n_args)
-		(void) (sdt_argtype_listall(probe, sdt_argtype_callback, desc));
-	else
-		desc->dtargd_ndx = DTRACE_ARGNONE;
+	TAILQ_FOREACH(curr, &sdt_prov_list, prov_entry)
+		if (strcmp(prov->name, curr->name) == 0) {
+			/* The provider has already been defined. */
+			curr->sdt_refs++;
+			return;
+		}
 
-	return;
+	/*
+	 * Make a copy of prov so that we don't lose fields if its module is
+	 * unloaded but the provider isn't destroyed. This could happen with
+	 * a provider that spans multiple modules.
+	 */
+	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);
+
+	(void)dtrace_register(newprov->name, &sdt_attr, DTRACE_PRIV_USER, NULL,
+	    &sdt_pops, NULL, (dtrace_provider_id_t *)&newprov->id);
+	prov->id = newprov->id;
 }
 
-static int
-sdt_probe_callback(struct sdt_probe *probe, void *arg __unused)
+static void
+sdt_create_probe(struct sdt_probe *probe)
 {
-	struct sdt_provider *prov = probe->prov;
-	char mod[64];
-	char func[64];
-	char name[64];
+	struct sdt_provider *prov;
+	char mod[DTRACE_MODNAMELEN];
+	char func[DTRACE_FUNCNAMELEN];
+	char name[DTRACE_NAMELEN];
+	size_t len;
+
+	TAILQ_FOREACH(prov, &sdt_prov_list, prov_entry)
+		if (strcmp(prov->name, probe->prov->name) == 0)
+			break;
+
+	KASSERT(prov != NULL, ("probe defined without a provider"));
+
+	/* If no module name was specified, use the module filename. */
+	if (*probe->mod == 0) {
+		len = strlcpy(mod, probe->sdtp_lf->filename, sizeof(mod));
+		if (len > 3 && strcmp(mod + len - 3, ".ko") == 0)
+			mod[len - 3] = '\0';
+	} else
+		strlcpy(mod, probe->mod, sizeof(mod));
 
 	/*
 	 * 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.
+	 * in the C compiler, 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));
 
-	if (dtrace_probe_lookup(prov->id, mod, func, name) != 0)
-		return (0);
+	if (dtrace_probe_lookup(prov->id, mod, func, name) != DTRACE_IDNONE)
+		return;
 
-	(void) dtrace_probe_create(prov->id, probe->mod, probe->func,
-	    probe->name, 1, probe);
+	TAILQ_INSERT_TAIL(&prov->probe_list, probe, probe_entry);
 
-	return (0);
+	(void)dtrace_probe_create(prov->id, mod, func, name, 1, probe);
 }
 
-static int
-sdt_provider_entry(struct sdt_provider *prov, void *arg)
+/* Probes are created through the SDT module load/unload hook. */
+static void
+sdt_provide_probes(void *arg, dtrace_probedesc_t *desc)
 {
-	return (sdt_probe_listall(prov, sdt_probe_callback, NULL));
 }
 
 static void
-sdt_provide_probes(void *arg, dtrace_probedesc_t *desc)
+sdt_enable(void *arg __unused, dtrace_id_t id, void *parg)
 {
-	if (desc != NULL)
-		return;
+	struct sdt_probe *probe = parg;
 
-	(void) sdt_provider_listall(sdt_provider_entry, NULL);
+	probe->id = id;
+	probe->sdtp_lf->nenabled++;
 }
 
 static void
-sdt_destroy(void *arg, dtrace_id_t id, void *parg)
+sdt_disable(void *arg __unused, dtrace_id_t id, void *parg)
 {
-	/* Nothing to do here. */
+	struct sdt_probe *probe = parg;
+
+	KASSERT(probe->sdtp_lf->nenabled > 0, ("no probes enabled"));
+
+	probe->id = 0;
+	probe->sdtp_lf->nenabled--;
 }
 
 static void
-sdt_enable(void *arg, dtrace_id_t id, void *parg)
+sdt_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc)
 {
+	struct sdt_argtype *argtype;
 	struct sdt_probe *probe = parg;
 
-	probe->id = id;
+	if (desc->dtargd_ndx < probe->n_args) {
+		TAILQ_FOREACH(argtype, &probe->argtype_list, argtype_entry) {
+			if (desc->dtargd_ndx == argtype->ndx) {
+				/* XXX */
+				desc->dtargd_mapping = desc->dtargd_ndx;
+				strlcpy(desc->dtargd_native, argtype->type,
+				    sizeof(desc->dtargd_native));
+				desc->dtargd_xlate[0] = '\0'; /* XXX */
+			}
+		}
+	} else
+		desc->dtargd_ndx = DTRACE_ARGNONE;
 }
 
 static void
-sdt_disable(void *arg, dtrace_id_t id, void *parg)
+sdt_destroy(void *arg, dtrace_id_t id, void *parg)
 {
-	struct sdt_probe *probe = parg;
+	struct sdt_probe *probe;
 
-	probe->id = 0;
+	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.
+ */
+static void
+sdt_kld_load(void *arg __unused, struct linker_file *lf)
+{
+	struct sdt_provider **prov, **begin, **end;
+	struct sdt_probe **probe, **p_begin, **p_end;
+	struct sdt_argtype **argtype, **a_begin, **a_end;
+
+	if (linker_file_lookup_set(lf, "sdt_providers_set", &begin, &end, NULL))
+		return;
+	for (prov = begin; prov < end; prov++)
+		sdt_create_provider(*prov);
+
+	if (linker_file_lookup_set(lf, "sdt_probes_set", &p_begin, &p_end,
+	    NULL))
+		return;
+	for (probe = p_begin; probe < p_end; probe++) {
+		(*probe)->sdtp_lf = lf;
+		sdt_create_probe(*probe);
+		TAILQ_INIT(&(*probe)->argtype_list);
+	}
+
+	if (linker_file_lookup_set(lf, "sdt_argtypes_set", &a_begin, &a_end,
+	    NULL))
+		return;
+	for (argtype = a_begin; argtype < a_end; argtype++) {
+		(*argtype)->probe->n_args++;
+		TAILQ_INSERT_TAIL(&(*argtype)->probe->argtype_list, *argtype,
+		    argtype_entry);
+	}
+}
+
+static void
+sdt_kld_unload(void *arg __unused, struct linker_file *lf, int *error __unused)
+{
+	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))
+		/* No DTrace providers are declared in this file. */
+		return;
+
+	/*
+	 * Go through all the providers declared in this linker file and
+	 * unregister any that aren't declared in another loaded file.
+	 */
+	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;
+			}
+		}
+	}
 }
 
 static int
-sdt_provider_reg_callback(struct sdt_provider *prov, void *arg __unused)
+sdt_linker_file_cb(linker_file_t lf, void *arg __unused)
 {
-	return (dtrace_register(prov->name, &sdt_attr, DTRACE_PRIV_USER,
-	    NULL, &sdt_pops, NULL, (dtrace_provider_id_t *) &prov->id));
+
+	sdt_kld_load(NULL, lf);
+
+	return (0);
 }
 
 static void
-sdt_load(void *dummy)
+sdt_load(void *arg __unused)
 {
+
+	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_register_callbacks(sdt_provider_reg_callback, NULL,
-	    sdt_provider_unreg_callback, NULL, sdt_probe_callback, NULL);
-}
+	sdt_kld_load_tag = EVENTHANDLER_REGISTER(kld_load, sdt_kld_load, NULL,
+	    EVENTHANDLER_PRI_ANY);
+	sdt_kld_unload_tag = EVENTHANDLER_REGISTER(kld_unload, sdt_kld_unload,
+	    NULL, EVENTHANDLER_PRI_ANY);
 
-static int
-sdt_provider_unreg_callback(struct sdt_provider *prov, void *arg __unused)
-{
-	return (dtrace_unregister(prov->id));
+	/* Pick up probes from the kernel and already-loaded linker files. */
+	linker_file_foreach(sdt_linker_file_cb, NULL);
 }
 
 static int
-sdt_unload()
+sdt_unload(void *arg __unused)
 {
-	int error = 0;
+	struct sdt_provider *prov, *tmp;
+
+	EVENTHANDLER_DEREGISTER(kld_load, sdt_kld_load_tag);
+	EVENTHANDLER_DEREGISTER(kld_unload, sdt_kld_unload_tag);
 
 	sdt_probe_func = sdt_probe_stub;
 
-	sdt_deregister_callbacks();
-	
+	TAILQ_FOREACH_SAFE(prov, &sdt_prov_list, prov_entry, tmp) {
+		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 (error);
+	return (0);
 }
 
 /* ARGSUSED */
@@ -235,7 +363,6 @@ sdt_modevent(module_t mod __unused, int 
 	default:
 		error = EOPNOTSUPP;
 		break;
-
 	}
 
 	return (error);
@@ -243,8 +370,10 @@ sdt_modevent(module_t mod __unused, int 
 
 /* ARGSUSED */
 static int
-sdt_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, struct thread *td __unused)
+sdt_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused,
+    struct thread *td __unused)
 {
+
 	return (0);
 }
 

Modified: stable/9/sys/kern/kern_exec.c
==============================================================================
--- stable/9/sys/kern/kern_exec.c	Sat Sep 21 14:23:20 2013	(r255762)
+++ stable/9/sys/kern/kern_exec.c	Sat Sep 21 16:46:34 2013	(r255763)
@@ -95,12 +95,9 @@ dtrace_execexit_func_t	dtrace_fasttrap_e
 #endif
 
 SDT_PROVIDER_DECLARE(proc);
-SDT_PROBE_DEFINE(proc, kernel, , exec, exec);
-SDT_PROBE_ARGTYPE(proc, kernel, , exec, 0, "char *");
-SDT_PROBE_DEFINE(proc, kernel, , exec_failure, exec-failure);
-SDT_PROBE_ARGTYPE(proc, kernel, , exec_failure, 0, "int");
-SDT_PROBE_DEFINE(proc, kernel, , exec_success, exec-success);
-SDT_PROBE_ARGTYPE(proc, kernel, , exec_success, 0, "char *");
+SDT_PROBE_DEFINE1(proc, kernel, , exec, exec, "char *");
+SDT_PROBE_DEFINE1(proc, kernel, , exec_failure, exec-failure, "int");
+SDT_PROBE_DEFINE1(proc, kernel, , exec_success, exec-success, "char *");
 
 MALLOC_DEFINE(M_PARGS, "proc-args", "Process arguments");
 

Modified: stable/9/sys/kern/kern_exit.c
==============================================================================
--- stable/9/sys/kern/kern_exit.c	Sat Sep 21 14:23:20 2013	(r255762)
+++ stable/9/sys/kern/kern_exit.c	Sat Sep 21 16:46:34 2013	(r255763)
@@ -94,8 +94,7 @@ dtrace_execexit_func_t	dtrace_fasttrap_e
 #endif
 
 SDT_PROVIDER_DECLARE(proc);
-SDT_PROBE_DEFINE(proc, kernel, , exit, exit);
-SDT_PROBE_ARGTYPE(proc, kernel, , exit, 0, "int");
+SDT_PROBE_DEFINE1(proc, kernel, , exit, exit, "int");
 
 /* Hook for NFS teardown procedure. */
 void (*nlminfo_release_p)(struct proc *p);

Modified: stable/9/sys/kern/kern_fork.c
==============================================================================
--- stable/9/sys/kern/kern_fork.c	Sat Sep 21 14:23:20 2013	(r255762)
+++ stable/9/sys/kern/kern_fork.c	Sat Sep 21 16:46:34 2013	(r255763)
@@ -89,10 +89,8 @@ dtrace_fork_func_t	dtrace_fasttrap_fork;
 #endif
 
 SDT_PROVIDER_DECLARE(proc);
-SDT_PROBE_DEFINE(proc, kernel, , create, create);
-SDT_PROBE_ARGTYPE(proc, kernel, , create, 0, "struct proc *");
-SDT_PROBE_ARGTYPE(proc, kernel, , create, 1, "struct proc *");
-SDT_PROBE_ARGTYPE(proc, kernel, , create, 2, "int");
+SDT_PROBE_DEFINE3(proc, kernel, , create, create, "struct proc *",
+    "struct proc *", "int");
 
 #ifndef _SYS_SYSPROTO_H_
 struct fork_args {

Modified: stable/9/sys/kern/kern_linker.c
==============================================================================
--- stable/9/sys/kern/kern_linker.c	Sat Sep 21 14:23:20 2013	(r255762)
+++ stable/9/sys/kern/kern_linker.c	Sat Sep 21 16:46:34 2013	(r255763)
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/module.h>
 #include <sys/mount.h>
 #include <sys/linker.h>
+#include <sys/eventhandler.h>
 #include <sys/fcntl.h>
 #include <sys/jail.h>
 #include <sys/libkern.h>
@@ -580,8 +581,6 @@ linker_make_file(const char *pathname, l
 	lf->ndeps = 0;
 	lf->deps = NULL;
 	lf->loadcnt = ++loadcnt;
-	lf->sdt_probes = NULL;
-	lf->sdt_nprobes = 0;
 	STAILQ_INIT(&lf->common);
 	TAILQ_INIT(&lf->modules);
 	TAILQ_INSERT_TAIL(&linker_files, lf, link);
@@ -1044,6 +1043,9 @@ kern_kldload(struct thread *td, const ch
 	lf->userrefs++;
 	if (fileid != NULL)
 		*fileid = lf->id;
+
+	EVENTHANDLER_INVOKE(kld_load, lf);
+
 #ifdef HWPMC_HOOKS
 	KLD_DOWNGRADE();
 	pkm.pm_file = lf->filename;
@@ -1099,12 +1101,10 @@ kern_kldunload(struct thread *td, int fi
 	if (lf) {
 		KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
 
-		/* Check if there are DTrace probes enabled on this file. */
-		if (lf->nenabled > 0) {
-			printf("kldunload: attempt to unload file that has"
-			    " DTrace probes enabled\n");
+		EVENTHANDLER_INVOKE(kld_unload, lf, &error);
+		if (error != 0)
 			error = EBUSY;
-		} else if (lf->userrefs == 0) {
+		else if (lf->userrefs == 0) {
 			/*
 			 * XXX: maybe LINKER_UNLOAD_FORCE should override ?
 			 */

Modified: stable/9/sys/kern/kern_proc.c
==============================================================================
--- stable/9/sys/kern/kern_proc.c	Sat Sep 21 14:23:20 2013	(r255762)
+++ stable/9/sys/kern/kern_proc.c	Sat Sep 21 16:46:34 2013	(r255763)
@@ -91,33 +91,18 @@ __FBSDID("$FreeBSD$");
 #endif
 
 SDT_PROVIDER_DEFINE(proc);
-SDT_PROBE_DEFINE(proc, kernel, ctor, entry, entry);
-SDT_PROBE_ARGTYPE(proc, kernel, ctor, entry, 0, "struct proc *");
-SDT_PROBE_ARGTYPE(proc, kernel, ctor, entry, 1, "int");
-SDT_PROBE_ARGTYPE(proc, kernel, ctor, entry, 2, "void *");
-SDT_PROBE_ARGTYPE(proc, kernel, ctor, entry, 3, "int");
-SDT_PROBE_DEFINE(proc, kernel, ctor, return, return);
-SDT_PROBE_ARGTYPE(proc, kernel, ctor, return, 0, "struct proc *");
-SDT_PROBE_ARGTYPE(proc, kernel, ctor, return, 1, "int");
-SDT_PROBE_ARGTYPE(proc, kernel, ctor, return, 2, "void *");
-SDT_PROBE_ARGTYPE(proc, kernel, ctor, return, 3, "int");
-SDT_PROBE_DEFINE(proc, kernel, dtor, entry, entry);
-SDT_PROBE_ARGTYPE(proc, kernel, dtor, entry, 0, "struct proc *");
-SDT_PROBE_ARGTYPE(proc, kernel, dtor, entry, 1, "int");
-SDT_PROBE_ARGTYPE(proc, kernel, dtor, entry, 2, "void *");
-SDT_PROBE_ARGTYPE(proc, kernel, dtor, entry, 3, "struct thread *");
-SDT_PROBE_DEFINE(proc, kernel, dtor, return, return);
-SDT_PROBE_ARGTYPE(proc, kernel, dtor, return, 0, "struct proc *");
-SDT_PROBE_ARGTYPE(proc, kernel, dtor, return, 1, "int");
-SDT_PROBE_ARGTYPE(proc, kernel, dtor, return, 2, "void *");
-SDT_PROBE_DEFINE(proc, kernel, init, entry, entry);
-SDT_PROBE_ARGTYPE(proc, kernel, init, entry, 0, "struct proc *");
-SDT_PROBE_ARGTYPE(proc, kernel, init, entry, 1, "int");
-SDT_PROBE_ARGTYPE(proc, kernel, init, entry, 2, "int");
-SDT_PROBE_DEFINE(proc, kernel, init, return, return);
-SDT_PROBE_ARGTYPE(proc, kernel, init, return, 0, "struct proc *");
-SDT_PROBE_ARGTYPE(proc, kernel, init, return, 1, "int");
-SDT_PROBE_ARGTYPE(proc, kernel, init, return, 2, "int");
+SDT_PROBE_DEFINE4(proc, kernel, ctor, entry, entry, "struct proc *", "int",
+    "void *", "int");
+SDT_PROBE_DEFINE4(proc, kernel, ctor, return, return, "struct proc *", "int",
+    "void *", "int");
+SDT_PROBE_DEFINE4(proc, kernel, dtor, entry, entry, "struct proc *", "int",
+    "void *", "struct thread *");
+SDT_PROBE_DEFINE3(proc, kernel, dtor, return, return, "struct proc *", "int",
+    "void *");
+SDT_PROBE_DEFINE3(proc, kernel, init, entry, entry, "struct proc *", "int",
+    "int");
+SDT_PROBE_DEFINE3(proc, kernel, init, return, return, "struct proc *", "int",
+    "int");
 
 MALLOC_DEFINE(M_PGRP, "pgrp", "process group header");
 MALLOC_DEFINE(M_SESSION, "session", "session header");

Modified: stable/9/sys/kern/kern_sdt.c
==============================================================================
--- stable/9/sys/kern/kern_sdt.c	Sat Sep 21 14:23:20 2013	(r255762)
+++ stable/9/sys/kern/kern_sdt.c	Sat Sep 21 16:46:34 2013	(r255763)
@@ -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,

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201309211646.r8LGkYbF032233>