- /* propagate EAGAIN or ERESTART */
- return (rv);
- }
-
- lck_mtx_unlock(&dtrace_lock);
-
- lck_rw_lock_exclusive(&dtrace_dof_mode_lock);
-
- /*
- * If we are currently lazy, transition states.
- *
- * Unlike dtrace_close, we do not need to check the
- * value of dtrace_opens, as any positive value (and
- * we count as 1) means we transition states.
- */
- if (dtrace_dof_mode == DTRACE_DOF_MODE_LAZY_ON) {
- dtrace_dof_mode = DTRACE_DOF_MODE_LAZY_OFF;
-
- /*
- * Iterate all existing processes and load lazy dofs.
- */
- proc_iterate(PROC_ALLPROCLIST | PROC_NOWAITTRANS,
- dtrace_lazy_dofs_proc_iterate_doit,
- NULL,
- dtrace_lazy_dofs_proc_iterate_filter,
- NULL);
- }
-
- lck_rw_unlock_exclusive(&dtrace_dof_mode_lock);
-
- /*
- * Update kernel symbol state.
- *
- * We must own the provider and dtrace locks.
- *
- * NOTE! It may appear there is a race by setting this value so late
- * after dtrace_probe_provide. However, any kext loaded after the
- * call to probe provide and before we set LAZY_OFF will be marked as
- * eligible for symbols from userspace. The same dtrace that is currently
- * calling dtrace_open() (this call!) will get a list of kexts needing
- * symbols and fill them in, thus closing the race window.
- *
- * We want to set this value only after it certain it will succeed, as
- * this significantly reduces the complexity of error exits.
- */
- lck_mtx_lock(&dtrace_lock);
- if (dtrace_kernel_symbol_mode == DTRACE_KERNEL_SYMBOLS_FROM_USERSPACE) {
- dtrace_kernel_symbol_mode = DTRACE_KERNEL_SYMBOLS_FROM_KERNEL;
- }
- lck_mtx_unlock(&dtrace_lock);
-#endif /* __APPLE__ */
-
- return (0);
-}
-
-/*ARGSUSED*/
-static int
-dtrace_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
-{
-#pragma unused(flag, otyp, cred_p) /* __APPLE__ */
- minor_t minor = getminor(dev);
- dtrace_state_t *state;
-
-#if !defined(__APPLE__)
- if (minor == DTRACEMNRN_HELPER)
- return (0);
-#else
- /* Darwin puts Helper on its own major device. */
-#endif /* __APPLE__ */
-
- state = ddi_get_soft_state(dtrace_softstate, minor);
-
- lck_mtx_lock(&cpu_lock);
- lck_mtx_lock(&dtrace_lock);
-
- if (state->dts_anon) {
- /*
- * There is anonymous state. Destroy that first.
- */
- ASSERT(dtrace_anon.dta_state == NULL);
- dtrace_state_destroy(state->dts_anon);
- }
-
- 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);
-
- lck_mtx_unlock(&dtrace_lock);
- lck_mtx_unlock(&cpu_lock);
-
-#if defined(__APPLE__)
- /*
- * Lock ordering requires the dof mode lock be taken before
- * the dtrace_lock.
- */
- lck_rw_lock_exclusive(&dtrace_dof_mode_lock);
- lck_mtx_lock(&dtrace_lock);
-
- if (dtrace_opens == 0) {
- /*
- * If we are currently lazy-off, and this is the last close, transition to
- * lazy state.
- */
- if (dtrace_dof_mode == DTRACE_DOF_MODE_LAZY_OFF) {
- dtrace_dof_mode = DTRACE_DOF_MODE_LAZY_ON;
- }
-
- /*
- * If we are the last dtrace client, switch back to lazy (from userspace) symbols
- */
- if (dtrace_kernel_symbol_mode == DTRACE_KERNEL_SYMBOLS_FROM_KERNEL) {
- dtrace_kernel_symbol_mode = DTRACE_KERNEL_SYMBOLS_FROM_USERSPACE;
- }
- }
-
- lck_mtx_unlock(&dtrace_lock);
- lck_rw_unlock_exclusive(&dtrace_dof_mode_lock);
-
- /*
- * Kext probes may be retained past the end of the kext's lifespan. The
- * probes are kept until the last reference to them has been removed.
- * Since closing an active dtrace context is likely to drop that last reference,
- * lets take a shot at cleaning out the orphaned probes now.
- */
- dtrace_module_unloaded(NULL);
-#endif /* __APPLE__ */
-
- return (0);
-}
-
-#if !defined(__APPLE__)
-/*ARGSUSED*/
-static int
-dtrace_ioctl_helper(int cmd, intptr_t arg, int *rv)
-{
- int rval;
- dof_helper_t help, *dhp = NULL;
-
- switch (cmd) {
- case DTRACEHIOC_ADDDOF:
- if (copyin((void *)arg, &help, sizeof (help)) != 0) {
- dtrace_dof_error(NULL, "failed to copyin DOF helper");
- return (EFAULT);
- }
-
- dhp = &help;
- arg = (intptr_t)help.dofhp_dof;
- /*FALLTHROUGH*/
-
- case DTRACEHIOC_ADD: {
- dof_hdr_t *dof = dtrace_dof_copyin(arg, &rval);
-
- if (dof == NULL)
- return (rval);
-
- mutex_enter(&dtrace_lock);
-
- /*
- * dtrace_helper_slurp() takes responsibility for the dof --
- * it may free it now or it may save it and free it later.
- */
- if ((rval = dtrace_helper_slurp(dof, dhp)) != -1) {
- *rv = rval;
- rval = 0;
- } else {
- rval = EINVAL;
- }
-
- mutex_exit(&dtrace_lock);
- return (rval);
- }
-
- case DTRACEHIOC_REMOVE: {
- mutex_enter(&dtrace_lock);
- rval = dtrace_helper_destroygen(arg);
- mutex_exit(&dtrace_lock);
-
- return (rval);
- }
-
- default:
- break;
- }
-
- return (ENOTTY);
-}
-
-/*ARGSUSED*/
-static int
-dtrace_ioctl(dev_t dev, u_long cmd, intptr_t arg, int md, cred_t *cr, int *rv)
-{
- minor_t minor = getminor(dev);
- dtrace_state_t *state;
- int rval;
-
- if (minor == DTRACEMNRN_HELPER)
- return (dtrace_ioctl_helper(cmd, arg, rv));
-
- state = ddi_get_soft_state(dtrace_softstate, minor);
-
- if (state->dts_anon) {
- ASSERT(dtrace_anon.dta_state == NULL);
- state = state->dts_anon;
- }
-
- switch (cmd) {
- case DTRACEIOC_PROVIDER: {
- dtrace_providerdesc_t pvd;
- dtrace_provider_t *pvp;
-
- if (copyin((void *)arg, &pvd, sizeof (pvd)) != 0)
- return (EFAULT);
-
- pvd.dtvd_name[DTRACE_PROVNAMELEN - 1] = '\0';
- lck_mtx_lock(&dtrace_provider_lock);
-
- for (pvp = dtrace_provider; pvp != NULL; pvp = pvp->dtpv_next) {
- if (strcmp(pvp->dtpv_name, pvd.dtvd_name) == 0)
- break;
- }
-
- lck_mtx_unlock(&dtrace_provider_lock);
-
- if (pvp == NULL)
- return (ESRCH);
-
- bcopy(&pvp->dtpv_priv, &pvd.dtvd_priv, sizeof (dtrace_ppriv_t));
- bcopy(&pvp->dtpv_attr, &pvd.dtvd_attr, sizeof (dtrace_pattr_t));
- if (copyout(&pvd, (void *)arg, sizeof (pvd)) != 0)
- return (EFAULT);
-
- return (0);
- }
-
- case DTRACEIOC_EPROBE: {
- dtrace_eprobedesc_t epdesc;
- dtrace_ecb_t *ecb;
- dtrace_action_t *act;
- void *buf;
- size_t size;
- uintptr_t dest;
- int nrecs;
-
- if (copyin((void *)arg, &epdesc, sizeof (epdesc)) != 0)
- return (EFAULT);
-
- lck_mtx_lock(&dtrace_lock);
-
- if ((ecb = dtrace_epid2ecb(state, epdesc.dtepd_epid)) == NULL) {
- lck_mtx_unlock(&dtrace_lock);
- return (EINVAL);
- }
-
- if (ecb->dte_probe == NULL) {
- lck_mtx_unlock(&dtrace_lock);
- return (EINVAL);
- }
-
- epdesc.dtepd_probeid = ecb->dte_probe->dtpr_id;
- epdesc.dtepd_uarg = ecb->dte_uarg;
- epdesc.dtepd_size = ecb->dte_size;
-
- nrecs = epdesc.dtepd_nrecs;
- epdesc.dtepd_nrecs = 0;
- for (act = ecb->dte_action; act != NULL; act = act->dta_next) {
- if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple)
- continue;
-
- epdesc.dtepd_nrecs++;
- }
-
- /*
- * Now that we have the size, we need to allocate a temporary
- * buffer in which to store the complete description. We need
- * the temporary buffer to be able to drop dtrace_lock()
- * across the copyout(), below.
- */
- size = sizeof (dtrace_eprobedesc_t) +
- (epdesc.dtepd_nrecs * sizeof (dtrace_recdesc_t));
-
- buf = kmem_alloc(size, KM_SLEEP);
- dest = (uintptr_t)buf;
-
- bcopy(&epdesc, (void *)dest, sizeof (epdesc));
- dest += offsetof(dtrace_eprobedesc_t, dtepd_rec[0]);
-
- for (act = ecb->dte_action; act != NULL; act = act->dta_next) {
- if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple)
- continue;
-
- if (nrecs-- == 0)
- break;
-
- bcopy(&act->dta_rec, (void *)dest,
- sizeof (dtrace_recdesc_t));
- dest += sizeof (dtrace_recdesc_t);
- }
-
- lck_mtx_unlock(&dtrace_lock);
-
- if (copyout(buf, (void *)arg, dest - (uintptr_t)buf) != 0) {
- kmem_free(buf, size);
- return (EFAULT);
- }
-
- kmem_free(buf, size);
- return (0);
- }
-
- case DTRACEIOC_AGGDESC: {
- dtrace_aggdesc_t aggdesc;
- dtrace_action_t *act;
- dtrace_aggregation_t *agg;
- int nrecs;
- uint32_t offs;
- dtrace_recdesc_t *lrec;
- void *buf;
- size_t size;
- uintptr_t dest;
-
- if (copyin((void *)arg, &aggdesc, sizeof (aggdesc)) != 0)
- return (EFAULT);
-
- lck_mtx_lock(&dtrace_lock);
-
- if ((agg = dtrace_aggid2agg(state, aggdesc.dtagd_id)) == NULL) {
- lck_mtx_unlock(&dtrace_lock);
- return (EINVAL);
- }
-
- aggdesc.dtagd_epid = agg->dtag_ecb->dte_epid;
-
- nrecs = aggdesc.dtagd_nrecs;
- aggdesc.dtagd_nrecs = 0;
-
- offs = agg->dtag_base;
- lrec = &agg->dtag_action.dta_rec;
- aggdesc.dtagd_size = lrec->dtrd_offset + lrec->dtrd_size - offs;
-
- for (act = agg->dtag_first; ; act = act->dta_next) {
- ASSERT(act->dta_intuple ||
- DTRACEACT_ISAGG(act->dta_kind));
-
- /*
- * If this action has a record size of zero, it
- * denotes an argument to the aggregating action.
- * Because the presence of this record doesn't (or
- * shouldn't) affect the way the data is interpreted,
- * we don't copy it out to save user-level the
- * confusion of dealing with a zero-length record.
- */
- if (act->dta_rec.dtrd_size == 0) {
- ASSERT(agg->dtag_hasarg);
- continue;
- }
-
- aggdesc.dtagd_nrecs++;
-
- if (act == &agg->dtag_action)
- break;
- }
-
- /*
- * Now that we have the size, we need to allocate a temporary
- * buffer in which to store the complete description. We need
- * the temporary buffer to be able to drop dtrace_lock()
- * across the copyout(), below.
- */
- size = sizeof (dtrace_aggdesc_t) +
- (aggdesc.dtagd_nrecs * sizeof (dtrace_recdesc_t));
-
- buf = kmem_alloc(size, KM_SLEEP);
- dest = (uintptr_t)buf;
-
- bcopy(&aggdesc, (void *)dest, sizeof (aggdesc));
- dest += offsetof(dtrace_aggdesc_t, dtagd_rec[0]);
-
- for (act = agg->dtag_first; ; act = act->dta_next) {
- dtrace_recdesc_t rec = act->dta_rec;
-
- /*
- * See the comment in the above loop for why we pass
- * over zero-length records.
- */
- if (rec.dtrd_size == 0) {
- ASSERT(agg->dtag_hasarg);
- continue;
- }
-
- if (nrecs-- == 0)
- break;
-
- rec.dtrd_offset -= offs;
- bcopy(&rec, (void *)dest, sizeof (rec));
- dest += sizeof (dtrace_recdesc_t);
-
- if (act == &agg->dtag_action)
- break;
- }
-
- lck_mtx_unlock(&dtrace_lock);
-
- if (copyout(buf, (void *)arg, dest - (uintptr_t)buf) != 0) {
- kmem_free(buf, size);
- return (EFAULT);
- }
-
- kmem_free(buf, size);
- return (0);
- }
-
- case DTRACEIOC_ENABLE: {
- dof_hdr_t *dof;
- dtrace_enabling_t *enab = NULL;
- dtrace_vstate_t *vstate;
- int err = 0;
-
- *rv = 0;
-
- /*
- * If a NULL argument has been passed, we take this as our
- * cue to reevaluate our enablings.
- */
- if (arg == NULL) {
- dtrace_enabling_matchall();
-
- return (0);
- }
-
- if ((dof = dtrace_dof_copyin(arg, &rval)) == NULL)
- return (rval);
-
- lck_mtx_lock(&cpu_lock);
- lck_mtx_lock(&dtrace_lock);
- vstate = &state->dts_vstate;
-
- if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) {
- lck_mtx_unlock(&dtrace_lock);
- lck_mtx_unlock(&cpu_lock);
- dtrace_dof_destroy(dof);
- return (EBUSY);
- }
-
- if (dtrace_dof_slurp(dof, vstate, cr, &enab, 0, B_TRUE) != 0) {
- lck_mtx_unlock(&dtrace_lock);
- lck_mtx_unlock(&cpu_lock);
- dtrace_dof_destroy(dof);
- return (EINVAL);
- }
-
- if ((rval = dtrace_dof_options(dof, state)) != 0) {
- dtrace_enabling_destroy(enab);
- lck_mtx_unlock(&dtrace_lock);
- lck_mtx_unlock(&cpu_lock);
- dtrace_dof_destroy(dof);
- return (rval);
- }
-
- if ((err = dtrace_enabling_match(enab, rv)) == 0) {
- err = dtrace_enabling_retain(enab);
- } else {
- dtrace_enabling_destroy(enab);
- }
-
- lck_mtx_unlock(&cpu_lock);
- lck_mtx_unlock(&dtrace_lock);
- dtrace_dof_destroy(dof);
-
- return (err);
- }
-
- case DTRACEIOC_REPLICATE: {
- dtrace_repldesc_t desc;
- dtrace_probedesc_t *match = &desc.dtrpd_match;
- dtrace_probedesc_t *create = &desc.dtrpd_create;
- int err;
-
- if (copyin((void *)arg, &desc, sizeof (desc)) != 0)
- return (EFAULT);
-
- match->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0';
- match->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0';
- match->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0';
- match->dtpd_name[DTRACE_NAMELEN - 1] = '\0';
-
- create->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0';
- create->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0';
- create->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0';
- create->dtpd_name[DTRACE_NAMELEN - 1] = '\0';
-
- lck_mtx_lock(&dtrace_lock);
- err = dtrace_enabling_replicate(state, match, create);
- lck_mtx_unlock(&dtrace_lock);
-
- return (err);
- }
-
- case DTRACEIOC_PROBEMATCH:
- case DTRACEIOC_PROBES: {
- 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) {
- lck_mtx_lock(&dtrace_provider_lock);
- dtrace_probe_provide(&desc, NULL);
- lck_mtx_unlock(&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);
-
- lck_mtx_lock(&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) {
- lck_mtx_unlock(&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) {
- lck_mtx_unlock(&dtrace_lock);
- return (ESRCH);
- }
-
- dtrace_probe_description(probe, &desc);
- lck_mtx_unlock(&dtrace_lock);
-
- if (copyout(&desc, (void *)arg, sizeof (desc)) != 0)
- return (EFAULT);
-
- return (0);
- }
-
- case DTRACEIOC_PROBEARG: {
- dtrace_argdesc_t desc;
- dtrace_probe_t *probe;
- dtrace_provider_t *prov;
-
- if (copyin((void *)arg, &desc, sizeof (desc)) != 0)
- return (EFAULT);
-
- if (desc.dtargd_id == DTRACE_IDNONE)
- return (EINVAL);
-
- if (desc.dtargd_ndx == DTRACE_ARGNONE)
- return (EINVAL);
-
- lck_mtx_lock(&dtrace_provider_lock);
- lck_mtx_lock(&mod_lock);
- lck_mtx_lock(&dtrace_lock);
-
- if (desc.dtargd_id > dtrace_nprobes) {
- lck_mtx_unlock(&dtrace_lock);
- lck_mtx_unlock(&mod_lock);
- lck_mtx_unlock(&dtrace_provider_lock);
- return (EINVAL);
- }
-
- if ((probe = dtrace_probes[desc.dtargd_id - 1]) == NULL) {
- lck_mtx_unlock(&dtrace_lock);
- lck_mtx_unlock(&mod_lock);
- lck_mtx_unlock(&dtrace_provider_lock);
- return (EINVAL);
- }
-
- lck_mtx_unlock(&dtrace_lock);
-
- prov = probe->dtpr_provider;
-
- if (prov->dtpv_pops.dtps_getargdesc == NULL) {
- /*
- * There isn't any typed information for this probe.
- * Set the argument number to DTRACE_ARGNONE.
- */
- desc.dtargd_ndx = DTRACE_ARGNONE;
- } else {
- desc.dtargd_native[0] = '\0';
- desc.dtargd_xlate[0] = '\0';
- desc.dtargd_mapping = desc.dtargd_ndx;
-
- prov->dtpv_pops.dtps_getargdesc(prov->dtpv_arg,
- probe->dtpr_id, probe->dtpr_arg, &desc);
- }
-
- lck_mtx_unlock(&mod_lock);
- lck_mtx_unlock(&dtrace_provider_lock);
-
- if (copyout(&desc, (void *)arg, sizeof (desc)) != 0)
- return (EFAULT);
-
- return (0);
- }
-
- case DTRACEIOC_GO: {
- processorid_t cpuid;
- rval = dtrace_state_go(state, &cpuid);
-
- if (rval != 0)
- return (rval);
-
- if (copyout(&cpuid, (void *)arg, sizeof (cpuid)) != 0)
- return (EFAULT);
-
- return (0);
- }
-
- case DTRACEIOC_STOP: {
- processorid_t cpuid;
-
- lck_mtx_lock(&dtrace_lock);
- rval = dtrace_state_stop(state, &cpuid);
- lck_mtx_unlock(&dtrace_lock);
-
- if (rval != 0)
- return (rval);
-
- if (copyout(&cpuid, (void *)arg, sizeof (cpuid)) != 0)
- return (EFAULT);
-
- return (0);
- }
-
- case DTRACEIOC_DOFGET: {
- dof_hdr_t hdr, *dof;
- uint64_t len;
-
- if (copyin((void *)arg, &hdr, sizeof (hdr)) != 0)
- return (EFAULT);
-
- lck_mtx_lock(&dtrace_lock);
- dof = dtrace_dof_create(state);
- lck_mtx_unlock(&dtrace_lock);
-
- len = MIN(hdr.dofh_loadsz, dof->dofh_loadsz);
- rval = copyout(dof, (void *)arg, len);
- dtrace_dof_destroy(dof);
-
- return (rval == 0 ? 0 : EFAULT);
- }
-
- case DTRACEIOC_AGGSNAP:
- case DTRACEIOC_BUFSNAP: {
- dtrace_bufdesc_t desc;
- caddr_t cached;
- dtrace_buffer_t *buf;
-
- if (copyin((void *)arg, &desc, sizeof (desc)) != 0)
- return (EFAULT);
-
- if (desc.dtbd_cpu < 0 || desc.dtbd_cpu >= NCPU)
- return (EINVAL);
-
- lck_mtx_lock(&dtrace_lock);
-
- if (cmd == DTRACEIOC_BUFSNAP) {
- buf = &state->dts_buffer[desc.dtbd_cpu];
- } else {
- buf = &state->dts_aggbuffer[desc.dtbd_cpu];
- }
-
- if (buf->dtb_flags & (DTRACEBUF_RING | DTRACEBUF_FILL)) {
- size_t sz = buf->dtb_offset;
-
- if (state->dts_activity != DTRACE_ACTIVITY_STOPPED) {
- lck_mtx_unlock(&dtrace_lock);
- return (EBUSY);
- }
-
- /*
- * If this buffer has already been consumed, we're
- * going to indicate that there's nothing left here
- * to consume.
- */
- if (buf->dtb_flags & DTRACEBUF_CONSUMED) {
- lck_mtx_unlock(&dtrace_lock);
-
- desc.dtbd_size = 0;
- desc.dtbd_drops = 0;
- desc.dtbd_errors = 0;
- desc.dtbd_oldest = 0;
- sz = sizeof (desc);
-
- if (copyout(&desc, (void *)arg, sz) != 0)
- return (EFAULT);
-
- return (0);
- }
-
- /*
- * If this is a ring buffer that has wrapped, we want
- * to copy the whole thing out.
- */
- if (buf->dtb_flags & DTRACEBUF_WRAPPED) {
- dtrace_buffer_polish(buf);
- sz = buf->dtb_size;
- }
-
- if (copyout(buf->dtb_tomax, desc.dtbd_data, sz) != 0) {
- lck_mtx_unlock(&dtrace_lock);
- return (EFAULT);
- }
-
- desc.dtbd_size = sz;
- desc.dtbd_drops = buf->dtb_drops;
- desc.dtbd_errors = buf->dtb_errors;
- desc.dtbd_oldest = buf->dtb_xamot_offset;
-
- lck_mtx_unlock(&dtrace_lock);
-
- if (copyout(&desc, (void *)arg, sizeof (desc)) != 0)
- return (EFAULT);
-
- buf->dtb_flags |= DTRACEBUF_CONSUMED;
-
- return (0);
- }
-
- if (buf->dtb_tomax == NULL) {
- ASSERT(buf->dtb_xamot == NULL);
- lck_mtx_unlock(&dtrace_lock);
- return (ENOENT);
- }
-
- cached = buf->dtb_tomax;
- ASSERT(!(buf->dtb_flags & DTRACEBUF_NOSWITCH));
-
- dtrace_xcall(desc.dtbd_cpu,
- (dtrace_xcall_t)dtrace_buffer_switch, buf);
-
- state->dts_errors += buf->dtb_xamot_errors;
-
- /*
- * If the buffers did not actually switch, then the cross call
- * did not take place -- presumably because the given CPU is
- * not in the ready set. If this is the case, we'll return
- * ENOENT.
- */
- if (buf->dtb_tomax == cached) {
- ASSERT(buf->dtb_xamot != cached);
- lck_mtx_unlock(&dtrace_lock);
- return (ENOENT);
- }
-
- ASSERT(cached == buf->dtb_xamot);
-
- /*
- * We have our snapshot; now copy it out.
- */
- if (copyout(buf->dtb_xamot, desc.dtbd_data,
- buf->dtb_xamot_offset) != 0) {
- lck_mtx_unlock(&dtrace_lock);
- return (EFAULT);
- }
-
- desc.dtbd_size = buf->dtb_xamot_offset;
- desc.dtbd_drops = buf->dtb_xamot_drops;
- desc.dtbd_errors = buf->dtb_xamot_errors;
- desc.dtbd_oldest = 0;
-
- lck_mtx_unlock(&dtrace_lock);
-
- /*
- * Finally, copy out the buffer description.
- */
- if (copyout(&desc, (void *)arg, sizeof (desc)) != 0)
- return (EFAULT);
-
- return (0);
- }
-
- case DTRACEIOC_CONF: {
- dtrace_conf_t conf;
-
- bzero(&conf, sizeof (conf));
- conf.dtc_difversion = DIF_VERSION;
- conf.dtc_difintregs = DIF_DIR_NREGS;
- conf.dtc_diftupregs = DIF_DTR_NREGS;
- conf.dtc_ctfmodel = CTF_MODEL_NATIVE;
-
- if (copyout(&conf, (void *)arg, sizeof (conf)) != 0)
- return (EFAULT);
-
- return (0);
- }
-
- case DTRACEIOC_STATUS: {
- dtrace_status_t stat;
- dtrace_dstate_t *dstate;
- int i, j;
- uint64_t nerrs;
-
- /*
- * See the comment in dtrace_state_deadman() for the reason
- * for setting dts_laststatus to INT64_MAX before setting
- * it to the correct value.
- */
- state->dts_laststatus = INT64_MAX;
- dtrace_membar_producer();
- state->dts_laststatus = dtrace_gethrtime();
-
- bzero(&stat, sizeof (stat));
-
- lck_mtx_lock(&dtrace_lock);
-
- if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) {
- lck_mtx_unlock(&dtrace_lock);
- return (ENOENT);
- }
-
- if (state->dts_activity == DTRACE_ACTIVITY_DRAINING)
- stat.dtst_exiting = 1;
-
- nerrs = state->dts_errors;
- dstate = &state->dts_vstate.dtvs_dynvars;
-
- for (i = 0; i < NCPU; i++) {
- dtrace_dstate_percpu_t *dcpu = &dstate->dtds_percpu[i];
-
- stat.dtst_dyndrops += dcpu->dtdsc_drops;
- stat.dtst_dyndrops_dirty += dcpu->dtdsc_dirty_drops;
- stat.dtst_dyndrops_rinsing += dcpu->dtdsc_rinsing_drops;
-
- if (state->dts_buffer[i].dtb_flags & DTRACEBUF_FULL)
- stat.dtst_filled++;
-
- nerrs += state->dts_buffer[i].dtb_errors;