Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 Jan 2008 00:53:56 GMT
From:      John Birrell <jb@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 133377 for review
Message-ID:  <200801160053.m0G0rug7047168@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=133377

Change 133377 by jb@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@freebsd.org
+ * Portions Copyright 2006-2008 John Birrell jb@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);



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