freebsd-skq/sys/kern/kern_ktrace.c

857 lines
20 KiB
C
Raw Normal View History

1994-05-24 10:09:53 +00:00
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)kern_ktrace.c 8.2 (Berkeley) 9/23/93
1999-08-28 01:08:13 +00:00
* $FreeBSD$
1994-05-24 10:09:53 +00:00
*/
#include "opt_ktrace.h"
#include "opt_mac.h"
1994-05-24 10:09:53 +00:00
#include <sys/param.h>
#include <sys/systm.h>
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
#include <sys/fcntl.h>
#include <sys/jail.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/mac.h>
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
#include <sys/malloc.h>
1994-05-24 10:09:53 +00:00
#include <sys/namei.h>
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
#include <sys/proc.h>
#include <sys/unistd.h>
1994-05-24 10:09:53 +00:00
#include <sys/vnode.h>
#include <sys/ktrace.h>
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
#include <sys/sema.h>
#include <sys/sx.h>
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
#include <sys/sysctl.h>
1994-05-24 10:09:53 +00:00
#include <sys/syslog.h>
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
#include <sys/sysproto.h>
1994-05-24 10:09:53 +00:00
static MALLOC_DEFINE(M_KTRACE, "KTRACE", "KTRACE");
#ifdef KTRACE
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
#ifndef KTRACE_REQUEST_POOL
#define KTRACE_REQUEST_POOL 100
#endif
struct ktr_request {
struct ktr_header ktr_header;
struct ucred *ktr_cred;
struct vnode *ktr_vp;
union {
struct ktr_syscall ktr_syscall;
struct ktr_sysret ktr_sysret;
struct ktr_genio ktr_genio;
struct ktr_psig ktr_psig;
struct ktr_csw ktr_csw;
} ktr_data;
int ktr_synchronous;
STAILQ_ENTRY(ktr_request) ktr_list;
};
static int data_lengths[] = {
0, /* none */
offsetof(struct ktr_syscall, ktr_args), /* KTR_SYSCALL */
sizeof(struct ktr_sysret), /* KTR_SYSRET */
0, /* KTR_NAMEI */
sizeof(struct ktr_genio), /* KTR_GENIO */
sizeof(struct ktr_psig), /* KTR_PSIG */
sizeof(struct ktr_csw), /* KTR_CSW */
0 /* KTR_USER */
};
static STAILQ_HEAD(, ktr_request) ktr_todo;
static STAILQ_HEAD(, ktr_request) ktr_free;
static uint ktr_requestpool = KTRACE_REQUEST_POOL;
TUNABLE_INT("kern.ktrace_request_pool", &ktr_requestpool);
static int print_message = 1;
struct mtx ktrace_mtx;
static struct sema ktrace_sema;
static void ktrace_init(void *dummy);
static int sysctl_kern_ktrace_request_pool(SYSCTL_HANDLER_ARGS);
static uint ktrace_resize_pool(uint newsize);
static struct ktr_request *ktr_getrequest(int type);
static void ktr_submitrequest(struct ktr_request *req);
static void ktr_freerequest(struct ktr_request *req);
static void ktr_loop(void *dummy);
static void ktr_writerequest(struct ktr_request *req);
static int ktrcanset(struct thread *,struct proc *);
static int ktrsetchildren(struct thread *,struct proc *,int,int,struct vnode *);
static int ktrops(struct thread *,struct proc *,int,int,struct vnode *);
static void
ktrace_init(void *dummy)
{
struct ktr_request *req;
int i;
mtx_init(&ktrace_mtx, "ktrace", NULL, MTX_DEF | MTX_QUIET);
sema_init(&ktrace_sema, 0, "ktrace");
STAILQ_INIT(&ktr_todo);
STAILQ_INIT(&ktr_free);
for (i = 0; i < ktr_requestpool; i++) {
req = malloc(sizeof(struct ktr_request), M_KTRACE, M_WAITOK);
STAILQ_INSERT_HEAD(&ktr_free, req, ktr_list);
}
kthread_create(ktr_loop, NULL, NULL, RFHIGHPID, "ktrace");
}
SYSINIT(ktrace_init, SI_SUB_KTRACE, SI_ORDER_ANY, ktrace_init, NULL);
static int
sysctl_kern_ktrace_request_pool(SYSCTL_HANDLER_ARGS)
{
struct thread *td;
uint newsize, oldsize, wantsize;
int error;
/* Handle easy read-only case first to avoid warnings from GCC. */
if (!req->newptr) {
mtx_lock(&ktrace_mtx);
oldsize = ktr_requestpool;
mtx_unlock(&ktrace_mtx);
return (SYSCTL_OUT(req, &oldsize, sizeof(uint)));
}
error = SYSCTL_IN(req, &wantsize, sizeof(uint));
if (error)
return (error);
td = curthread;
td->td_inktrace = 1;
mtx_lock(&ktrace_mtx);
oldsize = ktr_requestpool;
newsize = ktrace_resize_pool(wantsize);
mtx_unlock(&ktrace_mtx);
td->td_inktrace = 0;
error = SYSCTL_OUT(req, &oldsize, sizeof(uint));
if (error)
return (error);
if (newsize != wantsize)
return (ENOSPC);
return (0);
}
SYSCTL_PROC(_kern, OID_AUTO, ktrace_request_pool, CTLTYPE_UINT|CTLFLAG_RW,
&ktr_requestpool, 0, sysctl_kern_ktrace_request_pool, "IU", "");
static uint
ktrace_resize_pool(uint newsize)
{
struct ktr_request *req;
mtx_assert(&ktrace_mtx, MA_OWNED);
print_message = 1;
if (newsize == ktr_requestpool)
return (newsize);
if (newsize < ktr_requestpool)
/* Shrink pool down to newsize if possible. */
while (ktr_requestpool > newsize) {
req = STAILQ_FIRST(&ktr_free);
if (req == NULL)
return (ktr_requestpool);
STAILQ_REMOVE_HEAD(&ktr_free, ktr_list);
ktr_requestpool--;
mtx_unlock(&ktrace_mtx);
free(req, M_KTRACE);
mtx_lock(&ktrace_mtx);
}
else
/* Grow pool up to newsize. */
while (ktr_requestpool < newsize) {
mtx_unlock(&ktrace_mtx);
req = malloc(sizeof(struct ktr_request), M_KTRACE,
M_WAITOK);
mtx_lock(&ktrace_mtx);
STAILQ_INSERT_HEAD(&ktr_free, req, ktr_list);
ktr_requestpool++;
}
return (ktr_requestpool);
}
static struct ktr_request *
ktr_getrequest(int type)
{
struct ktr_request *req;
struct thread *td = curthread;
struct proc *p = td->td_proc;
int pm;
td->td_inktrace = 1;
mtx_lock(&ktrace_mtx);
if (!KTRCHECK(td, type)) {
mtx_unlock(&ktrace_mtx);
td->td_inktrace = 0;
return (NULL);
}
req = STAILQ_FIRST(&ktr_free);
if (req != NULL) {
STAILQ_REMOVE_HEAD(&ktr_free, ktr_list);
req->ktr_header.ktr_type = type;
KASSERT(p->p_tracep != NULL, ("ktrace: no trace vnode"));
req->ktr_vp = p->p_tracep;
VREF(p->p_tracep);
mtx_unlock(&ktrace_mtx);
microtime(&req->ktr_header.ktr_time);
req->ktr_header.ktr_pid = p->p_pid;
bcopy(p->p_comm, req->ktr_header.ktr_comm, MAXCOMLEN + 1);
req->ktr_cred = crhold(td->td_ucred);
req->ktr_header.ktr_buffer = NULL;
req->ktr_header.ktr_len = 0;
req->ktr_synchronous = 0;
} else {
pm = print_message;
print_message = 0;
mtx_unlock(&ktrace_mtx);
if (pm)
printf("Out of ktrace request objects.\n");
td->td_inktrace = 0;
}
return (req);
}
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
static void
ktr_submitrequest(struct ktr_request *req)
1994-05-24 10:09:53 +00:00
{
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
mtx_lock(&ktrace_mtx);
STAILQ_INSERT_TAIL(&ktr_todo, req, ktr_list);
sema_post(&ktrace_sema);
if (req->ktr_synchronous) {
/*
* For a synchronous request, we wait for the ktrace thread
* to get to our item in the todo list and wake us up. Then
* we write the request out ourselves and wake the ktrace
* thread back up.
*/
msleep(req, &ktrace_mtx, curthread->td_priority, "ktrsync", 0);
mtx_unlock(&ktrace_mtx);
ktr_writerequest(req);
mtx_lock(&ktrace_mtx);
wakeup(req);
}
mtx_unlock(&ktrace_mtx);
curthread->td_inktrace = 0;
}
static void
ktr_freerequest(struct ktr_request *req)
{
crfree(req->ktr_cred);
mtx_lock(&Giant);
vrele(req->ktr_vp);
mtx_unlock(&Giant);
mtx_lock(&ktrace_mtx);
STAILQ_INSERT_HEAD(&ktr_free, req, ktr_list);
mtx_unlock(&ktrace_mtx);
}
static void
ktr_loop(void *dummy)
{
struct ktr_request *req;
struct thread *td;
struct ucred *cred;
/* Only cache these values once. */
td = curthread;
cred = td->td_ucred;
for (;;) {
sema_wait(&ktrace_sema);
mtx_lock(&ktrace_mtx);
req = STAILQ_FIRST(&ktr_todo);
STAILQ_REMOVE_HEAD(&ktr_todo, ktr_list);
KASSERT(req != NULL, ("got a NULL request"));
if (req->ktr_synchronous) {
wakeup(req);
msleep(req, &ktrace_mtx, curthread->td_priority,
"ktrwait", 0);
mtx_unlock(&ktrace_mtx);
} else {
mtx_unlock(&ktrace_mtx);
/*
* It is not enough just to pass the cached cred
* to the VOP's in ktr_writerequest(). Some VFS
* operations use curthread->td_ucred, so we need
* to modify our thread's credentials as well.
* Evil.
*/
td->td_ucred = req->ktr_cred;
ktr_writerequest(req);
td->td_ucred = cred;
}
ktr_freerequest(req);
}
1994-05-24 10:09:53 +00:00
}
/*
* MPSAFE
*/
void
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
ktrsyscall(code, narg, args)
int code, narg;
register_t args[];
1994-05-24 10:09:53 +00:00
{
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
struct ktr_request *req;
struct ktr_syscall *ktp;
size_t buflen;
1994-05-24 10:09:53 +00:00
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
req = ktr_getrequest(KTR_SYSCALL);
if (req == NULL)
return;
ktp = &req->ktr_data.ktr_syscall;
1994-05-24 10:09:53 +00:00
ktp->ktr_code = code;
ktp->ktr_narg = narg;
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
buflen = sizeof(register_t) * narg;
if (buflen > 0) {
req->ktr_header.ktr_buffer = malloc(buflen, M_KTRACE, M_WAITOK);
bcopy(args, req->ktr_header.ktr_buffer, buflen);
req->ktr_header.ktr_len = buflen;
}
ktr_submitrequest(req);
1994-05-24 10:09:53 +00:00
}
/*
* MPSAFE
*/
void
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
ktrsysret(code, error, retval)
int code, error;
register_t retval;
1994-05-24 10:09:53 +00:00
{
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
struct ktr_request *req;
struct ktr_sysret *ktp;
1994-05-24 10:09:53 +00:00
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
req = ktr_getrequest(KTR_SYSRET);
if (req == NULL)
return;
ktp = &req->ktr_data.ktr_sysret;
ktp->ktr_code = code;
ktp->ktr_error = error;
ktp->ktr_retval = retval; /* what about val2 ? */
ktr_submitrequest(req);
1994-05-24 10:09:53 +00:00
}
void
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
ktrnamei(path)
1994-05-24 10:09:53 +00:00
char *path;
{
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
struct ktr_request *req;
int namelen;
1994-05-24 10:09:53 +00:00
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
req = ktr_getrequest(KTR_NAMEI);
if (req == NULL)
return;
namelen = strlen(path);
if (namelen > 0) {
req->ktr_header.ktr_len = namelen;
req->ktr_header.ktr_buffer = malloc(namelen, M_KTRACE,
M_WAITOK);
bcopy(path, req->ktr_header.ktr_buffer, namelen);
}
ktr_submitrequest(req);
1994-05-24 10:09:53 +00:00
}
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
/*
* Since the uio may not stay valid, we can not hand off this request to
* the thread and need to process it synchronously. However, we wish to
* keep the relative order of records in a trace file correct, so we
* do put this request on the queue (if it isn't empty) and then block.
* The ktrace thread waks us back up when it is time for this event to
* be posted and blocks until we have completed writing out the event
* and woken it back up.
*/
void
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
ktrgenio(fd, rw, uio, error)
1994-05-24 10:09:53 +00:00
int fd;
enum uio_rw rw;
struct uio *uio;
int error;
1994-05-24 10:09:53 +00:00
{
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
struct ktr_request *req;
struct ktr_genio *ktg;
1995-05-30 08:16:23 +00:00
1994-05-24 10:09:53 +00:00
if (error)
return;
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
req = ktr_getrequest(KTR_GENIO);
if (req == NULL)
return;
ktg = &req->ktr_data.ktr_genio;
ktg->ktr_fd = fd;
ktg->ktr_rw = rw;
req->ktr_header.ktr_buffer = uio;
uio->uio_offset = 0;
uio->uio_rw = UIO_WRITE;
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
req->ktr_synchronous = 1;
ktr_submitrequest(req);
1994-05-24 10:09:53 +00:00
}
void
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
ktrpsig(sig, action, mask, code)
1999-10-04 18:29:51 +00:00
int sig;
1994-05-24 10:09:53 +00:00
sig_t action;
sigset_t *mask;
1999-10-04 18:29:51 +00:00
int code;
1994-05-24 10:09:53 +00:00
{
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
struct ktr_request *req;
struct ktr_psig *kp;
1994-05-24 10:09:53 +00:00
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
req = ktr_getrequest(KTR_PSIG);
if (req == NULL)
return;
kp = &req->ktr_data.ktr_psig;
kp->signo = (char)sig;
kp->action = action;
kp->mask = *mask;
kp->code = code;
ktr_submitrequest(req);
1994-05-24 10:09:53 +00:00
}
void
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
ktrcsw(out, user)
1994-05-24 10:09:53 +00:00
int out, user;
{
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
struct ktr_request *req;
struct ktr_csw *kc;
1994-05-24 10:09:53 +00:00
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
req = ktr_getrequest(KTR_CSW);
if (req == NULL)
return;
kc = &req->ktr_data.ktr_csw;
kc->out = out;
kc->user = user;
ktr_submitrequest(req);
1994-05-24 10:09:53 +00:00
}
#endif
1994-05-24 10:09:53 +00:00
/* Interface and common routines */
/*
* ktrace system call
*/
#ifndef _SYS_SYSPROTO_H_
1994-05-24 10:09:53 +00:00
struct ktrace_args {
char *fname;
int ops;
int facs;
int pid;
};
#endif
1994-05-24 10:09:53 +00:00
/* ARGSUSED */
int
ktrace(td, uap)
struct thread *td;
1994-05-24 10:09:53 +00:00
register struct ktrace_args *uap;
{
#ifdef KTRACE
1994-05-24 10:09:53 +00:00
register struct vnode *vp = NULL;
register struct proc *p;
struct pgrp *pg;
int facs = uap->facs & ~KTRFAC_ROOT;
int ops = KTROP(uap->ops);
int descend = uap->ops & KTRFLAG_DESCEND;
int ret = 0;
int flags, error = 0;
1994-05-24 10:09:53 +00:00
struct nameidata nd;
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
td->td_inktrace = 1;
1994-05-24 10:09:53 +00:00
if (ops != KTROP_CLEAR) {
/*
* an operation which requires a file argument.
*/
NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, td);
flags = FREAD | FWRITE | O_NOFOLLOW;
error = vn_open(&nd, &flags, 0);
if (error) {
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
td->td_inktrace = 0;
1994-05-24 10:09:53 +00:00
return (error);
}
NDFREE(&nd, NDF_ONLY_PNBUF);
1994-05-24 10:09:53 +00:00
vp = nd.ni_vp;
VOP_UNLOCK(vp, 0, td);
1994-05-24 10:09:53 +00:00
if (vp->v_type != VREG) {
(void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
td->td_inktrace = 0;
1994-05-24 10:09:53 +00:00
return (EACCES);
}
}
/*
* Clear all uses of the tracefile.
1994-05-24 10:09:53 +00:00
*/
if (ops == KTROP_CLEARFILE) {
sx_slock(&allproc_lock);
LIST_FOREACH(p, &allproc, p_list) {
PROC_LOCK(p);
1994-05-24 10:09:53 +00:00
if (p->p_tracep == vp) {
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
if (ktrcanset(td, p)) {
mtx_lock(&ktrace_mtx);
1994-05-24 10:09:53 +00:00
p->p_tracep = NULL;
p->p_traceflag = 0;
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
mtx_unlock(&ktrace_mtx);
PROC_UNLOCK(p);
1994-05-24 10:09:53 +00:00
(void) vn_close(vp, FREAD|FWRITE,
td->td_ucred, td);
} else {
PROC_UNLOCK(p);
1994-05-24 10:09:53 +00:00
error = EPERM;
}
} else
PROC_UNLOCK(p);
1994-05-24 10:09:53 +00:00
}
sx_sunlock(&allproc_lock);
1994-05-24 10:09:53 +00:00
goto done;
}
/*
* need something to (un)trace (XXX - why is this here?)
*/
if (!facs) {
error = EINVAL;
goto done;
}
1995-05-30 08:16:23 +00:00
/*
1994-05-24 10:09:53 +00:00
* do it
*/
if (uap->pid < 0) {
/*
* by process group
*/
sx_slock(&proctree_lock);
1994-05-24 10:09:53 +00:00
pg = pgfind(-uap->pid);
if (pg == NULL) {
sx_sunlock(&proctree_lock);
1994-05-24 10:09:53 +00:00
error = ESRCH;
goto done;
}
/*
* ktrops() may call vrele(). Lock pg_members
* by the proctree_lock rather than pg_mtx.
*/
PGRP_UNLOCK(pg);
LIST_FOREACH(p, &pg->pg_members, p_pglist)
1994-05-24 10:09:53 +00:00
if (descend)
ret |= ktrsetchildren(td, p, ops, facs, vp);
1995-05-30 08:16:23 +00:00
else
ret |= ktrops(td, p, ops, facs, vp);
sx_sunlock(&proctree_lock);
1994-05-24 10:09:53 +00:00
} else {
/*
* by pid
*/
p = pfind(uap->pid);
if (p == NULL) {
error = ESRCH;
goto done;
}
PROC_UNLOCK(p);
/* XXX: UNLOCK above has a race */
1994-05-24 10:09:53 +00:00
if (descend)
ret |= ktrsetchildren(td, p, ops, facs, vp);
1994-05-24 10:09:53 +00:00
else
ret |= ktrops(td, p, ops, facs, vp);
1994-05-24 10:09:53 +00:00
}
if (!ret)
error = EPERM;
done:
if (vp != NULL)
(void) vn_close(vp, FWRITE, td->td_ucred, td);
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
td->td_inktrace = 0;
1994-05-24 10:09:53 +00:00
return (error);
#else
return ENOSYS;
#endif
1994-05-24 10:09:53 +00:00
}
/*
* utrace system call
*/
/* ARGSUSED */
int
utrace(td, uap)
struct thread *td;
register struct utrace_args *uap;
{
#ifdef KTRACE
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
struct ktr_request *req;
void *cp;
2001-01-08 07:22:06 +00:00
if (uap->len > KTR_USER_MAXLEN)
return (EINVAL);
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
req = ktr_getrequest(KTR_USER);
if (req == NULL)
return (0);
cp = malloc(uap->len, M_KTRACE, M_WAITOK);
if (!copyin(uap->addr, cp, uap->len)) {
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
req->ktr_header.ktr_buffer = cp;
req->ktr_header.ktr_len = uap->len;
ktr_submitrequest(req);
} else {
ktr_freerequest(req);
td->td_inktrace = 0;
}
return (0);
#else
return (ENOSYS);
#endif
}
#ifdef KTRACE
static int
ktrops(td, p, ops, facs, vp)
struct thread *td;
struct proc *p;
1994-05-24 10:09:53 +00:00
int ops, facs;
struct vnode *vp;
{
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
struct vnode *tracevp = NULL;
1994-05-24 10:09:53 +00:00
PROC_LOCK(p);
if (!ktrcanset(td, p)) {
PROC_UNLOCK(p);
1994-05-24 10:09:53 +00:00
return (0);
}
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
mtx_lock(&ktrace_mtx);
1994-05-24 10:09:53 +00:00
if (ops == KTROP_SET) {
1995-05-30 08:16:23 +00:00
if (p->p_tracep != vp) {
1994-05-24 10:09:53 +00:00
/*
* if trace file already in use, relinquish below
1994-05-24 10:09:53 +00:00
*/
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
tracevp = p->p_tracep;
VREF(vp);
p->p_tracep = vp;
1994-05-24 10:09:53 +00:00
}
p->p_traceflag |= facs;
if (td->td_ucred->cr_uid == 0)
1994-05-24 10:09:53 +00:00
p->p_traceflag |= KTRFAC_ROOT;
1995-05-30 08:16:23 +00:00
} else {
1994-05-24 10:09:53 +00:00
/* KTROP_CLEAR */
if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0) {
/* no more tracing */
p->p_traceflag = 0;
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
tracevp = p->p_tracep;
p->p_tracep = NULL;
1994-05-24 10:09:53 +00:00
}
}
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
mtx_unlock(&ktrace_mtx);
PROC_UNLOCK(p);
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
if (tracevp != NULL)
vrele(tracevp);
1994-05-24 10:09:53 +00:00
return (1);
}
static int
ktrsetchildren(td, top, ops, facs, vp)
struct thread *td;
struct proc *top;
1994-05-24 10:09:53 +00:00
int ops, facs;
struct vnode *vp;
{
register struct proc *p;
register int ret = 0;
p = top;
sx_slock(&proctree_lock);
1994-05-24 10:09:53 +00:00
for (;;) {
ret |= ktrops(td, p, ops, facs, vp);
1994-05-24 10:09:53 +00:00
/*
* If this process has children, descend to them next,
* otherwise do any siblings, and if done with this level,
* follow back up the tree (but not past top).
*/
if (!LIST_EMPTY(&p->p_children))
p = LIST_FIRST(&p->p_children);
1994-05-24 10:09:53 +00:00
else for (;;) {
if (p == top) {
sx_sunlock(&proctree_lock);
1994-05-24 10:09:53 +00:00
return (ret);
}
if (LIST_NEXT(p, p_sibling)) {
p = LIST_NEXT(p, p_sibling);
1994-05-24 10:09:53 +00:00
break;
}
p = p->p_pptr;
1994-05-24 10:09:53 +00:00
}
}
/*NOTREACHED*/
}
static void
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
ktr_writerequest(struct ktr_request *req)
1994-05-24 10:09:53 +00:00
{
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
struct ktr_header *kth;
struct vnode *vp;
struct uio *uio = NULL;
struct proc *p;
struct thread *td;
struct ucred *cred;
1994-05-24 10:09:53 +00:00
struct uio auio;
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
struct iovec aiov[3];
struct mount *mp;
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
int datalen, buflen, vrele_count;
1994-05-24 10:09:53 +00:00
int error;
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
vp = req->ktr_vp;
/*
* If vp is NULL, the vp has been cleared out from under this
* request, so just drop it.
*/
1994-05-24 10:09:53 +00:00
if (vp == NULL)
return;
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
kth = &req->ktr_header;
datalen = data_lengths[kth->ktr_type];
buflen = kth->ktr_len;
cred = req->ktr_cred;
td = curthread;
1994-05-24 10:09:53 +00:00
auio.uio_iov = &aiov[0];
auio.uio_offset = 0;
auio.uio_segflg = UIO_SYSSPACE;
auio.uio_rw = UIO_WRITE;
aiov[0].iov_base = (caddr_t)kth;
aiov[0].iov_len = sizeof(struct ktr_header);
auio.uio_resid = sizeof(struct ktr_header);
auio.uio_iovcnt = 1;
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
auio.uio_td = td;
if (datalen != 0) {
aiov[1].iov_base = (caddr_t)&req->ktr_data;
aiov[1].iov_len = datalen;
auio.uio_resid += datalen;
1994-05-24 10:09:53 +00:00
auio.uio_iovcnt++;
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
kth->ktr_len += datalen;
1994-05-24 10:09:53 +00:00
}
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
if (buflen != 0) {
KASSERT(kth->ktr_buffer != NULL, ("ktrace: nothing to write"));
aiov[auio.uio_iovcnt].iov_base = kth->ktr_buffer;
aiov[auio.uio_iovcnt].iov_len = buflen;
auio.uio_resid += buflen;
auio.uio_iovcnt++;
} else
uio = kth->ktr_buffer;
KASSERT((uio == NULL) ^ (kth->ktr_type == KTR_GENIO),
("ktrace: uio and genio mismatch"));
if (uio != NULL)
kth->ktr_len += uio->uio_resid;
mtx_lock(&Giant);
vn_start_write(vp, &mp, V_WAIT);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
(void)VOP_LEASE(vp, td, cred, LEASE_WRITE);
#ifdef MAC
error = mac_check_vnode_op(cred, vp, MAC_OP_VNODE_WRITE);
if (error == 0)
#endif
error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, cred);
if (error == 0 && uio != NULL) {
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
(void)VOP_LEASE(vp, td, cred, LEASE_WRITE);
error = VOP_WRITE(vp, uio, IO_UNIT | IO_APPEND, cred);
}
VOP_UNLOCK(vp, 0, td);
vn_finished_write(mp);
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
mtx_unlock(&Giant);
if (buflen != 0)
free(kth->ktr_buffer, M_KTRACE);
1994-05-24 10:09:53 +00:00
if (!error)
return;
/*
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
* If error encountered, give up tracing on this vnode. We defer
* all the vrele()'s on the vnode until after we are finished walking
* the various lists to avoid needlessly holding locks.
1994-05-24 10:09:53 +00:00
*/
log(LOG_NOTICE, "ktrace write failed, errno %d, tracing stopped\n",
error);
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
vrele_count = 0;
/*
* First, clear this vnode from being used by any processes in the
* system.
* XXX - If one process gets an EPERM writing to the vnode, should
* we really do this? Other processes might have suitable
* credentials for the operation.
*/
sx_slock(&allproc_lock);
LIST_FOREACH(p, &allproc, p_list) {
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
PROC_LOCK(p);
1994-05-24 10:09:53 +00:00
if (p->p_tracep == vp) {
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
mtx_lock(&ktrace_mtx);
1994-05-24 10:09:53 +00:00
p->p_tracep = NULL;
p->p_traceflag = 0;
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
mtx_unlock(&ktrace_mtx);
vrele_count++;
1994-05-24 10:09:53 +00:00
}
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
PROC_UNLOCK(p);
1994-05-24 10:09:53 +00:00
}
sx_sunlock(&allproc_lock);
Overhaul the ktrace subsystem a bit. For the most part, the actual vnode operations to dump a ktrace event out to an output file are now handled asychronously by a ktrace worker thread. This enables most ktrace events to not need Giant once p_tracep and p_traceflag are suitably protected by the new ktrace_lock. There is a single todo list of pending ktrace requests. The various ktrace tracepoints allocate a ktrace request object and tack it onto the end of the queue. The ktrace kernel thread grabs requests off the head of the queue and processes them using the trace vnode and credentials of the thread triggering the event. Since we cannot assume that the user memory referenced when doing a ktrgenio() will be valid and since we can't access it from the ktrace worker thread without a bit of hassle anyways, ktrgenio() requests are still handled synchronously. However, in order to ensure that the requests from a given thread still maintain relative order to one another, when a synchronous ktrace event (such as a genio event) is triggered, we still put the request object on the todo list to synchronize with the worker thread. The original thread blocks atomically with putting the item on the queue. When the worker thread comes across an asynchronous request, it wakes up the original thread and then blocks to ensure it doesn't manage to write a later event before the original thread has a chance to write out the synchronous event. When the original thread wakes up, it writes out the synchronous using its own context and then finally wakes the worker thread back up. Yuck. The sychronous events aren't pretty but they do work. Since ktrace events can be triggered in fairly low-level areas (msleep() and cv_wait() for example) the ktrace code is designed to use very few locks when posting an event (currently just the ktrace_mtx lock and the vnode interlock to bump the refcoun on the trace vnode). This also means that we can't allocate a ktrace request object when an event is triggered. Instead, ktrace request objects are allocated from a pre-allocated pool and returned to the pool after a request is serviced. The size of this pool defaults to 100 objects, which is about 13k on an i386 kernel. The size of the pool can be adjusted at compile time via the KTRACE_REQUEST_POOL kernel option, at boot time via the kern.ktrace_request_pool loader tunable, or at runtime via the kern.ktrace_request_pool sysctl. If the pool of request objects is exhausted, then a warning message is printed to the console. The message is rate-limited in that it is only printed once until the size of the pool is adjusted via the sysctl. I have tested all kernel traces but have not tested user traces submitted by utrace(2), though they should work fine in theory. Since a ktrace request has several properties (content of event, trace vnode, details of originating process, credentials for I/O, etc.), I chose to drop the first argument to the various ktrfoo() functions. Currently the functions just assume the event is posted from curthread. If there is a great desire to do so, I suppose I could instead put back the first argument but this time make it a thread pointer instead of a vnode pointer. Also, KTRPOINT() now takes a thread as its first argument instead of a process. This is because the check for a recursive ktrace event is now per-thread instead of process-wide. Tested on: i386 Compiles on: sparc64, alpha
2002-06-07 05:32:59 +00:00
/*
* Second, clear this vnode from any pending requests.
*/
mtx_lock(&ktrace_mtx);
STAILQ_FOREACH(req, &ktr_todo, ktr_list) {
if (req->ktr_vp == vp) {
req->ktr_vp = NULL;
vrele_count++;
}
}
mtx_unlock(&ktrace_mtx);
mtx_lock(&Giant);
while (vrele_count-- > 0)
vrele(vp);
mtx_unlock(&Giant);
1994-05-24 10:09:53 +00:00
}
/*
* Return true if caller has permission to set the ktracing state
* of target. Essentially, the target can't possess any
* more permissions than the caller. KTRFAC_ROOT signifies that
1995-05-30 08:16:23 +00:00
* root previously set the tracing status on the target process, and
1994-05-24 10:09:53 +00:00
* so, only root may further change it.
*/
static int
ktrcanset(td, targetp)
struct thread *td;
struct proc *targetp;
1994-05-24 10:09:53 +00:00
{
PROC_LOCK_ASSERT(targetp, MA_OWNED);
if (targetp->p_traceflag & KTRFAC_ROOT &&
suser_cred(td->td_ucred, PRISON_ROOT))
This Implements the mumbled about "Jail" feature. This is a seriously beefed up chroot kind of thing. The process is jailed along the same lines as a chroot does it, but with additional tough restrictions imposed on what the superuser can do. For all I know, it is safe to hand over the root bit inside a prison to the customer living in that prison, this is what it was developed for in fact: "real virtual servers". Each prison has an ip number associated with it, which all IP communications will be coerced to use and each prison has its own hostname. Needless to say, you need more RAM this way, but the advantage is that each customer can run their own particular version of apache and not stomp on the toes of their neighbors. It generally does what one would expect, but setting up a jail still takes a little knowledge. A few notes: I have no scripts for setting up a jail, don't ask me for them. The IP number should be an alias on one of the interfaces. mount a /proc in each jail, it will make ps more useable. /proc/<pid>/status tells the hostname of the prison for jailed processes. Quotas are only sensible if you have a mountpoint per prison. There are no privisions for stopping resource-hogging. Some "#ifdef INET" and similar may be missing (send patches!) If somebody wants to take it from here and develop it into more of a "virtual machine" they should be most welcome! Tools, comments, patches & documentation most welcome. Have fun... Sponsored by: http://www.rndassociates.com/ Run for almost a year by: http://www.servetheweb.com/
1999-04-28 11:38:52 +00:00
return (0);
1994-05-24 10:09:53 +00:00
if (p_candebug(td, targetp) != 0)
return (0);
return (1);
1994-05-24 10:09:53 +00:00
}
#endif /* KTRACE */