1 /*- 2 * Copyright (c) 2005-2007 Joseph Koshy 3 * Copyright (c) 2007 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * Portions of this software were developed by A. Joseph Koshy under 7 * sponsorship from the FreeBSD Foundation and Google, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 32 /* 33 * Logging code for hwpmc(4) 34 */ 35 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 #include <sys/param.h> 40 #if (__FreeBSD_version >= 1100000) 41 #include <sys/capsicum.h> 42 #else 43 #include <sys/capability.h> 44 #endif 45 #include <sys/file.h> 46 #include <sys/kernel.h> 47 #include <sys/kthread.h> 48 #include <sys/lock.h> 49 #include <sys/module.h> 50 #include <sys/mutex.h> 51 #include <sys/pmc.h> 52 #include <sys/pmckern.h> 53 #include <sys/pmclog.h> 54 #include <sys/proc.h> 55 #include <sys/signalvar.h> 56 #include <sys/sysctl.h> 57 #include <sys/systm.h> 58 #include <sys/uio.h> 59 #include <sys/unistd.h> 60 #include <sys/vnode.h> 61 62 /* 63 * Sysctl tunables 64 */ 65 66 SYSCTL_DECL(_kern_hwpmc); 67 68 /* 69 * kern.hwpmc.logbuffersize -- size of the per-cpu owner buffers. 70 */ 71 72 static int pmclog_buffer_size = PMC_LOG_BUFFER_SIZE; 73 #if (__FreeBSD_version < 1100000) 74 TUNABLE_INT(PMC_SYSCTL_NAME_PREFIX "logbuffersize", &pmclog_buffer_size); 75 #endif 76 SYSCTL_INT(_kern_hwpmc, OID_AUTO, logbuffersize, CTLFLAG_RDTUN, 77 &pmclog_buffer_size, 0, "size of log buffers in kilobytes"); 78 79 /* 80 * kern.hwpmc.nbuffer -- number of global log buffers 81 */ 82 83 static int pmc_nlogbuffers = PMC_NLOGBUFFERS; 84 #if (__FreeBSD_version < 1100000) 85 TUNABLE_INT(PMC_SYSCTL_NAME_PREFIX "nbuffers", &pmc_nlogbuffers); 86 #endif 87 SYSCTL_INT(_kern_hwpmc, OID_AUTO, nbuffers, CTLFLAG_RDTUN, 88 &pmc_nlogbuffers, 0, "number of global log buffers"); 89 90 /* 91 * Global log buffer list and associated spin lock. 92 */ 93 94 TAILQ_HEAD(, pmclog_buffer) pmc_bufferlist = 95 TAILQ_HEAD_INITIALIZER(pmc_bufferlist); 96 static struct mtx pmc_bufferlist_mtx; /* spin lock */ 97 static struct mtx pmc_kthread_mtx; /* sleep lock */ 98 99 #define PMCLOG_INIT_BUFFER_DESCRIPTOR(D) do { \ 100 const int __roundup = roundup(sizeof(*D), \ 101 sizeof(uint32_t)); \ 102 (D)->plb_fence = ((char *) (D)) + \ 103 1024*pmclog_buffer_size; \ 104 (D)->plb_base = (D)->plb_ptr = ((char *) (D)) + \ 105 __roundup; \ 106 } while (0) 107 108 109 /* 110 * Log file record constructors. 111 */ 112 #define _PMCLOG_TO_HEADER(T,L) \ 113 ((PMCLOG_HEADER_MAGIC << 24) | \ 114 (PMCLOG_TYPE_ ## T << 16) | \ 115 ((L) & 0xFFFF)) 116 117 /* reserve LEN bytes of space and initialize the entry header */ 118 #define _PMCLOG_RESERVE(PO,TYPE,LEN,ACTION) do { \ 119 uint32_t *_le; \ 120 int _len = roundup((LEN), sizeof(uint32_t)); \ 121 if ((_le = pmclog_reserve((PO), _len)) == NULL) { \ 122 ACTION; \ 123 } \ 124 *_le = _PMCLOG_TO_HEADER(TYPE,_len); \ 125 _le += 3 /* skip over timestamp */ 126 127 #define PMCLOG_RESERVE(P,T,L) _PMCLOG_RESERVE(P,T,L,return) 128 #define PMCLOG_RESERVE_WITH_ERROR(P,T,L) _PMCLOG_RESERVE(P,T,L, \ 129 error=ENOMEM;goto error) 130 131 #define PMCLOG_EMIT32(V) do { *_le++ = (V); } while (0) 132 #define PMCLOG_EMIT64(V) do { \ 133 *_le++ = (uint32_t) ((V) & 0xFFFFFFFF); \ 134 *_le++ = (uint32_t) (((V) >> 32) & 0xFFFFFFFF); \ 135 } while (0) 136 137 138 /* Emit a string. Caution: does NOT update _le, so needs to be last */ 139 #define PMCLOG_EMITSTRING(S,L) do { bcopy((S), _le, (L)); } while (0) 140 #define PMCLOG_EMITNULLSTRING(L) do { bzero(_le, (L)); } while (0) 141 142 #define PMCLOG_DESPATCH(PO) \ 143 pmclog_release((PO)); \ 144 } while (0) 145 146 147 /* 148 * Assertions about the log file format. 149 */ 150 151 CTASSERT(sizeof(struct pmclog_callchain) == 6*4 + 152 PMC_CALLCHAIN_DEPTH_MAX*sizeof(uintfptr_t)); 153 CTASSERT(sizeof(struct pmclog_closelog) == 3*4); 154 CTASSERT(sizeof(struct pmclog_dropnotify) == 3*4); 155 CTASSERT(sizeof(struct pmclog_map_in) == PATH_MAX + 156 4*4 + sizeof(uintfptr_t)); 157 CTASSERT(offsetof(struct pmclog_map_in,pl_pathname) == 158 4*4 + sizeof(uintfptr_t)); 159 CTASSERT(sizeof(struct pmclog_map_out) == 4*4 + 2*sizeof(uintfptr_t)); 160 CTASSERT(sizeof(struct pmclog_pcsample) == 6*4 + sizeof(uintfptr_t)); 161 CTASSERT(sizeof(struct pmclog_pmcallocate) == 6*4); 162 CTASSERT(sizeof(struct pmclog_pmcattach) == 5*4 + PATH_MAX); 163 CTASSERT(offsetof(struct pmclog_pmcattach,pl_pathname) == 5*4); 164 CTASSERT(sizeof(struct pmclog_pmcdetach) == 5*4); 165 CTASSERT(sizeof(struct pmclog_proccsw) == 5*4 + 8); 166 CTASSERT(sizeof(struct pmclog_procexec) == 5*4 + PATH_MAX + 167 sizeof(uintfptr_t)); 168 CTASSERT(offsetof(struct pmclog_procexec,pl_pathname) == 5*4 + 169 sizeof(uintfptr_t)); 170 CTASSERT(sizeof(struct pmclog_procexit) == 5*4 + 8); 171 CTASSERT(sizeof(struct pmclog_procfork) == 5*4); 172 CTASSERT(sizeof(struct pmclog_sysexit) == 4*4); 173 CTASSERT(sizeof(struct pmclog_userdata) == 4*4); 174 175 /* 176 * Log buffer structure 177 */ 178 179 struct pmclog_buffer { 180 TAILQ_ENTRY(pmclog_buffer) plb_next; 181 char *plb_base; 182 char *plb_ptr; 183 char *plb_fence; 184 }; 185 186 /* 187 * Prototypes 188 */ 189 190 static int pmclog_get_buffer(struct pmc_owner *po); 191 static void pmclog_loop(void *arg); 192 static void pmclog_release(struct pmc_owner *po); 193 static uint32_t *pmclog_reserve(struct pmc_owner *po, int length); 194 static void pmclog_schedule_io(struct pmc_owner *po); 195 static void pmclog_stop_kthread(struct pmc_owner *po); 196 197 /* 198 * Helper functions 199 */ 200 201 /* 202 * Get a log buffer 203 */ 204 205 static int 206 pmclog_get_buffer(struct pmc_owner *po) 207 { 208 struct pmclog_buffer *plb; 209 210 mtx_assert(&po->po_mtx, MA_OWNED); 211 212 KASSERT(po->po_curbuf == NULL, 213 ("[pmclog,%d] po=%p current buffer still valid", __LINE__, po)); 214 215 mtx_lock_spin(&pmc_bufferlist_mtx); 216 if ((plb = TAILQ_FIRST(&pmc_bufferlist)) != NULL) 217 TAILQ_REMOVE(&pmc_bufferlist, plb, plb_next); 218 mtx_unlock_spin(&pmc_bufferlist_mtx); 219 220 PMCDBG2(LOG,GTB,1, "po=%p plb=%p", po, plb); 221 222 #ifdef HWPMC_DEBUG 223 if (plb) 224 KASSERT(plb->plb_ptr == plb->plb_base && 225 plb->plb_base < plb->plb_fence, 226 ("[pmclog,%d] po=%p buffer invariants: ptr=%p " 227 "base=%p fence=%p", __LINE__, po, plb->plb_ptr, 228 plb->plb_base, plb->plb_fence)); 229 #endif 230 231 po->po_curbuf = plb; 232 233 /* update stats */ 234 atomic_add_int(&pmc_stats.pm_buffer_requests, 1); 235 if (plb == NULL) 236 atomic_add_int(&pmc_stats.pm_buffer_requests_failed, 1); 237 238 return (plb ? 0 : ENOMEM); 239 } 240 241 /* 242 * Log handler loop. 243 * 244 * This function is executed by each pmc owner's helper thread. 245 */ 246 247 static void 248 pmclog_loop(void *arg) 249 { 250 int error; 251 struct pmc_owner *po; 252 struct pmclog_buffer *lb; 253 struct proc *p; 254 struct ucred *ownercred; 255 struct ucred *mycred; 256 struct thread *td; 257 struct uio auio; 258 struct iovec aiov; 259 size_t nbytes; 260 261 po = (struct pmc_owner *) arg; 262 p = po->po_owner; 263 td = curthread; 264 mycred = td->td_ucred; 265 266 PROC_LOCK(p); 267 ownercred = crhold(p->p_ucred); 268 PROC_UNLOCK(p); 269 270 PMCDBG2(LOG,INI,1, "po=%p kt=%p", po, po->po_kthread); 271 KASSERT(po->po_kthread == curthread->td_proc, 272 ("[pmclog,%d] proc mismatch po=%p po/kt=%p curproc=%p", __LINE__, 273 po, po->po_kthread, curthread->td_proc)); 274 275 lb = NULL; 276 277 278 /* 279 * Loop waiting for I/O requests to be added to the owner 280 * struct's queue. The loop is exited when the log file 281 * is deconfigured. 282 */ 283 284 mtx_lock(&pmc_kthread_mtx); 285 286 for (;;) { 287 288 /* check if we've been asked to exit */ 289 if ((po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) 290 break; 291 292 if (lb == NULL) { /* look for a fresh buffer to write */ 293 mtx_lock_spin(&po->po_mtx); 294 if ((lb = TAILQ_FIRST(&po->po_logbuffers)) == NULL) { 295 mtx_unlock_spin(&po->po_mtx); 296 297 /* No more buffers and shutdown required. */ 298 if (po->po_flags & PMC_PO_SHUTDOWN) { 299 mtx_unlock(&pmc_kthread_mtx); 300 /* 301 * Close the file to get PMCLOG_EOF 302 * error in pmclog(3). 303 */ 304 fo_close(po->po_file, curthread); 305 mtx_lock(&pmc_kthread_mtx); 306 break; 307 } 308 309 (void) msleep(po, &pmc_kthread_mtx, PWAIT, 310 "pmcloop", 0); 311 continue; 312 } 313 314 TAILQ_REMOVE(&po->po_logbuffers, lb, plb_next); 315 mtx_unlock_spin(&po->po_mtx); 316 } 317 318 mtx_unlock(&pmc_kthread_mtx); 319 320 /* process the request */ 321 PMCDBG3(LOG,WRI,2, "po=%p base=%p ptr=%p", po, 322 lb->plb_base, lb->plb_ptr); 323 /* change our thread's credentials before issuing the I/O */ 324 325 aiov.iov_base = lb->plb_base; 326 aiov.iov_len = nbytes = lb->plb_ptr - lb->plb_base; 327 328 auio.uio_iov = &aiov; 329 auio.uio_iovcnt = 1; 330 auio.uio_offset = -1; 331 auio.uio_resid = nbytes; 332 auio.uio_rw = UIO_WRITE; 333 auio.uio_segflg = UIO_SYSSPACE; 334 auio.uio_td = td; 335 336 /* switch thread credentials -- see kern_ktrace.c */ 337 td->td_ucred = ownercred; 338 error = fo_write(po->po_file, &auio, ownercred, 0, td); 339 td->td_ucred = mycred; 340 341 if (error) { 342 /* XXX some errors are recoverable */ 343 /* send a SIGIO to the owner and exit */ 344 PROC_LOCK(p); 345 kern_psignal(p, SIGIO); 346 PROC_UNLOCK(p); 347 348 mtx_lock(&pmc_kthread_mtx); 349 350 po->po_error = error; /* save for flush log */ 351 352 PMCDBG2(LOG,WRI,2, "po=%p error=%d", po, error); 353 354 break; 355 } 356 357 mtx_lock(&pmc_kthread_mtx); 358 359 /* put the used buffer back into the global pool */ 360 PMCLOG_INIT_BUFFER_DESCRIPTOR(lb); 361 362 mtx_lock_spin(&pmc_bufferlist_mtx); 363 TAILQ_INSERT_HEAD(&pmc_bufferlist, lb, plb_next); 364 mtx_unlock_spin(&pmc_bufferlist_mtx); 365 366 lb = NULL; 367 } 368 369 wakeup_one(po->po_kthread); 370 po->po_kthread = NULL; 371 372 mtx_unlock(&pmc_kthread_mtx); 373 374 /* return the current I/O buffer to the global pool */ 375 if (lb) { 376 PMCLOG_INIT_BUFFER_DESCRIPTOR(lb); 377 378 mtx_lock_spin(&pmc_bufferlist_mtx); 379 TAILQ_INSERT_HEAD(&pmc_bufferlist, lb, plb_next); 380 mtx_unlock_spin(&pmc_bufferlist_mtx); 381 } 382 383 /* 384 * Exit this thread, signalling the waiter 385 */ 386 387 crfree(ownercred); 388 389 kproc_exit(0); 390 } 391 392 /* 393 * Release and log entry and schedule an I/O if needed. 394 */ 395 396 static void 397 pmclog_release(struct pmc_owner *po) 398 { 399 KASSERT(po->po_curbuf->plb_ptr >= po->po_curbuf->plb_base, 400 ("[pmclog,%d] buffer invariants po=%p ptr=%p base=%p", __LINE__, 401 po, po->po_curbuf->plb_ptr, po->po_curbuf->plb_base)); 402 KASSERT(po->po_curbuf->plb_ptr <= po->po_curbuf->plb_fence, 403 ("[pmclog,%d] buffer invariants po=%p ptr=%p fenc=%p", __LINE__, 404 po, po->po_curbuf->plb_ptr, po->po_curbuf->plb_fence)); 405 406 /* schedule an I/O if we've filled a buffer */ 407 if (po->po_curbuf->plb_ptr >= po->po_curbuf->plb_fence) 408 pmclog_schedule_io(po); 409 410 mtx_unlock_spin(&po->po_mtx); 411 412 PMCDBG1(LOG,REL,1, "po=%p", po); 413 } 414 415 416 /* 417 * Attempt to reserve 'length' bytes of space in an owner's log 418 * buffer. The function returns a pointer to 'length' bytes of space 419 * if there was enough space or returns NULL if no space was 420 * available. Non-null returns do so with the po mutex locked. The 421 * caller must invoke pmclog_release() on the pmc owner structure 422 * when done. 423 */ 424 425 static uint32_t * 426 pmclog_reserve(struct pmc_owner *po, int length) 427 { 428 uintptr_t newptr, oldptr; 429 uint32_t *lh; 430 struct timespec ts; 431 432 PMCDBG2(LOG,ALL,1, "po=%p len=%d", po, length); 433 434 KASSERT(length % sizeof(uint32_t) == 0, 435 ("[pmclog,%d] length not a multiple of word size", __LINE__)); 436 437 mtx_lock_spin(&po->po_mtx); 438 439 /* No more data when shutdown in progress. */ 440 if (po->po_flags & PMC_PO_SHUTDOWN) { 441 mtx_unlock_spin(&po->po_mtx); 442 return (NULL); 443 } 444 445 if (po->po_curbuf == NULL) 446 if (pmclog_get_buffer(po) != 0) { 447 mtx_unlock_spin(&po->po_mtx); 448 return (NULL); 449 } 450 451 KASSERT(po->po_curbuf != NULL, 452 ("[pmclog,%d] po=%p no current buffer", __LINE__, po)); 453 454 KASSERT(po->po_curbuf->plb_ptr >= po->po_curbuf->plb_base && 455 po->po_curbuf->plb_ptr <= po->po_curbuf->plb_fence, 456 ("[pmclog,%d] po=%p buffer invariants: ptr=%p base=%p fence=%p", 457 __LINE__, po, po->po_curbuf->plb_ptr, po->po_curbuf->plb_base, 458 po->po_curbuf->plb_fence)); 459 460 oldptr = (uintptr_t) po->po_curbuf->plb_ptr; 461 newptr = oldptr + length; 462 463 KASSERT(oldptr != (uintptr_t) NULL, 464 ("[pmclog,%d] po=%p Null log buffer pointer", __LINE__, po)); 465 466 /* 467 * If we have space in the current buffer, return a pointer to 468 * available space with the PO structure locked. 469 */ 470 if (newptr <= (uintptr_t) po->po_curbuf->plb_fence) { 471 po->po_curbuf->plb_ptr = (char *) newptr; 472 goto done; 473 } 474 475 /* 476 * Otherwise, schedule the current buffer for output and get a 477 * fresh buffer. 478 */ 479 pmclog_schedule_io(po); 480 481 if (pmclog_get_buffer(po) != 0) { 482 mtx_unlock_spin(&po->po_mtx); 483 return (NULL); 484 } 485 486 KASSERT(po->po_curbuf != NULL, 487 ("[pmclog,%d] po=%p no current buffer", __LINE__, po)); 488 489 KASSERT(po->po_curbuf->plb_ptr != NULL, 490 ("[pmclog,%d] null return from pmc_get_log_buffer", __LINE__)); 491 492 KASSERT(po->po_curbuf->plb_ptr == po->po_curbuf->plb_base && 493 po->po_curbuf->plb_ptr <= po->po_curbuf->plb_fence, 494 ("[pmclog,%d] po=%p buffer invariants: ptr=%p base=%p fence=%p", 495 __LINE__, po, po->po_curbuf->plb_ptr, po->po_curbuf->plb_base, 496 po->po_curbuf->plb_fence)); 497 498 oldptr = (uintptr_t) po->po_curbuf->plb_ptr; 499 500 done: 501 lh = (uint32_t *) oldptr; 502 lh++; /* skip header */ 503 getnanotime(&ts); /* fill in the timestamp */ 504 *lh++ = ts.tv_sec & 0xFFFFFFFF; 505 *lh++ = ts.tv_nsec & 0xFFFFFFF; 506 return ((uint32_t *) oldptr); 507 } 508 509 /* 510 * Schedule an I/O. 511 * 512 * Transfer the current buffer to the helper kthread. 513 */ 514 515 static void 516 pmclog_schedule_io(struct pmc_owner *po) 517 { 518 KASSERT(po->po_curbuf != NULL, 519 ("[pmclog,%d] schedule_io with null buffer po=%p", __LINE__, po)); 520 521 KASSERT(po->po_curbuf->plb_ptr >= po->po_curbuf->plb_base, 522 ("[pmclog,%d] buffer invariants po=%p ptr=%p base=%p", __LINE__, 523 po, po->po_curbuf->plb_ptr, po->po_curbuf->plb_base)); 524 KASSERT(po->po_curbuf->plb_ptr <= po->po_curbuf->plb_fence, 525 ("[pmclog,%d] buffer invariants po=%p ptr=%p fenc=%p", __LINE__, 526 po, po->po_curbuf->plb_ptr, po->po_curbuf->plb_fence)); 527 528 PMCDBG1(LOG,SIO, 1, "po=%p", po); 529 530 mtx_assert(&po->po_mtx, MA_OWNED); 531 532 /* 533 * Add the current buffer to the tail of the buffer list and 534 * wakeup the helper. 535 */ 536 TAILQ_INSERT_TAIL(&po->po_logbuffers, po->po_curbuf, plb_next); 537 po->po_curbuf = NULL; 538 wakeup_one(po); 539 } 540 541 /* 542 * Stop the helper kthread. 543 */ 544 545 static void 546 pmclog_stop_kthread(struct pmc_owner *po) 547 { 548 /* 549 * Close the file to force the thread out of fo_write, 550 * unset flag, wakeup the helper thread, 551 * wait for it to exit 552 */ 553 554 if (po->po_file != NULL) 555 fo_close(po->po_file, curthread); 556 557 mtx_lock(&pmc_kthread_mtx); 558 po->po_flags &= ~PMC_PO_OWNS_LOGFILE; 559 wakeup_one(po); 560 if (po->po_kthread) 561 msleep(po->po_kthread, &pmc_kthread_mtx, PPAUSE, "pmckstp", 0); 562 mtx_unlock(&pmc_kthread_mtx); 563 } 564 565 /* 566 * Public functions 567 */ 568 569 /* 570 * Configure a log file for pmc owner 'po'. 571 * 572 * Parameter 'logfd' is a file handle referencing an open file in the 573 * owner process. This file needs to have been opened for writing. 574 */ 575 576 int 577 pmclog_configure_log(struct pmc_mdep *md, struct pmc_owner *po, int logfd) 578 { 579 int error; 580 struct proc *p; 581 cap_rights_t rights; 582 /* 583 * As long as it is possible to get a LOR between pmc_sx lock and 584 * proctree/allproc sx locks used for adding a new process, assure 585 * the former is not held here. 586 */ 587 sx_assert(&pmc_sx, SA_UNLOCKED); 588 PMCDBG2(LOG,CFG,1, "config po=%p logfd=%d", po, logfd); 589 590 p = po->po_owner; 591 592 /* return EBUSY if a log file was already present */ 593 if (po->po_flags & PMC_PO_OWNS_LOGFILE) 594 return (EBUSY); 595 596 KASSERT(po->po_kthread == NULL, 597 ("[pmclog,%d] po=%p kthread (%p) already present", __LINE__, po, 598 po->po_kthread)); 599 KASSERT(po->po_file == NULL, 600 ("[pmclog,%d] po=%p file (%p) already present", __LINE__, po, 601 po->po_file)); 602 603 /* get a reference to the file state */ 604 error = fget_write(curthread, logfd, 605 cap_rights_init(&rights, CAP_WRITE), &po->po_file); 606 if (error) 607 goto error; 608 609 /* mark process as owning a log file */ 610 po->po_flags |= PMC_PO_OWNS_LOGFILE; 611 error = kproc_create(pmclog_loop, po, &po->po_kthread, 612 RFHIGHPID, 0, "hwpmc: proc(%d)", p->p_pid); 613 if (error) 614 goto error; 615 616 /* mark process as using HWPMCs */ 617 PROC_LOCK(p); 618 p->p_flag |= P_HWPMC; 619 PROC_UNLOCK(p); 620 621 /* create a log initialization entry */ 622 PMCLOG_RESERVE_WITH_ERROR(po, INITIALIZE, 623 sizeof(struct pmclog_initialize)); 624 PMCLOG_EMIT32(PMC_VERSION); 625 PMCLOG_EMIT32(md->pmd_cputype); 626 PMCLOG_DESPATCH(po); 627 628 return (0); 629 630 error: 631 /* shutdown the thread */ 632 if (po->po_kthread) 633 pmclog_stop_kthread(po); 634 635 KASSERT(po->po_kthread == NULL, ("[pmclog,%d] po=%p kthread not " 636 "stopped", __LINE__, po)); 637 638 if (po->po_file) 639 (void) fdrop(po->po_file, curthread); 640 po->po_file = NULL; /* clear file and error state */ 641 po->po_error = 0; 642 643 return (error); 644 } 645 646 647 /* 648 * De-configure a log file. This will throw away any buffers queued 649 * for this owner process. 650 */ 651 652 int 653 pmclog_deconfigure_log(struct pmc_owner *po) 654 { 655 int error; 656 struct pmclog_buffer *lb; 657 658 PMCDBG1(LOG,CFG,1, "de-config po=%p", po); 659 660 if ((po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) 661 return (EINVAL); 662 663 KASSERT(po->po_sscount == 0, 664 ("[pmclog,%d] po=%p still owning SS PMCs", __LINE__, po)); 665 KASSERT(po->po_file != NULL, 666 ("[pmclog,%d] po=%p no log file", __LINE__, po)); 667 668 /* stop the kthread, this will reset the 'OWNS_LOGFILE' flag */ 669 pmclog_stop_kthread(po); 670 671 KASSERT(po->po_kthread == NULL, 672 ("[pmclog,%d] po=%p kthread not stopped", __LINE__, po)); 673 674 /* return all queued log buffers to the global pool */ 675 while ((lb = TAILQ_FIRST(&po->po_logbuffers)) != NULL) { 676 TAILQ_REMOVE(&po->po_logbuffers, lb, plb_next); 677 PMCLOG_INIT_BUFFER_DESCRIPTOR(lb); 678 mtx_lock_spin(&pmc_bufferlist_mtx); 679 TAILQ_INSERT_HEAD(&pmc_bufferlist, lb, plb_next); 680 mtx_unlock_spin(&pmc_bufferlist_mtx); 681 } 682 683 /* return the 'current' buffer to the global pool */ 684 if ((lb = po->po_curbuf) != NULL) { 685 PMCLOG_INIT_BUFFER_DESCRIPTOR(lb); 686 mtx_lock_spin(&pmc_bufferlist_mtx); 687 TAILQ_INSERT_HEAD(&pmc_bufferlist, lb, plb_next); 688 mtx_unlock_spin(&pmc_bufferlist_mtx); 689 } 690 691 /* drop a reference to the fd */ 692 error = fdrop(po->po_file, curthread); 693 po->po_file = NULL; 694 po->po_error = 0; 695 696 return (error); 697 } 698 699 /* 700 * Flush a process' log buffer. 701 */ 702 703 int 704 pmclog_flush(struct pmc_owner *po) 705 { 706 int error; 707 struct pmclog_buffer *lb; 708 709 PMCDBG1(LOG,FLS,1, "po=%p", po); 710 711 /* 712 * If there is a pending error recorded by the logger thread, 713 * return that. 714 */ 715 if (po->po_error) 716 return (po->po_error); 717 718 error = 0; 719 720 /* 721 * Check that we do have an active log file. 722 */ 723 mtx_lock(&pmc_kthread_mtx); 724 if ((po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) { 725 error = EINVAL; 726 goto error; 727 } 728 729 /* 730 * Schedule the current buffer if any and not empty. 731 */ 732 mtx_lock_spin(&po->po_mtx); 733 lb = po->po_curbuf; 734 if (lb && lb->plb_ptr != lb->plb_base) { 735 pmclog_schedule_io(po); 736 } else 737 error = ENOBUFS; 738 mtx_unlock_spin(&po->po_mtx); 739 740 error: 741 mtx_unlock(&pmc_kthread_mtx); 742 743 return (error); 744 } 745 746 int 747 pmclog_close(struct pmc_owner *po) 748 { 749 750 PMCDBG1(LOG,CLO,1, "po=%p", po); 751 752 mtx_lock(&pmc_kthread_mtx); 753 754 /* 755 * Schedule the current buffer. 756 */ 757 mtx_lock_spin(&po->po_mtx); 758 if (po->po_curbuf) 759 pmclog_schedule_io(po); 760 else 761 wakeup_one(po); 762 mtx_unlock_spin(&po->po_mtx); 763 764 /* 765 * Initiate shutdown: no new data queued, 766 * thread will close file on last block. 767 */ 768 po->po_flags |= PMC_PO_SHUTDOWN; 769 770 mtx_unlock(&pmc_kthread_mtx); 771 772 return (0); 773 } 774 775 void 776 pmclog_process_callchain(struct pmc *pm, struct pmc_sample *ps) 777 { 778 int n, recordlen; 779 uint32_t flags; 780 struct pmc_owner *po; 781 782 PMCDBG3(LOG,SAM,1,"pm=%p pid=%d n=%d", pm, ps->ps_pid, 783 ps->ps_nsamples); 784 785 recordlen = offsetof(struct pmclog_callchain, pl_pc) + 786 ps->ps_nsamples * sizeof(uintfptr_t); 787 po = pm->pm_owner; 788 flags = PMC_CALLCHAIN_TO_CPUFLAGS(ps->ps_cpu,ps->ps_flags); 789 PMCLOG_RESERVE(po, CALLCHAIN, recordlen); 790 PMCLOG_EMIT32(ps->ps_pid); 791 PMCLOG_EMIT32(pm->pm_id); 792 PMCLOG_EMIT32(flags); 793 for (n = 0; n < ps->ps_nsamples; n++) 794 PMCLOG_EMITADDR(ps->ps_pc[n]); 795 PMCLOG_DESPATCH(po); 796 } 797 798 void 799 pmclog_process_closelog(struct pmc_owner *po) 800 { 801 PMCLOG_RESERVE(po,CLOSELOG,sizeof(struct pmclog_closelog)); 802 PMCLOG_DESPATCH(po); 803 } 804 805 void 806 pmclog_process_dropnotify(struct pmc_owner *po) 807 { 808 PMCLOG_RESERVE(po,DROPNOTIFY,sizeof(struct pmclog_dropnotify)); 809 PMCLOG_DESPATCH(po); 810 } 811 812 void 813 pmclog_process_map_in(struct pmc_owner *po, pid_t pid, uintfptr_t start, 814 const char *path) 815 { 816 int pathlen, recordlen; 817 818 KASSERT(path != NULL, ("[pmclog,%d] map-in, null path", __LINE__)); 819 820 pathlen = strlen(path) + 1; /* #bytes for path name */ 821 recordlen = offsetof(struct pmclog_map_in, pl_pathname) + 822 pathlen; 823 824 PMCLOG_RESERVE(po, MAP_IN, recordlen); 825 PMCLOG_EMIT32(pid); 826 PMCLOG_EMITADDR(start); 827 PMCLOG_EMITSTRING(path,pathlen); 828 PMCLOG_DESPATCH(po); 829 } 830 831 void 832 pmclog_process_map_out(struct pmc_owner *po, pid_t pid, uintfptr_t start, 833 uintfptr_t end) 834 { 835 KASSERT(start <= end, ("[pmclog,%d] start > end", __LINE__)); 836 837 PMCLOG_RESERVE(po, MAP_OUT, sizeof(struct pmclog_map_out)); 838 PMCLOG_EMIT32(pid); 839 PMCLOG_EMITADDR(start); 840 PMCLOG_EMITADDR(end); 841 PMCLOG_DESPATCH(po); 842 } 843 844 void 845 pmclog_process_pmcallocate(struct pmc *pm) 846 { 847 struct pmc_owner *po; 848 struct pmc_soft *ps; 849 850 po = pm->pm_owner; 851 852 PMCDBG1(LOG,ALL,1, "pm=%p", pm); 853 854 if (PMC_TO_CLASS(pm) == PMC_CLASS_SOFT) { 855 PMCLOG_RESERVE(po, PMCALLOCATEDYN, 856 sizeof(struct pmclog_pmcallocatedyn)); 857 PMCLOG_EMIT32(pm->pm_id); 858 PMCLOG_EMIT32(pm->pm_event); 859 PMCLOG_EMIT32(pm->pm_flags); 860 ps = pmc_soft_ev_acquire(pm->pm_event); 861 if (ps != NULL) 862 PMCLOG_EMITSTRING(ps->ps_ev.pm_ev_name,PMC_NAME_MAX); 863 else 864 PMCLOG_EMITNULLSTRING(PMC_NAME_MAX); 865 pmc_soft_ev_release(ps); 866 PMCLOG_DESPATCH(po); 867 } else { 868 PMCLOG_RESERVE(po, PMCALLOCATE, 869 sizeof(struct pmclog_pmcallocate)); 870 PMCLOG_EMIT32(pm->pm_id); 871 PMCLOG_EMIT32(pm->pm_event); 872 PMCLOG_EMIT32(pm->pm_flags); 873 PMCLOG_DESPATCH(po); 874 } 875 } 876 877 void 878 pmclog_process_pmcattach(struct pmc *pm, pid_t pid, char *path) 879 { 880 int pathlen, recordlen; 881 struct pmc_owner *po; 882 883 PMCDBG2(LOG,ATT,1,"pm=%p pid=%d", pm, pid); 884 885 po = pm->pm_owner; 886 887 pathlen = strlen(path) + 1; /* #bytes for the string */ 888 recordlen = offsetof(struct pmclog_pmcattach, pl_pathname) + pathlen; 889 890 PMCLOG_RESERVE(po, PMCATTACH, recordlen); 891 PMCLOG_EMIT32(pm->pm_id); 892 PMCLOG_EMIT32(pid); 893 PMCLOG_EMITSTRING(path, pathlen); 894 PMCLOG_DESPATCH(po); 895 } 896 897 void 898 pmclog_process_pmcdetach(struct pmc *pm, pid_t pid) 899 { 900 struct pmc_owner *po; 901 902 PMCDBG2(LOG,ATT,1,"!pm=%p pid=%d", pm, pid); 903 904 po = pm->pm_owner; 905 906 PMCLOG_RESERVE(po, PMCDETACH, sizeof(struct pmclog_pmcdetach)); 907 PMCLOG_EMIT32(pm->pm_id); 908 PMCLOG_EMIT32(pid); 909 PMCLOG_DESPATCH(po); 910 } 911 912 /* 913 * Log a context switch event to the log file. 914 */ 915 916 void 917 pmclog_process_proccsw(struct pmc *pm, struct pmc_process *pp, pmc_value_t v) 918 { 919 struct pmc_owner *po; 920 921 KASSERT(pm->pm_flags & PMC_F_LOG_PROCCSW, 922 ("[pmclog,%d] log-process-csw called gratuitously", __LINE__)); 923 924 PMCDBG3(LOG,SWO,1,"pm=%p pid=%d v=%jx", pm, pp->pp_proc->p_pid, 925 v); 926 927 po = pm->pm_owner; 928 929 PMCLOG_RESERVE(po, PROCCSW, sizeof(struct pmclog_proccsw)); 930 PMCLOG_EMIT32(pm->pm_id); 931 PMCLOG_EMIT64(v); 932 PMCLOG_EMIT32(pp->pp_proc->p_pid); 933 PMCLOG_DESPATCH(po); 934 } 935 936 void 937 pmclog_process_procexec(struct pmc_owner *po, pmc_id_t pmid, pid_t pid, 938 uintfptr_t startaddr, char *path) 939 { 940 int pathlen, recordlen; 941 942 PMCDBG3(LOG,EXC,1,"po=%p pid=%d path=\"%s\"", po, pid, path); 943 944 pathlen = strlen(path) + 1; /* #bytes for the path */ 945 recordlen = offsetof(struct pmclog_procexec, pl_pathname) + pathlen; 946 947 PMCLOG_RESERVE(po, PROCEXEC, recordlen); 948 PMCLOG_EMIT32(pid); 949 PMCLOG_EMITADDR(startaddr); 950 PMCLOG_EMIT32(pmid); 951 PMCLOG_EMITSTRING(path,pathlen); 952 PMCLOG_DESPATCH(po); 953 } 954 955 /* 956 * Log a process exit event (and accumulated pmc value) to the log file. 957 */ 958 959 void 960 pmclog_process_procexit(struct pmc *pm, struct pmc_process *pp) 961 { 962 int ri; 963 struct pmc_owner *po; 964 965 ri = PMC_TO_ROWINDEX(pm); 966 PMCDBG3(LOG,EXT,1,"pm=%p pid=%d v=%jx", pm, pp->pp_proc->p_pid, 967 pp->pp_pmcs[ri].pp_pmcval); 968 969 po = pm->pm_owner; 970 971 PMCLOG_RESERVE(po, PROCEXIT, sizeof(struct pmclog_procexit)); 972 PMCLOG_EMIT32(pm->pm_id); 973 PMCLOG_EMIT64(pp->pp_pmcs[ri].pp_pmcval); 974 PMCLOG_EMIT32(pp->pp_proc->p_pid); 975 PMCLOG_DESPATCH(po); 976 } 977 978 /* 979 * Log a fork event. 980 */ 981 982 void 983 pmclog_process_procfork(struct pmc_owner *po, pid_t oldpid, pid_t newpid) 984 { 985 PMCLOG_RESERVE(po, PROCFORK, sizeof(struct pmclog_procfork)); 986 PMCLOG_EMIT32(oldpid); 987 PMCLOG_EMIT32(newpid); 988 PMCLOG_DESPATCH(po); 989 } 990 991 /* 992 * Log a process exit event of the form suitable for system-wide PMCs. 993 */ 994 995 void 996 pmclog_process_sysexit(struct pmc_owner *po, pid_t pid) 997 { 998 PMCLOG_RESERVE(po, SYSEXIT, sizeof(struct pmclog_sysexit)); 999 PMCLOG_EMIT32(pid); 1000 PMCLOG_DESPATCH(po); 1001 } 1002 1003 /* 1004 * Write a user log entry. 1005 */ 1006 1007 int 1008 pmclog_process_userlog(struct pmc_owner *po, struct pmc_op_writelog *wl) 1009 { 1010 int error; 1011 1012 PMCDBG2(LOG,WRI,1, "writelog po=%p ud=0x%x", po, wl->pm_userdata); 1013 1014 error = 0; 1015 1016 PMCLOG_RESERVE_WITH_ERROR(po, USERDATA, 1017 sizeof(struct pmclog_userdata)); 1018 PMCLOG_EMIT32(wl->pm_userdata); 1019 PMCLOG_DESPATCH(po); 1020 1021 error: 1022 return (error); 1023 } 1024 1025 /* 1026 * Initialization. 1027 * 1028 * Create a pool of log buffers and initialize mutexes. 1029 */ 1030 1031 void 1032 pmclog_initialize() 1033 { 1034 int n; 1035 struct pmclog_buffer *plb; 1036 1037 if (pmclog_buffer_size <= 0) { 1038 (void) printf("hwpmc: tunable logbuffersize=%d must be " 1039 "greater than zero.\n", pmclog_buffer_size); 1040 pmclog_buffer_size = PMC_LOG_BUFFER_SIZE; 1041 } 1042 1043 if (pmc_nlogbuffers <= 0) { 1044 (void) printf("hwpmc: tunable nlogbuffers=%d must be greater " 1045 "than zero.\n", pmc_nlogbuffers); 1046 pmc_nlogbuffers = PMC_NLOGBUFFERS; 1047 } 1048 1049 /* create global pool of log buffers */ 1050 for (n = 0; n < pmc_nlogbuffers; n++) { 1051 plb = malloc(1024 * pmclog_buffer_size, M_PMC, 1052 M_WAITOK|M_ZERO); 1053 PMCLOG_INIT_BUFFER_DESCRIPTOR(plb); 1054 TAILQ_INSERT_HEAD(&pmc_bufferlist, plb, plb_next); 1055 } 1056 mtx_init(&pmc_bufferlist_mtx, "pmc-buffer-list", "pmc-leaf", 1057 MTX_SPIN); 1058 mtx_init(&pmc_kthread_mtx, "pmc-kthread", "pmc-sleep", MTX_DEF); 1059 } 1060 1061 /* 1062 * Shutdown logging. 1063 * 1064 * Destroy mutexes and release memory back the to free pool. 1065 */ 1066 1067 void 1068 pmclog_shutdown() 1069 { 1070 struct pmclog_buffer *plb; 1071 1072 mtx_destroy(&pmc_kthread_mtx); 1073 mtx_destroy(&pmc_bufferlist_mtx); 1074 1075 while ((plb = TAILQ_FIRST(&pmc_bufferlist)) != NULL) { 1076 TAILQ_REMOVE(&pmc_bufferlist, plb, plb_next); 1077 free(plb, M_PMC); 1078 } 1079 } 1080