Print this page
4469 DTrace helper tracing should be dynamic

@@ -267,21 +267,26 @@
 static dtrace_id_t      dtrace_probeid_end;     /* special END probe */
 dtrace_id_t             dtrace_probeid_error;   /* special ERROR probe */
 
 /*
  * DTrace Helper Tracing Variables
- */
-uint32_t dtrace_helptrace_next = 0;
+ *
+ * These variables should be set dynamically to enable helper tracing.  The
+ * only variables that should be set are dtrace_helptrace_enable (which should
+ * be set to a non-zero value to allocate helper tracing buffers on the next
+ * open of /dev/dtrace) and dtrace_helptrace_disable (which should be set to a
+ * non-zero value to deallocate helper tracing buffers on the next close of
+ * /dev/dtrace).  When (and only when) helper tracing is disabled, the
+ * buffer size may also be set via dtrace_helptrace_bufsize.
+ */
+int                     dtrace_helptrace_enable = 0;
+int                     dtrace_helptrace_disable = 0;
+int                     dtrace_helptrace_bufsize = 16 * 1024 * 1024;
 uint32_t dtrace_helptrace_nlocals;
-char    *dtrace_helptrace_buffer;
-int     dtrace_helptrace_bufsize = 512 * 1024;
-
-#ifdef DEBUG
-int     dtrace_helptrace_enabled = 1;
-#else
-int     dtrace_helptrace_enabled = 0;
-#endif
+static dtrace_helptrace_t *dtrace_helptrace_buffer;
+static uint32_t         dtrace_helptrace_next = 0;
+static int              dtrace_helptrace_wrapped = 0;
 
 /*
  * DTrace Error Hashing
  *
  * On DEBUG kernels, DTrace will track the errors that has seen in a hash

@@ -14319,14 +14324,14 @@
 static void
 dtrace_helper_trace(dtrace_helper_action_t *helper,
     dtrace_mstate_t *mstate, dtrace_vstate_t *vstate, int where)
 {
         uint32_t size, next, nnext, i;
-        dtrace_helptrace_t *ent;
+        dtrace_helptrace_t *ent, *buffer;
         uint16_t flags = cpu_core[CPU->cpu_id].cpuc_dtrace_flags;
 
-        if (!dtrace_helptrace_enabled)
+        if ((buffer = dtrace_helptrace_buffer) == NULL)
                 return;
 
         ASSERT(vstate->dtvs_nlocals <= dtrace_helptrace_nlocals);
 
         /*

@@ -14350,14 +14355,16 @@
         } while (dtrace_cas32(&dtrace_helptrace_next, next, nnext) != next);
 
         /*
          * We have our slot; fill it in.
          */
-        if (nnext == size)
+        if (nnext == size) {
+                dtrace_helptrace_wrapped++;
                 next = 0;
+        }
 
-        ent = (dtrace_helptrace_t *)&dtrace_helptrace_buffer[next];
+        ent = (dtrace_helptrace_t *)((uintptr_t)buffer + next);
         ent->dtht_helper = helper;
         ent->dtht_where = where;
         ent->dtht_nlocals = vstate->dtvs_nlocals;
 
         ent->dtht_fltoffs = (mstate->dtms_present & DTRACE_MSTATE_FLTOFFS) ?

@@ -14387,11 +14394,11 @@
         uint64_t rval;
         dtrace_helpers_t *helpers = curproc->p_dtrace_helpers;
         dtrace_helper_action_t *helper;
         dtrace_vstate_t *vstate;
         dtrace_difo_t *pred;
-        int i, trace = dtrace_helptrace_enabled;
+        int i, trace = dtrace_helptrace_buffer != NULL;
 
         ASSERT(which >= 0 && which < DTRACE_NHELPER_ACTIONS);
 
         if (helpers == NULL)
                 return (0);

@@ -15704,21 +15711,10 @@
 
         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.

@@ -15810,10 +15806,22 @@
                 mutex_exit(&cpu_lock);
                 mutex_exit(&dtrace_lock);
                 return (EBUSY);
         }
 
+        if (dtrace_helptrace_enable && dtrace_helptrace_buffer == NULL) {
+                /*
+                 * If DTrace helper tracing is enabled, we need to allocate the
+                 * trace buffer and initialize the values.
+                 */
+                dtrace_helptrace_buffer =
+                    kmem_zalloc(dtrace_helptrace_bufsize, KM_SLEEP);
+                dtrace_helptrace_next = 0;
+                dtrace_helptrace_wrapped = 0;
+                dtrace_helptrace_enable = 0;
+        }
+
         state = dtrace_state_create(devp, cred_p);
         mutex_exit(&cpu_lock);
 
         if (state == NULL) {
                 if (--dtrace_opens == 0 && dtrace_anon.dta_enabling == NULL)

@@ -15831,10 +15839,11 @@
 static int
 dtrace_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
 {
         minor_t minor = getminor(dev);
         dtrace_state_t *state;
+        dtrace_helptrace_t *buf = NULL;
 
         if (minor == DTRACEMNRN_HELPER)
                 return (0);
 
         state = ddi_get_soft_state(dtrace_softstate, minor);

@@ -15848,20 +15857,37 @@
                  */
                 ASSERT(dtrace_anon.dta_state == NULL);
                 dtrace_state_destroy(state->dts_anon);
         }
 
+        if (dtrace_helptrace_disable) {
+                /*
+                 * If we have been told to disable helper tracing, set the
+                 * buffer to NULL before calling into dtrace_state_destroy();
+                 * we take advantage of its dtrace_sync() to know that no
+                 * CPU is in probe context with enabled helper tracing
+                 * after it returns.
+                 */
+                buf = dtrace_helptrace_buffer;
+                dtrace_helptrace_buffer = NULL;
+        }
+
         dtrace_state_destroy(state);
         ASSERT(dtrace_opens > 0);
 
         /*
          * Only relinquish control of the kernel debugger interface when there
          * are no consumers and no anonymous enablings.
          */
         if (--dtrace_opens == 0 && dtrace_anon.dta_enabling == NULL)
                 (void) kdi_dtrace_set(KDI_DTSET_DTRACE_DEACTIVATE);
 
+        if (buf != NULL) {
+                kmem_free(buf, dtrace_helptrace_bufsize);
+                dtrace_helptrace_disable = 0;
+        }
+
         mutex_exit(&dtrace_lock);
         mutex_exit(&cpu_lock);
 
         return (0);
 }

@@ -16751,15 +16777,10 @@
         ASSERT(dtrace_getf == 0);
         ASSERT(dtrace_closef == 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);