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/kern/kern_ktr.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2000 John Baldwin <jhb@FreeBSD.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 /*
   30  * This module holds the global variables used by KTR and the ktr_tracepoint()
   31  * function that does the actual tracing.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD: releng/12.0/sys/kern/kern_ktr.c 326271 2017-11-27 15:20:12Z pfg $");
   36 
   37 #include "opt_ddb.h"
   38 #include "opt_ktr.h"
   39 #include "opt_alq.h"
   40 
   41 #include <sys/param.h>
   42 #include <sys/queue.h>
   43 #include <sys/alq.h>
   44 #include <sys/cons.h>
   45 #include <sys/cpuset.h>
   46 #include <sys/kdb.h>
   47 #include <sys/kernel.h>
   48 #include <sys/ktr.h>
   49 #include <sys/libkern.h>
   50 #include <sys/lock.h>
   51 #include <sys/malloc.h>
   52 #include <sys/mutex.h>
   53 #include <sys/proc.h>
   54 #include <sys/smp.h>
   55 #include <sys/sysctl.h>
   56 #include <sys/systm.h>
   57 #include <sys/time.h>
   58 
   59 #include <machine/cpu.h>
   60 
   61 #ifdef DDB
   62 #include <ddb/ddb.h>
   63 #include <ddb/db_output.h>
   64 #endif
   65 
   66 #ifndef KTR_BOOT_ENTRIES
   67 #define KTR_BOOT_ENTRIES        1024
   68 #endif
   69 
   70 #ifndef KTR_ENTRIES
   71 #define KTR_ENTRIES     1024
   72 #endif
   73 
   74 /* Limit the allocations to something manageable. */
   75 #define KTR_ENTRIES_MAX (8 * 1024 * 1024)
   76 
   77 #ifndef KTR_MASK
   78 #define KTR_MASK        (0)
   79 #endif
   80 
   81 #ifndef KTR_CPUMASK
   82 #define KTR_CPUMASK     CPUSET_FSET
   83 #endif
   84 
   85 #ifndef KTR_TIME
   86 #define KTR_TIME        get_cyclecount()
   87 #endif
   88 
   89 #ifndef KTR_CPU
   90 #define KTR_CPU         PCPU_GET(cpuid)
   91 #endif
   92 
   93 static MALLOC_DEFINE(M_KTR, "KTR", "KTR");
   94 
   95 FEATURE(ktr, "Kernel support for KTR kernel tracing facility");
   96 
   97 volatile int    ktr_idx = 0;
   98 uint64_t ktr_mask = KTR_MASK;
   99 uint64_t ktr_compile = KTR_COMPILE;
  100 int     ktr_entries = KTR_BOOT_ENTRIES;
  101 int     ktr_version = KTR_VERSION;
  102 struct  ktr_entry ktr_buf_init[KTR_BOOT_ENTRIES];
  103 struct  ktr_entry *ktr_buf = ktr_buf_init;
  104 cpuset_t ktr_cpumask = CPUSET_T_INITIALIZER(KTR_CPUMASK);
  105 
  106 static SYSCTL_NODE(_debug, OID_AUTO, ktr, CTLFLAG_RD, 0, "KTR options");
  107 
  108 SYSCTL_INT(_debug_ktr, OID_AUTO, version, CTLFLAG_RD,
  109     &ktr_version, 0, "Version of the KTR interface");
  110 
  111 SYSCTL_UQUAD(_debug_ktr, OID_AUTO, compile, CTLFLAG_RD,
  112     &ktr_compile, 0, "Bitmask of KTR event classes compiled into the kernel");
  113 
  114 static int
  115 sysctl_debug_ktr_cpumask(SYSCTL_HANDLER_ARGS)
  116 {
  117         char lktr_cpumask_str[CPUSETBUFSIZ];
  118         cpuset_t imask;
  119         int error;
  120 
  121         cpusetobj_strprint(lktr_cpumask_str, &ktr_cpumask);
  122         error = sysctl_handle_string(oidp, lktr_cpumask_str,
  123             sizeof(lktr_cpumask_str), req);
  124         if (error != 0 || req->newptr == NULL)
  125                 return (error);
  126         if (cpusetobj_strscan(&imask, lktr_cpumask_str) == -1)
  127                 return (EINVAL);
  128         CPU_COPY(&imask, &ktr_cpumask);
  129 
  130         return (error);
  131 }
  132 SYSCTL_PROC(_debug_ktr, OID_AUTO, cpumask,
  133     CTLFLAG_RWTUN | CTLFLAG_MPSAFE | CTLTYPE_STRING, NULL, 0,
  134     sysctl_debug_ktr_cpumask, "S",
  135     "Bitmask of CPUs on which KTR logging is enabled");
  136 
  137 static int
  138 sysctl_debug_ktr_clear(SYSCTL_HANDLER_ARGS)
  139 {
  140         int clear, error;
  141 
  142         clear = 0;
  143         error = sysctl_handle_int(oidp, &clear, 0, req);
  144         if (error || !req->newptr)
  145                 return (error);
  146 
  147         if (clear) {
  148                 bzero(ktr_buf, sizeof(*ktr_buf) * ktr_entries);
  149                 ktr_idx = 0;
  150         }
  151 
  152         return (error);
  153 }
  154 SYSCTL_PROC(_debug_ktr, OID_AUTO, clear, CTLTYPE_INT|CTLFLAG_RW, 0, 0,
  155     sysctl_debug_ktr_clear, "I", "Clear KTR Buffer");
  156 
  157 /*
  158  * This is a sysctl proc so that it is serialized as !MPSAFE along with
  159  * the other ktr sysctl procs.
  160  */
  161 static int
  162 sysctl_debug_ktr_mask(SYSCTL_HANDLER_ARGS)
  163 {
  164         uint64_t mask;
  165         int error;
  166 
  167         mask = ktr_mask;
  168         error = sysctl_handle_64(oidp, &mask, 0, req);
  169         if (error || !req->newptr)
  170                 return (error);
  171         ktr_mask = mask;
  172         return (error);
  173 }
  174 
  175 SYSCTL_PROC(_debug_ktr, OID_AUTO, mask, CTLTYPE_U64 | CTLFLAG_RWTUN, 0, 0,
  176     sysctl_debug_ktr_mask, "QU",
  177     "Bitmask of KTR event classes for which logging is enabled");
  178 
  179 #if KTR_ENTRIES > KTR_BOOT_ENTRIES
  180 /*
  181  * A simplified version of sysctl_debug_ktr_entries.
  182  * No need to care about SMP, scheduling, etc.
  183  */
  184 static void
  185 ktr_entries_initializer(void *dummy __unused)
  186 {
  187         uint64_t mask;
  188 
  189         /* Temporarily disable ktr in case malloc() is being traced. */
  190         mask = ktr_mask;
  191         ktr_mask = 0;
  192         ktr_buf = malloc(sizeof(*ktr_buf) * KTR_ENTRIES, M_KTR,
  193             M_WAITOK | M_ZERO);
  194         memcpy(ktr_buf, ktr_buf_init + ktr_idx,
  195             (KTR_BOOT_ENTRIES - ktr_idx) * sizeof(*ktr_buf));
  196         if (ktr_idx != 0) {
  197                 memcpy(ktr_buf + KTR_BOOT_ENTRIES - ktr_idx, ktr_buf_init,
  198                     ktr_idx * sizeof(*ktr_buf));
  199                 ktr_idx = KTR_BOOT_ENTRIES;
  200         }
  201         ktr_entries = KTR_ENTRIES;
  202         ktr_mask = mask;
  203 }
  204 SYSINIT(ktr_entries_initializer, SI_SUB_KMEM, SI_ORDER_ANY,
  205     ktr_entries_initializer, NULL);
  206 #endif
  207 
  208 static int
  209 sysctl_debug_ktr_entries(SYSCTL_HANDLER_ARGS)
  210 {
  211         uint64_t mask;
  212         int entries, error;
  213         struct ktr_entry *buf, *oldbuf;
  214 
  215         entries = ktr_entries;
  216         error = sysctl_handle_int(oidp, &entries, 0, req);
  217         if (error || !req->newptr)
  218                 return (error);
  219         if (entries > KTR_ENTRIES_MAX)
  220                 return (ERANGE);
  221         /* Disable ktr temporarily. */
  222         mask = ktr_mask;
  223         ktr_mask = 0;
  224         /* Wait for threads to go idle. */
  225         if ((error = quiesce_all_cpus("ktrent", PCATCH)) != 0) {
  226                 ktr_mask = mask;
  227                 return (error);
  228         }
  229         if (ktr_buf != ktr_buf_init)
  230                 oldbuf = ktr_buf;
  231         else
  232                 oldbuf = NULL;
  233         /* Allocate a new buffer. */
  234         buf = malloc(sizeof(*buf) * entries, M_KTR, M_WAITOK | M_ZERO);
  235         /* Install the new buffer and restart ktr. */
  236         ktr_buf = buf;
  237         ktr_entries = entries;
  238         ktr_idx = 0;
  239         ktr_mask = mask;
  240         if (oldbuf != NULL)
  241                 free(oldbuf, M_KTR);
  242 
  243         return (error);
  244 }
  245 
  246 SYSCTL_PROC(_debug_ktr, OID_AUTO, entries, CTLTYPE_INT|CTLFLAG_RW, 0, 0,
  247     sysctl_debug_ktr_entries, "I", "Number of entries in the KTR buffer");
  248 
  249 #ifdef KTR_VERBOSE
  250 int     ktr_verbose = KTR_VERBOSE;
  251 TUNABLE_INT("debug.ktr.verbose", &ktr_verbose);
  252 SYSCTL_INT(_debug_ktr, OID_AUTO, verbose, CTLFLAG_RW, &ktr_verbose, 0, "");
  253 #endif
  254 
  255 #ifdef KTR_ALQ
  256 struct alq *ktr_alq;
  257 char    ktr_alq_file[MAXPATHLEN] = "/tmp/ktr.out";
  258 int     ktr_alq_cnt = 0;
  259 int     ktr_alq_depth = KTR_ENTRIES;
  260 int     ktr_alq_enabled = 0;
  261 int     ktr_alq_failed = 0;
  262 int     ktr_alq_max = 0;
  263 
  264 SYSCTL_INT(_debug_ktr, OID_AUTO, alq_max, CTLFLAG_RW, &ktr_alq_max, 0,
  265     "Maximum number of entries to write");
  266 SYSCTL_INT(_debug_ktr, OID_AUTO, alq_cnt, CTLFLAG_RD, &ktr_alq_cnt, 0,
  267     "Current number of written entries");
  268 SYSCTL_INT(_debug_ktr, OID_AUTO, alq_failed, CTLFLAG_RD, &ktr_alq_failed, 0,
  269     "Number of times we overran the buffer");
  270 SYSCTL_INT(_debug_ktr, OID_AUTO, alq_depth, CTLFLAG_RW, &ktr_alq_depth, 0,
  271     "Number of items in the write buffer");
  272 SYSCTL_STRING(_debug_ktr, OID_AUTO, alq_file, CTLFLAG_RW, ktr_alq_file,
  273     sizeof(ktr_alq_file), "KTR logging file");
  274 
  275 static int
  276 sysctl_debug_ktr_alq_enable(SYSCTL_HANDLER_ARGS)
  277 {
  278         int error;
  279         int enable;
  280 
  281         enable = ktr_alq_enabled;
  282 
  283         error = sysctl_handle_int(oidp, &enable, 0, req);
  284         if (error || !req->newptr)
  285                 return (error);
  286 
  287         if (enable) {
  288                 if (ktr_alq_enabled)
  289                         return (0);
  290                 error = alq_open(&ktr_alq, (const char *)ktr_alq_file,
  291                     req->td->td_ucred, ALQ_DEFAULT_CMODE,
  292                     sizeof(struct ktr_entry), ktr_alq_depth);
  293                 if (error == 0) {
  294                         ktr_alq_cnt = 0;
  295                         ktr_alq_failed = 0;
  296                         ktr_alq_enabled = 1;
  297                 }
  298         } else {
  299                 if (ktr_alq_enabled == 0)
  300                         return (0);
  301                 ktr_alq_enabled = 0;
  302                 alq_close(ktr_alq);
  303                 ktr_alq = NULL;
  304         }
  305 
  306         return (error);
  307 }
  308 SYSCTL_PROC(_debug_ktr, OID_AUTO, alq_enable,
  309     CTLTYPE_INT|CTLFLAG_RW, 0, 0, sysctl_debug_ktr_alq_enable,
  310     "I", "Enable KTR logging");
  311 #endif
  312 
  313 void
  314 ktr_tracepoint(uint64_t mask, const char *file, int line, const char *format,
  315     u_long arg1, u_long arg2, u_long arg3, u_long arg4, u_long arg5,
  316     u_long arg6)
  317 {
  318         struct ktr_entry *entry;
  319 #ifdef KTR_ALQ
  320         struct ale *ale = NULL;
  321 #endif
  322         int newindex, saveindex;
  323 #if defined(KTR_VERBOSE) || defined(KTR_ALQ)
  324         struct thread *td;
  325 #endif
  326         int cpu;
  327 
  328         if (panicstr || kdb_active)
  329                 return;
  330         if ((ktr_mask & mask) == 0 || ktr_buf == NULL)
  331                 return;
  332         cpu = KTR_CPU;
  333         if (!CPU_ISSET(cpu, &ktr_cpumask))
  334                 return;
  335 #if defined(KTR_VERBOSE) || defined(KTR_ALQ)
  336         td = curthread;
  337         if (td->td_pflags & TDP_INKTR)
  338                 return;
  339         td->td_pflags |= TDP_INKTR;
  340 #endif
  341 #ifdef KTR_ALQ
  342         if (ktr_alq_enabled) {
  343                 if (td->td_critnest == 0 &&
  344                     (td->td_flags & TDF_IDLETD) == 0 &&
  345                     td != ald_thread) {
  346                         if (ktr_alq_max && ktr_alq_cnt > ktr_alq_max)
  347                                 goto done;
  348                         if ((ale = alq_get(ktr_alq, ALQ_NOWAIT)) == NULL) {
  349                                 ktr_alq_failed++;
  350                                 goto done;
  351                         }
  352                         ktr_alq_cnt++;
  353                         entry = (struct ktr_entry *)ale->ae_data;
  354                 } else {
  355                         goto done;
  356                 }
  357         } else
  358 #endif
  359         {
  360                 do {
  361                         saveindex = ktr_idx;
  362                         newindex = (saveindex + 1) % ktr_entries;
  363                 } while (atomic_cmpset_rel_int(&ktr_idx, saveindex, newindex) == 0);
  364                 entry = &ktr_buf[saveindex];
  365         }
  366         entry->ktr_timestamp = KTR_TIME;
  367         entry->ktr_cpu = cpu;
  368         entry->ktr_thread = curthread;
  369         if (file != NULL)
  370                 while (strncmp(file, "../", 3) == 0)
  371                         file += 3;
  372         entry->ktr_file = file;
  373         entry->ktr_line = line;
  374 #ifdef KTR_VERBOSE
  375         if (ktr_verbose) {
  376 #ifdef SMP
  377                 printf("cpu%d ", cpu);
  378 #endif
  379                 if (ktr_verbose > 1) {
  380                         printf("%s.%d\t", entry->ktr_file,
  381                             entry->ktr_line);
  382                 }
  383                 printf(format, arg1, arg2, arg3, arg4, arg5, arg6);
  384                 printf("\n");
  385         }
  386 #endif
  387         entry->ktr_desc = format;
  388         entry->ktr_parms[0] = arg1;
  389         entry->ktr_parms[1] = arg2;
  390         entry->ktr_parms[2] = arg3;
  391         entry->ktr_parms[3] = arg4;
  392         entry->ktr_parms[4] = arg5;
  393         entry->ktr_parms[5] = arg6;
  394 #ifdef KTR_ALQ
  395         if (ktr_alq_enabled && ale)
  396                 alq_post(ktr_alq, ale);
  397 done:
  398 #endif
  399 #if defined(KTR_VERBOSE) || defined(KTR_ALQ)
  400         td->td_pflags &= ~TDP_INKTR;
  401 #endif
  402 }
  403 
  404 #ifdef DDB
  405 
  406 struct tstate {
  407         int     cur;
  408         int     first;
  409 };
  410 static  struct tstate tstate;
  411 static  int db_ktr_verbose;
  412 static  int db_mach_vtrace(void);
  413 
  414 DB_SHOW_COMMAND(ktr, db_ktr_all)
  415 {
  416         
  417         tstate.cur = (ktr_idx - 1) % ktr_entries;
  418         tstate.first = -1;
  419         db_ktr_verbose = 0;
  420         db_ktr_verbose |= (strchr(modif, 'v') != NULL) ? 2 : 0;
  421         db_ktr_verbose |= (strchr(modif, 'V') != NULL) ? 1 : 0; /* just timestamp please */
  422         if (strchr(modif, 'a') != NULL) {
  423                 db_disable_pager();
  424                 while (cncheckc() == -1)
  425                         if (db_mach_vtrace() == 0)
  426                                 break;
  427         } else {
  428                 while (!db_pager_quit)
  429                         if (db_mach_vtrace() == 0)
  430                                 break;
  431         }
  432 }
  433 
  434 static int
  435 db_mach_vtrace(void)
  436 {
  437         struct ktr_entry        *kp;
  438 
  439         if (tstate.cur == tstate.first || ktr_buf == NULL) {
  440                 db_printf("--- End of trace buffer ---\n");
  441                 return (0);
  442         }
  443         kp = &ktr_buf[tstate.cur];
  444 
  445         /* Skip over unused entries. */
  446         if (kp->ktr_desc == NULL) {
  447                 db_printf("--- End of trace buffer ---\n");
  448                 return (0);
  449         }
  450         db_printf("%d (%p", tstate.cur, kp->ktr_thread);
  451 #ifdef SMP
  452         db_printf(":cpu%d", kp->ktr_cpu);
  453 #endif
  454         db_printf(")");
  455         if (db_ktr_verbose >= 1) {
  456                 db_printf(" %10.10lld", (long long)kp->ktr_timestamp);
  457         }
  458         if (db_ktr_verbose >= 2) {
  459                 db_printf(" %s.%d", kp->ktr_file, kp->ktr_line);
  460         }
  461         db_printf(": ");
  462         db_printf(kp->ktr_desc, kp->ktr_parms[0], kp->ktr_parms[1],
  463             kp->ktr_parms[2], kp->ktr_parms[3], kp->ktr_parms[4],
  464             kp->ktr_parms[5]);
  465         db_printf("\n");
  466 
  467         if (tstate.first == -1)
  468                 tstate.first = tstate.cur;
  469 
  470         if (--tstate.cur < 0)
  471                 tstate.cur = ktr_entries - 1;
  472 
  473         return (1);
  474 }
  475 
  476 #endif  /* DDB */

Cache object: 2ff97740fb6daf6494417b7c1e0a5d60


[ 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.