Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 20 Apr 2006 01:29:18 GMT
From:      John Birrell <jb@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 95650 for review
Message-ID:  <200604200129.k3K1TIRZ094263@repoman.freebsd.org>

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

Change 95650 by jb@jb_freebsd2 on 2006/04/20 01:28:33

	Work-in-progress update.

Affected files ...

.. //depot/projects/dtrace/src/sys/cddl/dev/dtrace/dtrace_ioctl.c#2 edit
.. //depot/projects/dtrace/src/sys/cddl/dev/dtrace/dtrace_load.c#2 edit
.. //depot/projects/dtrace/src/sys/cddl/dev/dtrace/dtrace_unload.c#2 edit

Differences ...

==== //depot/projects/dtrace/src/sys/cddl/dev/dtrace/dtrace_ioctl.c#2 (text+ko) ====

@@ -27,32 +27,23 @@
 dtrace_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused,
     int flags __unused, struct thread *td __unused)
 {
-	dtrace_conf_t conf;
-
 	int error = 0;
 
 	switch (cmd) {
-	/* Really handled in upper layer */
-	case FIOASYNC:
-	case FIONBIO:
+	case DTRACEIOC_AGGDESC:
+printf("DTRACEIOC_AGGDESC:\n");
+error = EINVAL;
 		break;
-	case DTRACEIOC_PROVIDER:
+	case DTRACEIOC_AGGSNAP:
+printf("DTRACEIOC_AGGSNAP:\n");
+error = EINVAL;
 		break;
-	case DTRACEIOC_PROBES:
-		break;
 	case DTRACEIOC_BUFSNAP:
+printf("DTRACEIOC_BUFSNAP:\n");
+error = EINVAL;
 		break;
-	case DTRACEIOC_PROBEMATCH:
-		break;
-	case DTRACEIOC_ENABLE:
-		break;
-	case DTRACEIOC_AGGSNAP:
-		break;
-	case DTRACEIOC_EPROBE:
-		break;
-	case DTRACEIOC_PROBEARG:
-		break;
-	case DTRACEIOC_CONF:
+	case DTRACEIOC_CONF: {
+		dtrace_conf_t conf;
 		bzero(&conf, sizeof (conf));
 		conf.dtc_difversion = DIF_VERSION;
 		conf.dtc_difintregs = DIF_DIR_NREGS;
@@ -62,20 +53,125 @@
 		*((dtrace_conf_t *) addr) = conf;
 
 		return (0);
+	}
+	case DTRACEIOC_DOFGET:
+printf("DTRACEIOC_DOFGET:\n");
+error = EINVAL;
+		break;
+	case DTRACEIOC_ENABLE:
+printf("DTRACEIOC_ENABLE:\n");
+error = EINVAL;
 		break;
-	case DTRACEIOC_STATUS:
+	case DTRACEIOC_EPROBE:
+printf("DTRACEIOC_EPROBE:\n");
+error = EINVAL;
+		break;
+	case DTRACEIOC_FORMAT:
+printf("DTRACEIOC_FORMAT:\n");
+error = EINVAL;
 		break;
 	case DTRACEIOC_GO:
+printf("DTRACEIOC_GO:\n");
+error = EINVAL;
+		break;
+	case DTRACEIOC_PROBEARG:
+printf("DTRACEIOC_PROBEARG:\n");
+error = EINVAL;
 		break;
-	case DTRACEIOC_STOP:
+	case DTRACEIOC_PROBEMATCH:
+	case DTRACEIOC_PROBES: {
+#ifdef DOODAD
+		dtrace_probe_t *probe = NULL;
+		dtrace_probedesc_t desc;
+		dtrace_probekey_t pkey;
+		dtrace_id_t i;
+		int m = 0;
+		uint32_t priv;
+		uid_t uid;
+		zoneid_t zoneid;
+
+		if (copyin((void *)arg, &desc, sizeof (desc)) != 0)
+			return (EFAULT);
+
+		desc.dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0';
+		desc.dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0';
+		desc.dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0';
+		desc.dtpd_name[DTRACE_NAMELEN - 1] = '\0';
+
+		/*
+		 * Before we attempt to match this probe, we want to give
+		 * all providers the opportunity to provide it.
+		 */
+		if (desc.dtpd_id == DTRACE_IDNONE) {
+			mutex_enter(&dtrace_provider_lock);
+			dtrace_probe_provide(&desc, NULL);
+			mutex_exit(&dtrace_provider_lock);
+			desc.dtpd_id++;
+		}
+
+		if (cmd == DTRACEIOC_PROBEMATCH)  {
+			dtrace_probekey(&desc, &pkey);
+			pkey.dtpk_id = DTRACE_IDNONE;
+		}
+
+		dtrace_cred2priv(cr, &priv, &uid, &zoneid);
+
+		mutex_enter(&dtrace_lock);
+
+		if (cmd == DTRACEIOC_PROBEMATCH) {
+			for (i = desc.dtpd_id; i <= dtrace_nprobes; i++) {
+				if ((probe = dtrace_probes[i - 1]) != NULL &&
+				    (m = dtrace_match_probe(probe, &pkey,
+				    priv, uid, zoneid)) != 0)
+					break;
+			}
+
+			if (m < 0) {
+				mutex_exit(&dtrace_lock);
+				return (EINVAL);
+			}
+
+		} else {
+			for (i = desc.dtpd_id; i <= dtrace_nprobes; i++) {
+				if ((probe = dtrace_probes[i - 1]) != NULL &&
+				    dtrace_match_priv(probe, priv, uid, zoneid))
+					break;
+			}
+		}
+
+		if (probe == NULL) {
+			mutex_exit(&dtrace_lock);
+			return (ESRCH);
+		}
+
+		dtrace_probe_description(probe, &desc);
+		mutex_exit(&dtrace_lock);
+
+		if (copyout(&desc, (void *)arg, sizeof (desc)) != 0)
+			return (EFAULT);
+#endif
+
+		return (0);
+	}
+	case DTRACEIOC_PROVIDER:
+printf("DTRACEIOC_PROVIDER:\n");
+error = EINVAL;
 		break;
-	case DTRACEIOC_AGGDESC:
+	case DTRACEIOC_REPLICATE:
+printf("DTRACEIOC_REPLICATE:\n");
+error = EINVAL;
 		break;
-	case DTRACEIOC_FORMAT:
+	case DTRACEIOC_STATUS:
+printf("DTRACEIOC_STATUS:\n");
+error = EINVAL;
 		break;
-	case DTRACEIOC_DOFGET:
+	case DTRACEIOC_STOP:
+printf("DTRACEIOC_STOP:\n");
+error = EINVAL;
 		break;
-	case DTRACEIOC_REPLICATE:
+	/* Really handled in upper layer */
+	case FIOASYNC:
+	case FIONBIO:
 		break;
 	default:
 		error = ENOTTY;

==== //depot/projects/dtrace/src/sys/cddl/dev/dtrace/dtrace_load.c#2 (text+ko) ====

@@ -22,14 +22,194 @@
  *
  */
 
+/*
+ * This function implements similar code to the Solaris dtrace_attach()
+ * function.
+ */
+
 static int
 dtrace_load()
 {
+	dtrace_provider_id_t id;
+#ifdef DOODAD
+	dtrace_state_t *state = NULL;
+	dtrace_enabling_t *enab;
+#endif
 	int error = 0;
 
+	mtx_init(&dtrace_lock,"dtrace probe state",NULL,MTX_RECURSE);
+	mtx_init(&dtrace_provider_lock,"dtrace provider state",NULL,MTX_RECURSE);
+	mtx_init(&dtrace_meta_lock,"dtrace meta-provider state",NULL,MTX_RECURSE);
+
 	/* Create the /dev/dtrace entry. */
 	dtrace_dev = make_dev(&dtrace_cdevsw, DTRACE_MINOR, UID_ROOT,
 	    GID_WHEEL, 0660, "dtrace");
 
+#ifdef DOODAD
+	mtx_lock(&cpu_lock);
+#endif
+	mtx_lock(&dtrace_provider_lock);
+	mtx_lock(&dtrace_lock);
+
+#ifdef DOODAD
+	if (ddi_soft_state_init(&dtrace_softstate,
+	    sizeof (dtrace_state_t), 0) != 0) {
+		cmn_err(CE_NOTE, "/dev/dtrace failed to initialize soft state");
+		mutex_exit(&cpu_lock);
+		mutex_exit(&dtrace_provider_lock);
+		mutex_exit(&dtrace_lock);
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_create_minor_node(devi, DTRACEMNR_DTRACE, S_IFCHR,
+	    DTRACEMNRN_DTRACE, DDI_PSEUDO, NULL) == DDI_FAILURE ||
+	    ddi_create_minor_node(devi, DTRACEMNR_HELPER, S_IFCHR,
+	    DTRACEMNRN_HELPER, DDI_PSEUDO, NULL) == DDI_FAILURE) {
+		cmn_err(CE_NOTE, "/dev/dtrace couldn't create minor nodes");
+		ddi_remove_minor_node(devi, NULL);
+		ddi_soft_state_fini(&dtrace_softstate);
+		mutex_exit(&cpu_lock);
+		mutex_exit(&dtrace_provider_lock);
+		mutex_exit(&dtrace_lock);
+		return (DDI_FAILURE);
+	}
+
+	ddi_report_dev(devi);
+	dtrace_devi = devi;
+
+	dtrace_modload = dtrace_module_loaded;
+	dtrace_modunload = dtrace_module_unloaded;
+	dtrace_cpu_init = dtrace_cpu_setup_initial;
+	dtrace_helpers_cleanup = dtrace_helpers_destroy;
+	dtrace_helpers_fork = dtrace_helpers_duplicate;
+	dtrace_cpustart_init = dtrace_suspend;
+	dtrace_cpustart_fini = dtrace_resume;
+	dtrace_debugger_init = dtrace_suspend;
+	dtrace_debugger_fini = dtrace_resume;
+	dtrace_kreloc_init = dtrace_suspend;
+	dtrace_kreloc_fini = dtrace_resume;
+
+	register_cpu_setup_func((cpu_setup_func_t *)dtrace_cpu_setup, NULL);
+
+	ASSERT(MUTEX_HELD(&cpu_lock));
+
+	dtrace_arena = vmem_create("dtrace", (void *)1, UINT32_MAX, 1,
+	    NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER);
+	dtrace_minor = vmem_create("dtrace_minor", (void *)DTRACEMNRN_CLONE,
+	    UINT32_MAX - DTRACEMNRN_CLONE, 1, NULL, NULL, NULL, 0,
+	    VM_SLEEP | VMC_IDENTIFIER);
+	dtrace_taskq = taskq_create("dtrace_taskq", 1, maxclsyspri,
+	    1, INT_MAX, 0);
+
+	dtrace_state_cache = kmem_cache_create("dtrace_state_cache",
+	    sizeof (dtrace_dstate_percpu_t) * NCPU, DTRACE_STATE_ALIGN,
+	    NULL, NULL, NULL, NULL, NULL, 0);
+
+	ASSERT(MUTEX_HELD(&cpu_lock));
+	dtrace_bymod = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_mod),
+	    offsetof(dtrace_probe_t, dtpr_nextmod),
+	    offsetof(dtrace_probe_t, dtpr_prevmod));
+
+	dtrace_byfunc = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_func),
+	    offsetof(dtrace_probe_t, dtpr_nextfunc),
+	    offsetof(dtrace_probe_t, dtpr_prevfunc));
+
+	dtrace_byname = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_name),
+	    offsetof(dtrace_probe_t, dtpr_nextname),
+	    offsetof(dtrace_probe_t, dtpr_prevname));
+
+	if (dtrace_retain_max < 1) {
+		cmn_err(CE_WARN, "illegal value (%lu) for dtrace_retain_max; "
+		    "setting to 1", dtrace_retain_max);
+		dtrace_retain_max = 1;
+	}
+
+	/*
+	 * Now discover our toxic ranges.
+	 */
+	dtrace_toxic_ranges(dtrace_toxrange_add);
+#endif
+
+	/*
+	 * Before we register ourselves as a provider to our own framework,
+	 * we would like to assert that dtrace_provider is NULL -- but that's
+	 * not true if we were loaded as a dependency of a DTrace provider.
+	 * Once we've registered, we can assert that dtrace_provider is our
+	 * pseudo provider.
+	 */
+	(void) dtrace_register("dtrace", &dtrace_provider_attr,
+	    DTRACE_PRIV_NONE, 0, &dtrace_provider_ops, NULL, &id);
+
+#ifdef DOODAD
+	ASSERT(dtrace_provider != NULL);
+	ASSERT((dtrace_provider_id_t)dtrace_provider == id);
+
+	dtrace_probeid_begin = dtrace_probe_create((dtrace_provider_id_t)
+	    dtrace_provider, NULL, NULL, "BEGIN", 0, NULL);
+	dtrace_probeid_end = dtrace_probe_create((dtrace_provider_id_t)
+	    dtrace_provider, NULL, NULL, "END", 0, NULL);
+	dtrace_probeid_error = dtrace_probe_create((dtrace_provider_id_t)
+	    dtrace_provider, NULL, NULL, "ERROR", 1, NULL);
+
+	dtrace_anon_property();
+	mutex_exit(&cpu_lock);
+
+	/*
+	 * If DTrace helper tracing is enabled, we need to allocate the
+	 * trace buffer and initialize the values.
+	 */
+	if (dtrace_helptrace_enabled) {
+		ASSERT(dtrace_helptrace_buffer == NULL);
+		dtrace_helptrace_buffer =
+		    kmem_zalloc(dtrace_helptrace_bufsize, KM_SLEEP);
+		dtrace_helptrace_next = 0;
+	}
+
+	/*
+	 * If there are already providers, we must ask them to provide their
+	 * probes, and then match any anonymous enabling against them.  Note
+	 * that there should be no other retained enablings at this time:
+	 * the only retained enablings at this time should be the anonymous
+	 * enabling.
+	 */
+	if (dtrace_anon.dta_enabling != NULL) {
+		ASSERT(dtrace_retained == dtrace_anon.dta_enabling);
+
+		dtrace_enabling_provide(NULL);
+		state = dtrace_anon.dta_state;
+
+		/*
+		 * We couldn't hold cpu_lock across the above call to
+		 * dtrace_enabling_provide(), but we must hold it to actually
+		 * enable the probes.  We have to drop all of our locks, pick
+		 * up cpu_lock, and regain our locks before matching the
+		 * retained anonymous enabling.
+		 */
+		mutex_exit(&dtrace_lock);
+		mutex_exit(&dtrace_provider_lock);
+
+		mutex_enter(&cpu_lock);
+		mutex_enter(&dtrace_provider_lock);
+		mutex_enter(&dtrace_lock);
+
+		if ((enab = dtrace_anon.dta_enabling) != NULL)
+			(void) dtrace_enabling_match(enab, NULL);
+
+		mutex_exit(&cpu_lock);
+	}
+#endif
+
+	mtx_unlock(&dtrace_lock);
+	mtx_unlock(&dtrace_provider_lock);
+
+#ifdef DOODAD
+	if (state != NULL) {
+		/*
+		 * If we created any anonymous state, set it going now.
+		 */
+		(void) dtrace_state_go(state, &dtrace_anon.dta_beganon);
+	}
+#endif
+
 	return (error);
 }

==== //depot/projects/dtrace/src/sys/cddl/dev/dtrace/dtrace_unload.c#2 (text+ko) ====

@@ -22,13 +22,136 @@
  *
  */
 
+#define	DDI_FAILURE	EBUSY
+
 static int
 dtrace_unload()
 {
 	int error = 0;
 
+#ifdef DOODAD
+	mutex_enter(&cpu_lock);
+#endif
+	mutex_enter(&dtrace_provider_lock);
+	mutex_enter(&dtrace_lock);
+
+#ifdef DOODAD
+	ASSERT(dtrace_opens == 0);
+#endif
+
+	if (dtrace_helpers > 0) {
+		mutex_exit(&dtrace_provider_lock);
+		mutex_exit(&dtrace_lock);
+#ifdef DOODAD
+		mutex_exit(&cpu_lock);
+#endif
+		return (DDI_FAILURE);
+	}
+
+	if (dtrace_unregister((dtrace_provider_id_t)dtrace_provider) != 0) {
+		mutex_exit(&dtrace_provider_lock);
+		mutex_exit(&dtrace_lock);
+#ifdef DOODAD
+		mutex_exit(&cpu_lock);
+#endif
+		return (DDI_FAILURE);
+	}
+
+	dtrace_provider = NULL;
+
+#ifdef DOODAD
+	if ((state = dtrace_anon_grab()) != NULL) {
+		/*
+		 * If there were ECBs on this state, the provider should
+		 * have not been allowed to detach; assert that there is
+		 * none.
+		 */
+		ASSERT(state->dts_necbs == 0);
+		dtrace_state_destroy(state);
+
+		/*
+		 * If we're being detached with anonymous state, we need to
+		 * indicate to the kernel debugger that DTrace is now inactive.
+		 */
+		(void) kdi_dtrace_set(KDI_DTSET_DTRACE_DEACTIVATE);
+	}
+
+	bzero(&dtrace_anon, sizeof (dtrace_anon_t));
+	unregister_cpu_setup_func((cpu_setup_func_t *)dtrace_cpu_setup, NULL);
+	dtrace_cpu_init = NULL;
+	dtrace_helpers_cleanup = NULL;
+	dtrace_helpers_fork = NULL;
+	dtrace_cpustart_init = NULL;
+	dtrace_cpustart_fini = NULL;
+	dtrace_debugger_init = NULL;
+	dtrace_debugger_fini = NULL;
+	dtrace_kreloc_init = NULL;
+	dtrace_kreloc_fini = NULL;
+	dtrace_modload = NULL;
+	dtrace_modunload = NULL;
+
+	mutex_exit(&cpu_lock);
+
+	if (dtrace_helptrace_enabled) {
+		kmem_free(dtrace_helptrace_buffer, dtrace_helptrace_bufsize);
+		dtrace_helptrace_buffer = NULL;
+	}
+
+	kmem_free(dtrace_probes, dtrace_nprobes * sizeof (dtrace_probe_t *));
+	dtrace_probes = NULL;
+	dtrace_nprobes = 0;
+
+	dtrace_hash_destroy(dtrace_bymod);
+	dtrace_hash_destroy(dtrace_byfunc);
+	dtrace_hash_destroy(dtrace_byname);
+	dtrace_bymod = NULL;
+	dtrace_byfunc = NULL;
+	dtrace_byname = NULL;
+
+	kmem_cache_destroy(dtrace_state_cache);
+	vmem_destroy(dtrace_minor);
+	vmem_destroy(dtrace_arena);
+
+	if (dtrace_toxrange != NULL) {
+		kmem_free(dtrace_toxrange,
+		    dtrace_toxranges_max * sizeof (dtrace_toxrange_t));
+		dtrace_toxrange = NULL;
+		dtrace_toxranges = 0;
+		dtrace_toxranges_max = 0;
+	}
+
+	ddi_remove_minor_node(dtrace_devi, NULL);
+	dtrace_devi = NULL;
+
+	ddi_soft_state_fini(&dtrace_softstate);
+
+	ASSERT(dtrace_vtime_references == 0);
+	ASSERT(dtrace_opens == 0);
+	ASSERT(dtrace_retained == NULL);
+#endif
+
+	mtx_unlock(&dtrace_lock);
+	mtx_unlock(&dtrace_provider_lock);
+
+	/*
+	 * We don't destroy the task queue until after we have dropped our
+	 * locks (taskq_destroy() may block on running tasks).  To prevent
+	 * attempting to do work after we have effectively detached but before
+	 * the task queue has been destroyed, all tasks dispatched via the
+	 * task queue must check that DTrace is still attached before
+	 * performing any operation.
+	 */
+#ifdef DOODAD
+	taskq_destroy(dtrace_taskq);
+	dtrace_taskq = NULL;
+#endif
+
 	/* Destroy the /dev/dtrace entry. */
 	destroy_dev(dtrace_dev);
 
+	mtx_destroy(&dtrace_meta_lock);
+	mtx_destroy(&dtrace_provider_lock);
+	mtx_destroy(&dtrace_lock);
+
 	return (error);
 }



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