]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/cddl/dev/dtrace/dtrace_ioctl.c
MFC r262665:
[FreeBSD/stable/10.git] / sys / cddl / dev / dtrace / dtrace_ioctl.c
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  *
21  * $FreeBSD$
22  *
23  */
24
25 static int dtrace_verbose_ioctl;
26 SYSCTL_INT(_debug_dtrace, OID_AUTO, verbose_ioctl, CTLFLAG_RW,
27     &dtrace_verbose_ioctl, 0, "log DTrace ioctls");
28
29 #define DTRACE_IOCTL_PRINTF(fmt, ...)   if (dtrace_verbose_ioctl) printf(fmt, ## __VA_ARGS__ )
30
31 static int
32 dtrace_ioctl_helper(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
33     struct thread *td)
34 {
35         int rval;
36         dof_helper_t *dhp = NULL;
37         dof_hdr_t *dof = NULL;
38
39         switch (cmd) {
40         case DTRACEHIOC_ADDDOF:
41                 dhp = (dof_helper_t *)addr;
42                 /* XXX all because dofhp_dof is 64 bit */
43                 addr = (caddr_t)(vm_offset_t)dhp->dofhp_dof;
44                 /* FALLTHROUGH */
45         case DTRACEHIOC_ADD:
46                 dof = dtrace_dof_copyin((intptr_t)addr, &rval);
47
48                 if (dof == NULL)
49                         return (rval);
50
51                 mutex_enter(&dtrace_lock);
52                 if ((rval = dtrace_helper_slurp((dof_hdr_t *)dof, dhp)) != -1) {
53                         if (dhp) {
54                                 dhp->gen = rval;
55                                 copyout(dhp, addr, sizeof(*dhp));
56                         }
57                         rval = 0;
58                 } else {
59                         rval = EINVAL;
60                 }
61                 mutex_exit(&dtrace_lock);
62                 return (rval);
63         case DTRACEHIOC_REMOVE:
64                 mutex_enter(&dtrace_lock);
65                 rval = dtrace_helper_destroygen((int)*addr);
66                 mutex_exit(&dtrace_lock);
67
68                 return (rval);
69         default:
70                 break;
71         }
72
73         return (ENOTTY);
74 }
75
76 /* ARGSUSED */
77 static int
78 dtrace_ioctl(struct cdev *dev, u_long cmd, caddr_t addr,
79     int flags __unused, struct thread *td)
80 {
81 #if __FreeBSD_version < 800039
82         dtrace_state_t *state = dev->si_drv1;
83 #else
84         dtrace_state_t *state;
85         devfs_get_cdevpriv((void **) &state);
86 #endif
87         int error = 0;
88         if (state == NULL)
89                 return (EINVAL);
90
91         if (state->dts_anon) {
92                 ASSERT(dtrace_anon.dta_state == NULL);
93                 state = state->dts_anon;
94         }
95
96         switch (cmd) {
97         case DTRACEIOC_AGGDESC: {
98                 dtrace_aggdesc_t **paggdesc = (dtrace_aggdesc_t **) addr;
99                 dtrace_aggdesc_t aggdesc;
100                 dtrace_action_t *act;
101                 dtrace_aggregation_t *agg;
102                 int nrecs;
103                 uint32_t offs;
104                 dtrace_recdesc_t *lrec;
105                 void *buf;
106                 size_t size;
107                 uintptr_t dest;
108
109                 DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_AGGDESC\n",__func__,__LINE__);
110
111                 if (copyin((void *) *paggdesc, &aggdesc, sizeof (aggdesc)) != 0)
112                         return (EFAULT);
113
114                 mutex_enter(&dtrace_lock);
115
116                 if ((agg = dtrace_aggid2agg(state, aggdesc.dtagd_id)) == NULL) {
117                         mutex_exit(&dtrace_lock);
118                         return (EINVAL);
119                 }
120
121                 aggdesc.dtagd_epid = agg->dtag_ecb->dte_epid;
122
123                 nrecs = aggdesc.dtagd_nrecs;
124                 aggdesc.dtagd_nrecs = 0;
125
126                 offs = agg->dtag_base;
127                 lrec = &agg->dtag_action.dta_rec;
128                 aggdesc.dtagd_size = lrec->dtrd_offset + lrec->dtrd_size - offs;
129
130                 for (act = agg->dtag_first; ; act = act->dta_next) {
131                         ASSERT(act->dta_intuple ||
132                             DTRACEACT_ISAGG(act->dta_kind));
133
134                         /*
135                          * If this action has a record size of zero, it
136                          * denotes an argument to the aggregating action.
137                          * Because the presence of this record doesn't (or
138                          * shouldn't) affect the way the data is interpreted,
139                          * we don't copy it out to save user-level the
140                          * confusion of dealing with a zero-length record.
141                          */
142                         if (act->dta_rec.dtrd_size == 0) {
143                                 ASSERT(agg->dtag_hasarg);
144                                 continue;
145                         }
146
147                         aggdesc.dtagd_nrecs++;
148
149                         if (act == &agg->dtag_action)
150                                 break;
151                 }
152
153                 /*
154                  * Now that we have the size, we need to allocate a temporary
155                  * buffer in which to store the complete description.  We need
156                  * the temporary buffer to be able to drop dtrace_lock()
157                  * across the copyout(), below.
158                  */
159                 size = sizeof (dtrace_aggdesc_t) +
160                     (aggdesc.dtagd_nrecs * sizeof (dtrace_recdesc_t));
161
162                 buf = kmem_alloc(size, KM_SLEEP);
163                 dest = (uintptr_t)buf;
164
165                 bcopy(&aggdesc, (void *)dest, sizeof (aggdesc));
166                 dest += offsetof(dtrace_aggdesc_t, dtagd_rec[0]);
167
168                 for (act = agg->dtag_first; ; act = act->dta_next) {
169                         dtrace_recdesc_t rec = act->dta_rec;
170
171                         /*
172                          * See the comment in the above loop for why we pass
173                          * over zero-length records.
174                          */
175                         if (rec.dtrd_size == 0) {
176                                 ASSERT(agg->dtag_hasarg);
177                                 continue;
178                         }
179
180                         if (nrecs-- == 0)
181                                 break;
182
183                         rec.dtrd_offset -= offs;
184                         bcopy(&rec, (void *)dest, sizeof (rec));
185                         dest += sizeof (dtrace_recdesc_t);
186
187                         if (act == &agg->dtag_action)
188                                 break;
189                 }
190
191                 mutex_exit(&dtrace_lock);
192
193                 if (copyout(buf, (void *) *paggdesc, dest - (uintptr_t)buf) != 0) {
194                         kmem_free(buf, size);
195                         return (EFAULT);
196                 }
197
198                 kmem_free(buf, size);
199                 return (0);
200         }
201         case DTRACEIOC_AGGSNAP:
202         case DTRACEIOC_BUFSNAP: {
203                 dtrace_bufdesc_t **pdesc = (dtrace_bufdesc_t **) addr;
204                 dtrace_bufdesc_t desc;
205                 caddr_t cached;
206                 dtrace_buffer_t *buf;
207
208                 dtrace_debug_output();
209
210                 if (copyin((void *) *pdesc, &desc, sizeof (desc)) != 0)
211                         return (EFAULT);
212
213                 DTRACE_IOCTL_PRINTF("%s(%d): %s curcpu %d cpu %d\n",
214                     __func__,__LINE__,
215                     cmd == DTRACEIOC_AGGSNAP ?
216                     "DTRACEIOC_AGGSNAP":"DTRACEIOC_BUFSNAP",
217                     curcpu, desc.dtbd_cpu);
218
219                 if (desc.dtbd_cpu >= NCPU)
220                         return (ENOENT);
221                 if (pcpu_find(desc.dtbd_cpu) == NULL)
222                         return (ENOENT);
223
224                 mutex_enter(&dtrace_lock);
225
226                 if (cmd == DTRACEIOC_BUFSNAP) {
227                         buf = &state->dts_buffer[desc.dtbd_cpu];
228                 } else {
229                         buf = &state->dts_aggbuffer[desc.dtbd_cpu];
230                 }
231
232                 if (buf->dtb_flags & (DTRACEBUF_RING | DTRACEBUF_FILL)) {
233                         size_t sz = buf->dtb_offset;
234
235                         if (state->dts_activity != DTRACE_ACTIVITY_STOPPED) {
236                                 mutex_exit(&dtrace_lock);
237                                 return (EBUSY);
238                         }
239
240                         /*
241                          * If this buffer has already been consumed, we're
242                          * going to indicate that there's nothing left here
243                          * to consume.
244                          */
245                         if (buf->dtb_flags & DTRACEBUF_CONSUMED) {
246                                 mutex_exit(&dtrace_lock);
247
248                                 desc.dtbd_size = 0;
249                                 desc.dtbd_drops = 0;
250                                 desc.dtbd_errors = 0;
251                                 desc.dtbd_oldest = 0;
252                                 sz = sizeof (desc);
253
254                                 if (copyout(&desc, (void *) *pdesc, sz) != 0)
255                                         return (EFAULT);
256
257                                 return (0);
258                         }
259
260                         /*
261                          * If this is a ring buffer that has wrapped, we want
262                          * to copy the whole thing out.
263                          */
264                         if (buf->dtb_flags & DTRACEBUF_WRAPPED) {
265                                 dtrace_buffer_polish(buf);
266                                 sz = buf->dtb_size;
267                         }
268
269                         if (copyout(buf->dtb_tomax, desc.dtbd_data, sz) != 0) {
270                                 mutex_exit(&dtrace_lock);
271                                 return (EFAULT);
272                         }
273
274                         desc.dtbd_size = sz;
275                         desc.dtbd_drops = buf->dtb_drops;
276                         desc.dtbd_errors = buf->dtb_errors;
277                         desc.dtbd_oldest = buf->dtb_xamot_offset;
278                         desc.dtbd_timestamp = dtrace_gethrtime();
279
280                         mutex_exit(&dtrace_lock);
281
282                         if (copyout(&desc, (void *) *pdesc, sizeof (desc)) != 0)
283                                 return (EFAULT);
284
285                         buf->dtb_flags |= DTRACEBUF_CONSUMED;
286
287                         return (0);
288                 }
289
290                 if (buf->dtb_tomax == NULL) {
291                         ASSERT(buf->dtb_xamot == NULL);
292                         mutex_exit(&dtrace_lock);
293                         return (ENOENT);
294                 }
295
296                 cached = buf->dtb_tomax;
297                 ASSERT(!(buf->dtb_flags & DTRACEBUF_NOSWITCH));
298
299                 dtrace_xcall(desc.dtbd_cpu,
300                     (dtrace_xcall_t)dtrace_buffer_switch, buf);
301
302                 state->dts_errors += buf->dtb_xamot_errors;
303
304                 /*
305                  * If the buffers did not actually switch, then the cross call
306                  * did not take place -- presumably because the given CPU is
307                  * not in the ready set.  If this is the case, we'll return
308                  * ENOENT.
309                  */
310                 if (buf->dtb_tomax == cached) {
311                         ASSERT(buf->dtb_xamot != cached);
312                         mutex_exit(&dtrace_lock);
313                         return (ENOENT);
314                 }
315
316                 ASSERT(cached == buf->dtb_xamot);
317
318                 DTRACE_IOCTL_PRINTF("%s(%d): copyout the buffer snapshot\n",__func__,__LINE__);
319
320                 /*
321                  * We have our snapshot; now copy it out.
322                  */
323                 if (copyout(buf->dtb_xamot, desc.dtbd_data,
324                     buf->dtb_xamot_offset) != 0) {
325                         mutex_exit(&dtrace_lock);
326                         return (EFAULT);
327                 }
328
329                 desc.dtbd_size = buf->dtb_xamot_offset;
330                 desc.dtbd_drops = buf->dtb_xamot_drops;
331                 desc.dtbd_errors = buf->dtb_xamot_errors;
332                 desc.dtbd_oldest = 0;
333                 desc.dtbd_timestamp = buf->dtb_switched;
334
335                 mutex_exit(&dtrace_lock);
336
337                 DTRACE_IOCTL_PRINTF("%s(%d): copyout buffer desc: size %zd drops %lu errors %lu\n",__func__,__LINE__,(size_t) desc.dtbd_size,(u_long) desc.dtbd_drops,(u_long) desc.dtbd_errors);
338
339                 /*
340                  * Finally, copy out the buffer description.
341                  */
342                 if (copyout(&desc, (void *) *pdesc, sizeof (desc)) != 0)
343                         return (EFAULT);
344
345                 return (0);
346         }
347         case DTRACEIOC_CONF: {
348                 dtrace_conf_t conf;
349
350                 DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_CONF\n",__func__,__LINE__);
351
352                 bzero(&conf, sizeof (conf));
353                 conf.dtc_difversion = DIF_VERSION;
354                 conf.dtc_difintregs = DIF_DIR_NREGS;
355                 conf.dtc_diftupregs = DIF_DTR_NREGS;
356                 conf.dtc_ctfmodel = CTF_MODEL_NATIVE;
357
358                 *((dtrace_conf_t *) addr) = conf;
359
360                 return (0);
361         }
362         case DTRACEIOC_DOFGET: {
363                 dof_hdr_t **pdof = (dof_hdr_t **) addr;
364                 dof_hdr_t hdr, *dof = *pdof;
365                 int rval;
366                 uint64_t len;
367
368                 DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_DOFGET\n",__func__,__LINE__);
369
370                 if (copyin((void *)dof, &hdr, sizeof (hdr)) != 0)
371                         return (EFAULT);
372
373                 mutex_enter(&dtrace_lock);
374                 dof = dtrace_dof_create(state);
375                 mutex_exit(&dtrace_lock);
376
377                 len = MIN(hdr.dofh_loadsz, dof->dofh_loadsz);
378                 rval = copyout(dof, (void *) *pdof, len);
379                 dtrace_dof_destroy(dof);
380
381                 return (rval == 0 ? 0 : EFAULT);
382         }
383         case DTRACEIOC_ENABLE: {
384                 dof_hdr_t *dof = NULL;
385                 dtrace_enabling_t *enab = NULL;
386                 dtrace_vstate_t *vstate;
387                 int err = 0;
388                 int rval;
389                 dtrace_enable_io_t *p = (dtrace_enable_io_t *) addr;
390
391                 DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_ENABLE\n",__func__,__LINE__);
392
393                 /*
394                  * If a NULL argument has been passed, we take this as our
395                  * cue to reevaluate our enablings.
396                  */
397                 if (p->dof == NULL) {
398                         dtrace_enabling_matchall();
399
400                         return (0);
401                 }
402
403                 if ((dof = dtrace_dof_copyin((uintptr_t) p->dof, &rval)) == NULL)
404                         return (EINVAL);
405
406                 mutex_enter(&cpu_lock);
407                 mutex_enter(&dtrace_lock);
408                 vstate = &state->dts_vstate;
409
410                 if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) {
411                         mutex_exit(&dtrace_lock);
412                         mutex_exit(&cpu_lock);
413                         dtrace_dof_destroy(dof);
414                         return (EBUSY);
415                 }
416
417                 if (dtrace_dof_slurp(dof, vstate, td->td_ucred, &enab, 0, B_TRUE) != 0) {
418                         mutex_exit(&dtrace_lock);
419                         mutex_exit(&cpu_lock);
420                         dtrace_dof_destroy(dof);
421                         return (EINVAL);
422                 }
423
424                 if ((rval = dtrace_dof_options(dof, state)) != 0) {
425                         dtrace_enabling_destroy(enab);
426                         mutex_exit(&dtrace_lock);
427                         mutex_exit(&cpu_lock);
428                         dtrace_dof_destroy(dof);
429                         return (rval);
430                 }
431
432                 if ((err = dtrace_enabling_match(enab, &p->n_matched)) == 0) {
433                         err = dtrace_enabling_retain(enab);
434                 } else {
435                         dtrace_enabling_destroy(enab);
436                 }
437
438                 mutex_exit(&cpu_lock);
439                 mutex_exit(&dtrace_lock);
440                 dtrace_dof_destroy(dof);
441
442                 return (err);
443         }
444         case DTRACEIOC_EPROBE: {
445                 dtrace_eprobedesc_t **pepdesc = (dtrace_eprobedesc_t **) addr;
446                 dtrace_eprobedesc_t epdesc;
447                 dtrace_ecb_t *ecb;
448                 dtrace_action_t *act;
449                 void *buf;
450                 size_t size;
451                 uintptr_t dest;
452                 int nrecs;
453
454                 DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_EPROBE\n",__func__,__LINE__);
455
456                 if (copyin((void *)*pepdesc, &epdesc, sizeof (epdesc)) != 0)
457                         return (EFAULT);
458
459                 mutex_enter(&dtrace_lock);
460
461                 if ((ecb = dtrace_epid2ecb(state, epdesc.dtepd_epid)) == NULL) {
462                         mutex_exit(&dtrace_lock);
463                         return (EINVAL);
464                 }
465
466                 if (ecb->dte_probe == NULL) {
467                         mutex_exit(&dtrace_lock);
468                         return (EINVAL);
469                 }
470
471                 epdesc.dtepd_probeid = ecb->dte_probe->dtpr_id;
472                 epdesc.dtepd_uarg = ecb->dte_uarg;
473                 epdesc.dtepd_size = ecb->dte_size;
474
475                 nrecs = epdesc.dtepd_nrecs;
476                 epdesc.dtepd_nrecs = 0;
477                 for (act = ecb->dte_action; act != NULL; act = act->dta_next) {
478                         if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple)
479                                 continue;
480
481                         epdesc.dtepd_nrecs++;
482                 }
483
484                 /*
485                  * Now that we have the size, we need to allocate a temporary
486                  * buffer in which to store the complete description.  We need
487                  * the temporary buffer to be able to drop dtrace_lock()
488                  * across the copyout(), below.
489                  */
490                 size = sizeof (dtrace_eprobedesc_t) +
491                     (epdesc.dtepd_nrecs * sizeof (dtrace_recdesc_t));
492
493                 buf = kmem_alloc(size, KM_SLEEP);
494                 dest = (uintptr_t)buf;
495
496                 bcopy(&epdesc, (void *)dest, sizeof (epdesc));
497                 dest += offsetof(dtrace_eprobedesc_t, dtepd_rec[0]);
498
499                 for (act = ecb->dte_action; act != NULL; act = act->dta_next) {
500                         if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple)
501                                 continue;
502
503                         if (nrecs-- == 0)
504                                 break;
505
506                         bcopy(&act->dta_rec, (void *)dest,
507                             sizeof (dtrace_recdesc_t));
508                         dest += sizeof (dtrace_recdesc_t);
509                 }
510
511                 mutex_exit(&dtrace_lock);
512
513                 if (copyout(buf, (void *) *pepdesc, dest - (uintptr_t)buf) != 0) {
514                         kmem_free(buf, size);
515                         return (EFAULT);
516                 }
517
518                 kmem_free(buf, size);
519                 return (0);
520         }
521         case DTRACEIOC_FORMAT: {
522                 dtrace_fmtdesc_t *fmt = (dtrace_fmtdesc_t *) addr;
523                 char *str;
524                 int len;
525
526                 DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_FORMAT\n",__func__,__LINE__);
527
528                 mutex_enter(&dtrace_lock);
529
530                 if (fmt->dtfd_format == 0 ||
531                     fmt->dtfd_format > state->dts_nformats) {
532                         mutex_exit(&dtrace_lock);
533                         return (EINVAL);
534                 }
535
536                 /*
537                  * Format strings are allocated contiguously and they are
538                  * never freed; if a format index is less than the number
539                  * of formats, we can assert that the format map is non-NULL
540                  * and that the format for the specified index is non-NULL.
541                  */
542                 ASSERT(state->dts_formats != NULL);
543                 str = state->dts_formats[fmt->dtfd_format - 1];
544                 ASSERT(str != NULL);
545
546                 len = strlen(str) + 1;
547
548                 if (len > fmt->dtfd_length) {
549                         fmt->dtfd_length = len;
550                 } else {
551                         if (copyout(str, fmt->dtfd_string, len) != 0) {
552                                 mutex_exit(&dtrace_lock);
553                                 return (EINVAL);
554                         }
555                 }
556
557                 mutex_exit(&dtrace_lock);
558                 return (0);
559         }
560         case DTRACEIOC_GO: {
561                 int rval;
562                 processorid_t *cpuid = (processorid_t *) addr;
563
564                 DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_GO\n",__func__,__LINE__);
565
566                 rval = dtrace_state_go(state, cpuid);
567
568                 return (rval);
569         }
570         case DTRACEIOC_PROBEARG: {
571                 dtrace_argdesc_t *desc = (dtrace_argdesc_t *) addr;
572                 dtrace_probe_t *probe;
573                 dtrace_provider_t *prov;
574
575                 DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_PROBEARG\n",__func__,__LINE__);
576
577                 if (desc->dtargd_id == DTRACE_IDNONE)
578                         return (EINVAL);
579
580                 if (desc->dtargd_ndx == DTRACE_ARGNONE)
581                         return (EINVAL);
582
583                 mutex_enter(&dtrace_provider_lock);
584 #if defined(sun)
585                 mutex_enter(&mod_lock);
586 #endif
587                 mutex_enter(&dtrace_lock);
588
589                 if (desc->dtargd_id > dtrace_nprobes) {
590                         mutex_exit(&dtrace_lock);
591 #if defined(sun)
592                         mutex_exit(&mod_lock);
593 #endif
594                         mutex_exit(&dtrace_provider_lock);
595                         return (EINVAL);
596                 }
597
598                 if ((probe = dtrace_probes[desc->dtargd_id - 1]) == NULL) {
599                         mutex_exit(&dtrace_lock);
600 #if defined(sun)
601                         mutex_exit(&mod_lock);
602 #endif
603                         mutex_exit(&dtrace_provider_lock);
604                         return (EINVAL);
605                 }
606
607                 mutex_exit(&dtrace_lock);
608
609                 prov = probe->dtpr_provider;
610
611                 if (prov->dtpv_pops.dtps_getargdesc == NULL) {
612                         /*
613                          * There isn't any typed information for this probe.
614                          * Set the argument number to DTRACE_ARGNONE.
615                          */
616                         desc->dtargd_ndx = DTRACE_ARGNONE;
617                 } else {
618                         desc->dtargd_native[0] = '\0';
619                         desc->dtargd_xlate[0] = '\0';
620                         desc->dtargd_mapping = desc->dtargd_ndx;
621
622                         prov->dtpv_pops.dtps_getargdesc(prov->dtpv_arg,
623                             probe->dtpr_id, probe->dtpr_arg, desc);
624                 }
625
626 #if defined(sun)
627                 mutex_exit(&mod_lock);
628 #endif
629                 mutex_exit(&dtrace_provider_lock);
630
631                 return (0);
632         }
633         case DTRACEIOC_PROBEMATCH:
634         case DTRACEIOC_PROBES: {
635                 dtrace_probedesc_t *p_desc = (dtrace_probedesc_t *) addr;
636                 dtrace_probe_t *probe = NULL;
637                 dtrace_probekey_t pkey;
638                 dtrace_id_t i;
639                 int m = 0;
640                 uint32_t priv = 0;
641                 uid_t uid = 0;
642                 zoneid_t zoneid = 0;
643
644                 DTRACE_IOCTL_PRINTF("%s(%d): %s\n",__func__,__LINE__,
645                     cmd == DTRACEIOC_PROBEMATCH ?
646                     "DTRACEIOC_PROBEMATCH":"DTRACEIOC_PROBES");
647
648                 p_desc->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0';
649                 p_desc->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0';
650                 p_desc->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0';
651                 p_desc->dtpd_name[DTRACE_NAMELEN - 1] = '\0';
652
653                 /*
654                  * Before we attempt to match this probe, we want to give
655                  * all providers the opportunity to provide it.
656                  */
657                 if (p_desc->dtpd_id == DTRACE_IDNONE) {
658                         mutex_enter(&dtrace_provider_lock);
659                         dtrace_probe_provide(p_desc, NULL);
660                         mutex_exit(&dtrace_provider_lock);
661                         p_desc->dtpd_id++;
662                 }
663
664                 if (cmd == DTRACEIOC_PROBEMATCH)  {
665                         dtrace_probekey(p_desc, &pkey);
666                         pkey.dtpk_id = DTRACE_IDNONE;
667                 }
668
669                 dtrace_cred2priv(td->td_ucred, &priv, &uid, &zoneid);
670
671                 mutex_enter(&dtrace_lock);
672
673                 if (cmd == DTRACEIOC_PROBEMATCH) {
674                         for (i = p_desc->dtpd_id; i <= dtrace_nprobes; i++) {
675                                 if ((probe = dtrace_probes[i - 1]) != NULL &&
676                                     (m = dtrace_match_probe(probe, &pkey,
677                                     priv, uid, zoneid)) != 0)
678                                         break;
679                         }
680
681                         if (m < 0) {
682                                 mutex_exit(&dtrace_lock);
683                                 return (EINVAL);
684                         }
685
686                 } else {
687                         for (i = p_desc->dtpd_id; i <= dtrace_nprobes; i++) {
688                                 if ((probe = dtrace_probes[i - 1]) != NULL &&
689                                     dtrace_match_priv(probe, priv, uid, zoneid))
690                                         break;
691                         }
692                 }
693
694                 if (probe == NULL) {
695                         mutex_exit(&dtrace_lock);
696                         return (ESRCH);
697                 }
698
699                 dtrace_probe_description(probe, p_desc);
700                 mutex_exit(&dtrace_lock);
701
702                 return (0);
703         }
704         case DTRACEIOC_PROVIDER: {
705                 dtrace_providerdesc_t *pvd = (dtrace_providerdesc_t *) addr;
706                 dtrace_provider_t *pvp;
707
708                 DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_PROVIDER\n",__func__,__LINE__);
709
710                 pvd->dtvd_name[DTRACE_PROVNAMELEN - 1] = '\0';
711                 mutex_enter(&dtrace_provider_lock);
712
713                 for (pvp = dtrace_provider; pvp != NULL; pvp = pvp->dtpv_next) {
714                         if (strcmp(pvp->dtpv_name, pvd->dtvd_name) == 0)
715                                 break;
716                 }
717
718                 mutex_exit(&dtrace_provider_lock);
719
720                 if (pvp == NULL)
721                         return (ESRCH);
722
723                 bcopy(&pvp->dtpv_priv, &pvd->dtvd_priv, sizeof (dtrace_ppriv_t));
724                 bcopy(&pvp->dtpv_attr, &pvd->dtvd_attr, sizeof (dtrace_pattr_t));
725
726                 return (0);
727         }
728         case DTRACEIOC_REPLICATE: {
729                 dtrace_repldesc_t *desc = (dtrace_repldesc_t *) addr;
730                 dtrace_probedesc_t *match = &desc->dtrpd_match;
731                 dtrace_probedesc_t *create = &desc->dtrpd_create;
732                 int err;
733
734                 DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_REPLICATE\n",__func__,__LINE__);
735
736                 match->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0';
737                 match->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0';
738                 match->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0';
739                 match->dtpd_name[DTRACE_NAMELEN - 1] = '\0';
740
741                 create->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0';
742                 create->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0';
743                 create->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0';
744                 create->dtpd_name[DTRACE_NAMELEN - 1] = '\0';
745
746                 mutex_enter(&dtrace_lock);
747                 err = dtrace_enabling_replicate(state, match, create);
748                 mutex_exit(&dtrace_lock);
749
750                 return (err);
751         }
752         case DTRACEIOC_STATUS: {
753                 dtrace_status_t *stat = (dtrace_status_t *) addr;
754                 dtrace_dstate_t *dstate;
755                 int i, j;
756                 uint64_t nerrs;
757
758                 DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_STATUS\n",__func__,__LINE__);
759
760                 /*
761                  * See the comment in dtrace_state_deadman() for the reason
762                  * for setting dts_laststatus to INT64_MAX before setting
763                  * it to the correct value.
764                  */
765                 state->dts_laststatus = INT64_MAX;
766                 dtrace_membar_producer();
767                 state->dts_laststatus = dtrace_gethrtime();
768
769                 bzero(stat, sizeof (*stat));
770
771                 mutex_enter(&dtrace_lock);
772
773                 if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) {
774                         mutex_exit(&dtrace_lock);
775                         return (ENOENT);
776                 }
777
778                 if (state->dts_activity == DTRACE_ACTIVITY_DRAINING)
779                         stat->dtst_exiting = 1;
780
781                 nerrs = state->dts_errors;
782                 dstate = &state->dts_vstate.dtvs_dynvars;
783
784                 for (i = 0; i < NCPU; i++) {
785 #if !defined(sun)
786                         if (pcpu_find(i) == NULL)
787                                 continue;
788 #endif
789                         dtrace_dstate_percpu_t *dcpu = &dstate->dtds_percpu[i];
790
791                         stat->dtst_dyndrops += dcpu->dtdsc_drops;
792                         stat->dtst_dyndrops_dirty += dcpu->dtdsc_dirty_drops;
793                         stat->dtst_dyndrops_rinsing += dcpu->dtdsc_rinsing_drops;
794
795                         if (state->dts_buffer[i].dtb_flags & DTRACEBUF_FULL)
796                                 stat->dtst_filled++;
797
798                         nerrs += state->dts_buffer[i].dtb_errors;
799
800                         for (j = 0; j < state->dts_nspeculations; j++) {
801                                 dtrace_speculation_t *spec;
802                                 dtrace_buffer_t *buf;
803
804                                 spec = &state->dts_speculations[j];
805                                 buf = &spec->dtsp_buffer[i];
806                                 stat->dtst_specdrops += buf->dtb_xamot_drops;
807                         }
808                 }
809
810                 stat->dtst_specdrops_busy = state->dts_speculations_busy;
811                 stat->dtst_specdrops_unavail = state->dts_speculations_unavail;
812                 stat->dtst_stkstroverflows = state->dts_stkstroverflows;
813                 stat->dtst_dblerrors = state->dts_dblerrors;
814                 stat->dtst_killed =
815                     (state->dts_activity == DTRACE_ACTIVITY_KILLED);
816                 stat->dtst_errors = nerrs;
817
818                 mutex_exit(&dtrace_lock);
819
820                 return (0);
821         }
822         case DTRACEIOC_STOP: {
823                 int rval;
824                 processorid_t *cpuid = (processorid_t *) addr;
825
826                 DTRACE_IOCTL_PRINTF("%s(%d): DTRACEIOC_STOP\n",__func__,__LINE__);
827
828                 mutex_enter(&dtrace_lock);
829                 rval = dtrace_state_stop(state, cpuid);
830                 mutex_exit(&dtrace_lock);
831
832                 return (rval);
833         }
834         default:
835                 error = ENOTTY;
836         }
837         return (error);
838 }