The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/cddl/dev/dtrace/dtrace_ioctl.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 3839d88cede28aa3b8a87d0d7e8ceb9e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.