xref: /freebsd/sys/kern/kern_ktrace.c (revision 166b7573b5220aadf8b02a85933c9651b909b309)
19454b2d8SWarner Losh /*-
251369649SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
351369649SPedro F. Giffuni  *
4df8bae1dSRodney W. Grimes  * Copyright (c) 1989, 1993
52c255e9dSRobert Watson  *	The Regents of the University of California.
62c255e9dSRobert Watson  * Copyright (c) 2005 Robert N. M. Watson
72c255e9dSRobert Watson  * All rights reserved.
8df8bae1dSRodney W. Grimes  *
9df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
10df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
11df8bae1dSRodney W. Grimes  * are met:
12df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
13df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
14df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
15df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
16df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
1769a28758SEd Maste  * 3. Neither the name of the University nor the names of its contributors
18df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
19df8bae1dSRodney W. Grimes  *    without specific prior written permission.
20df8bae1dSRodney W. Grimes  *
21df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
32df8bae1dSRodney W. Grimes  */
33df8bae1dSRodney W. Grimes 
34677b542eSDavid E. O'Brien #include <sys/cdefs.h>
35db6a20e2SGarrett Wollman #include "opt_ktrace.h"
36df8bae1dSRodney W. Grimes 
37df8bae1dSRodney W. Grimes #include <sys/param.h>
384a144410SRobert Watson #include <sys/capsicum.h>
39f23b4c91SGarrett Wollman #include <sys/systm.h>
40ea3fc8e4SJohn Baldwin #include <sys/fcntl.h>
41ea3fc8e4SJohn Baldwin #include <sys/kernel.h>
42ea3fc8e4SJohn Baldwin #include <sys/kthread.h>
43fb919e4dSMark Murray #include <sys/lock.h>
44fb919e4dSMark Murray #include <sys/mutex.h>
45ea3fc8e4SJohn Baldwin #include <sys/malloc.h>
46033eb86eSJeff Roberson #include <sys/mount.h>
47df8bae1dSRodney W. Grimes #include <sys/namei.h>
48acd3428bSRobert Watson #include <sys/priv.h>
49ea3fc8e4SJohn Baldwin #include <sys/proc.h>
5002645b88SKonstantin Belousov #include <sys/resourcevar.h>
51ea3fc8e4SJohn Baldwin #include <sys/unistd.h>
52df8bae1dSRodney W. Grimes #include <sys/vnode.h>
5360e15db9SDag-Erling Smørgrav #include <sys/socket.h>
5460e15db9SDag-Erling Smørgrav #include <sys/stat.h>
55df8bae1dSRodney W. Grimes #include <sys/ktrace.h>
561005a129SJohn Baldwin #include <sys/sx.h>
57ea3fc8e4SJohn Baldwin #include <sys/sysctl.h>
587705d4b2SDmitry Chagin #include <sys/sysent.h>
59df8bae1dSRodney W. Grimes #include <sys/syslog.h>
60ea3fc8e4SJohn Baldwin #include <sys/sysproto.h>
61df8bae1dSRodney W. Grimes 
62aed55708SRobert Watson #include <security/mac/mac_framework.h>
63aed55708SRobert Watson 
642c255e9dSRobert Watson /*
652c255e9dSRobert Watson  * The ktrace facility allows the tracing of certain key events in user space
662c255e9dSRobert Watson  * processes, such as system calls, signal delivery, context switches, and
672c255e9dSRobert Watson  * user generated events using utrace(2).  It works by streaming event
682c255e9dSRobert Watson  * records and data to a vnode associated with the process using the
692c255e9dSRobert Watson  * ktrace(2) system call.  In general, records can be written directly from
702c255e9dSRobert Watson  * the context that generates the event.  One important exception to this is
712c255e9dSRobert Watson  * during a context switch, where sleeping is not permitted.  To handle this
722c255e9dSRobert Watson  * case, trace events are generated using in-kernel ktr_request records, and
732c255e9dSRobert Watson  * then delivered to disk at a convenient moment -- either immediately, the
742c255e9dSRobert Watson  * next traceable event, at system call return, or at process exit.
752c255e9dSRobert Watson  *
762c255e9dSRobert Watson  * When dealing with multiple threads or processes writing to the same event
772c255e9dSRobert Watson  * log, ordering guarantees are weak: specifically, if an event has multiple
782c255e9dSRobert Watson  * records (i.e., system call enter and return), they may be interlaced with
792c255e9dSRobert Watson  * records from another event.  Process and thread ID information is provided
802c255e9dSRobert Watson  * in the record, and user applications can de-interlace events if required.
812c255e9dSRobert Watson  */
822c255e9dSRobert Watson 
83a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_KTRACE, "KTRACE", "KTRACE");
8455166637SPoul-Henning Kamp 
85db6a20e2SGarrett Wollman #ifdef KTRACE
86ea3fc8e4SJohn Baldwin 
87de5b1952SAlexander Leidinger FEATURE(ktrace, "Kernel support for system-call tracing");
88de5b1952SAlexander Leidinger 
89ea3fc8e4SJohn Baldwin #ifndef KTRACE_REQUEST_POOL
90ea3fc8e4SJohn Baldwin #define	KTRACE_REQUEST_POOL	100
91ea3fc8e4SJohn Baldwin #endif
92ea3fc8e4SJohn Baldwin 
93ea3fc8e4SJohn Baldwin struct ktr_request {
94ea3fc8e4SJohn Baldwin 	struct	ktr_header ktr_header;
95d977a583SRobert Watson 	void	*ktr_buffer;
96ea3fc8e4SJohn Baldwin 	union {
977705d4b2SDmitry Chagin 		struct	ktr_proc_ctor ktr_proc_ctor;
98c601ad8eSDag-Erling Smørgrav 		struct	ktr_cap_fail ktr_cap_fail;
99ea3fc8e4SJohn Baldwin 		struct	ktr_syscall ktr_syscall;
100ea3fc8e4SJohn Baldwin 		struct	ktr_sysret ktr_sysret;
101ea3fc8e4SJohn Baldwin 		struct	ktr_genio ktr_genio;
102ea3fc8e4SJohn Baldwin 		struct	ktr_psig ktr_psig;
103ea3fc8e4SJohn Baldwin 		struct	ktr_csw ktr_csw;
10435818d2eSJohn Baldwin 		struct	ktr_fault ktr_fault;
10535818d2eSJohn Baldwin 		struct	ktr_faultend ktr_faultend;
106ffb66079SJohn Baldwin 		struct  ktr_struct_array ktr_struct_array;
107ea3fc8e4SJohn Baldwin 	} ktr_data;
108ea3fc8e4SJohn Baldwin 	STAILQ_ENTRY(ktr_request) ktr_list;
109ea3fc8e4SJohn Baldwin };
110ea3fc8e4SJohn Baldwin 
1113080f82bSMark Johnston static const int data_lengths[] = {
112093e059cSJilles Tjoelker 	[KTR_SYSCALL] = offsetof(struct ktr_syscall, ktr_args),
113093e059cSJilles Tjoelker 	[KTR_SYSRET] = sizeof(struct ktr_sysret),
114093e059cSJilles Tjoelker 	[KTR_NAMEI] = 0,
115093e059cSJilles Tjoelker 	[KTR_GENIO] = sizeof(struct ktr_genio),
116093e059cSJilles Tjoelker 	[KTR_PSIG] = sizeof(struct ktr_psig),
117093e059cSJilles Tjoelker 	[KTR_CSW] = sizeof(struct ktr_csw),
118093e059cSJilles Tjoelker 	[KTR_USER] = 0,
119093e059cSJilles Tjoelker 	[KTR_STRUCT] = 0,
120093e059cSJilles Tjoelker 	[KTR_SYSCTL] = 0,
121093e059cSJilles Tjoelker 	[KTR_PROCCTOR] = sizeof(struct ktr_proc_ctor),
122093e059cSJilles Tjoelker 	[KTR_PROCDTOR] = 0,
123093e059cSJilles Tjoelker 	[KTR_CAPFAIL] = sizeof(struct ktr_cap_fail),
124093e059cSJilles Tjoelker 	[KTR_FAULT] = sizeof(struct ktr_fault),
125093e059cSJilles Tjoelker 	[KTR_FAULTEND] = sizeof(struct ktr_faultend),
126ffb66079SJohn Baldwin 	[KTR_STRUCT_ARRAY] = sizeof(struct ktr_struct_array),
127ea3fc8e4SJohn Baldwin };
128ea3fc8e4SJohn Baldwin 
129ea3fc8e4SJohn Baldwin static STAILQ_HEAD(, ktr_request) ktr_free;
130ea3fc8e4SJohn Baldwin 
1317029da5cSPawel Biernacki static SYSCTL_NODE(_kern, OID_AUTO, ktrace, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
1327029da5cSPawel Biernacki     "KTRACE options");
13312301fc3SJohn Baldwin 
1348b149b51SJohn Baldwin static u_int ktr_requestpool = KTRACE_REQUEST_POOL;
13512301fc3SJohn Baldwin TUNABLE_INT("kern.ktrace.request_pool", &ktr_requestpool);
13612301fc3SJohn Baldwin 
1371e4296c9SKonstantin Belousov u_int ktr_geniosize = PAGE_SIZE;
138af3b2549SHans Petter Selasky SYSCTL_UINT(_kern_ktrace, OID_AUTO, genio_size, CTLFLAG_RWTUN, &ktr_geniosize,
13912301fc3SJohn Baldwin     0, "Maximum size of genio event payload");
140ea3fc8e4SJohn Baldwin 
141ea2b64c2SKonstantin Belousov /*
142ea2b64c2SKonstantin Belousov  * Allow to not to send signal to traced process, in which context the
143ea2b64c2SKonstantin Belousov  * ktr record is written.  The limit is applied from the process that
144ea2b64c2SKonstantin Belousov  * set up ktrace, so killing the traced process is not completely fair.
145ea2b64c2SKonstantin Belousov  */
146ea2b64c2SKonstantin Belousov int ktr_filesize_limit_signal = 0;
147ea2b64c2SKonstantin Belousov SYSCTL_INT(_kern_ktrace, OID_AUTO, filesize_limit_signal, CTLFLAG_RWTUN,
148ea2b64c2SKonstantin Belousov     &ktr_filesize_limit_signal, 0,
149ea2b64c2SKonstantin Belousov     "Send SIGXFSZ to the traced process when the log size limit is exceeded");
150ea2b64c2SKonstantin Belousov 
151ea3fc8e4SJohn Baldwin static int print_message = 1;
152d680caabSJohn Baldwin static struct mtx ktrace_mtx;
1532c255e9dSRobert Watson static struct sx ktrace_sx;
154ea3fc8e4SJohn Baldwin 
1551762f674SKonstantin Belousov struct ktr_io_params {
1561762f674SKonstantin Belousov 	struct vnode	*vp;
1571762f674SKonstantin Belousov 	struct ucred	*cr;
15802645b88SKonstantin Belousov 	off_t		lim;
1591762f674SKonstantin Belousov 	u_int		refs;
1601762f674SKonstantin Belousov };
1611762f674SKonstantin Belousov 
162ea3fc8e4SJohn Baldwin static void ktrace_init(void *dummy);
163ea3fc8e4SJohn Baldwin static int sysctl_kern_ktrace_request_pool(SYSCTL_HANDLER_ARGS);
164b4c20e5eSDmitry Chagin static u_int ktrace_resize_pool(u_int oldsize, u_int newsize);
16522ec0406SDmitry Chagin static struct ktr_request *ktr_getrequest_entered(struct thread *td, int type);
166ea3fc8e4SJohn Baldwin static struct ktr_request *ktr_getrequest(int type);
1672c255e9dSRobert Watson static void ktr_submitrequest(struct thread *td, struct ktr_request *req);
1681762f674SKonstantin Belousov static struct ktr_io_params *ktr_freeproc(struct proc *p);
169ea3fc8e4SJohn Baldwin static void ktr_freerequest(struct ktr_request *req);
170d680caabSJohn Baldwin static void ktr_freerequest_locked(struct ktr_request *req);
1712c255e9dSRobert Watson static void ktr_writerequest(struct thread *td, struct ktr_request *req);
172a7ff7443SJohn Baldwin static int ktrcanset(struct thread *,struct proc *);
1731762f674SKonstantin Belousov static int ktrsetchildren(struct thread *, struct proc *, int, int,
1741762f674SKonstantin Belousov     struct ktr_io_params *);
1751762f674SKonstantin Belousov static int ktrops(struct thread *, struct proc *, int, int,
1761762f674SKonstantin Belousov     struct ktr_io_params *);
17722ec0406SDmitry Chagin static void ktrprocctor_entered(struct thread *, struct proc *);
17898d93822SBruce Evans 
1792c255e9dSRobert Watson /*
1802c255e9dSRobert Watson  * ktrace itself generates events, such as context switches, which we do not
1812c255e9dSRobert Watson  * wish to trace.  Maintain a flag, TDP_INKTRACE, on each thread to determine
1822c255e9dSRobert Watson  * whether or not it is in a region where tracing of events should be
1832c255e9dSRobert Watson  * suppressed.
1842c255e9dSRobert Watson  */
1852c255e9dSRobert Watson static void
1862c255e9dSRobert Watson ktrace_enter(struct thread *td)
1872c255e9dSRobert Watson {
1882c255e9dSRobert Watson 
1892c255e9dSRobert Watson 	KASSERT(!(td->td_pflags & TDP_INKTRACE), ("ktrace_enter: flag set"));
1902c255e9dSRobert Watson 	td->td_pflags |= TDP_INKTRACE;
1912c255e9dSRobert Watson }
1922c255e9dSRobert Watson 
1932c255e9dSRobert Watson static void
1942c255e9dSRobert Watson ktrace_exit(struct thread *td)
1952c255e9dSRobert Watson {
1962c255e9dSRobert Watson 
1972c255e9dSRobert Watson 	KASSERT(td->td_pflags & TDP_INKTRACE, ("ktrace_exit: flag not set"));
1982c255e9dSRobert Watson 	td->td_pflags &= ~TDP_INKTRACE;
1992c255e9dSRobert Watson }
2002c255e9dSRobert Watson 
2012c255e9dSRobert Watson static void
2022c255e9dSRobert Watson ktrace_assert(struct thread *td)
2032c255e9dSRobert Watson {
2042c255e9dSRobert Watson 
2052c255e9dSRobert Watson 	KASSERT(td->td_pflags & TDP_INKTRACE, ("ktrace_assert: flag not set"));
2062c255e9dSRobert Watson }
2072c255e9dSRobert Watson 
208ea3fc8e4SJohn Baldwin static void
209c6d31b83SKonstantin Belousov ast_ktrace(struct thread *td, int tda __unused)
210c6d31b83SKonstantin Belousov {
211c6d31b83SKonstantin Belousov 	KTRUSERRET(td);
212c6d31b83SKonstantin Belousov }
213c6d31b83SKonstantin Belousov 
214c6d31b83SKonstantin Belousov static void
215ea3fc8e4SJohn Baldwin ktrace_init(void *dummy)
216df8bae1dSRodney W. Grimes {
217ea3fc8e4SJohn Baldwin 	struct ktr_request *req;
218ea3fc8e4SJohn Baldwin 	int i;
219df8bae1dSRodney W. Grimes 
220ea3fc8e4SJohn Baldwin 	mtx_init(&ktrace_mtx, "ktrace", NULL, MTX_DEF | MTX_QUIET);
2212c255e9dSRobert Watson 	sx_init(&ktrace_sx, "ktrace_sx");
222ea3fc8e4SJohn Baldwin 	STAILQ_INIT(&ktr_free);
223ea3fc8e4SJohn Baldwin 	for (i = 0; i < ktr_requestpool; i++) {
2245c18bf9dSMark Johnston 		req = malloc(sizeof(struct ktr_request), M_KTRACE, M_WAITOK |
2255c18bf9dSMark Johnston 		    M_ZERO);
226ea3fc8e4SJohn Baldwin 		STAILQ_INSERT_HEAD(&ktr_free, req, ktr_list);
227ea3fc8e4SJohn Baldwin 	}
2284a662c90SKonstantin Belousov 	ast_register(TDA_KTRACE, ASTR_ASTF_REQUIRED, 0, ast_ktrace);
229ea3fc8e4SJohn Baldwin }
230ea3fc8e4SJohn Baldwin SYSINIT(ktrace_init, SI_SUB_KTRACE, SI_ORDER_ANY, ktrace_init, NULL);
231ea3fc8e4SJohn Baldwin 
232ea3fc8e4SJohn Baldwin static int
233ea3fc8e4SJohn Baldwin sysctl_kern_ktrace_request_pool(SYSCTL_HANDLER_ARGS)
234ea3fc8e4SJohn Baldwin {
235ea3fc8e4SJohn Baldwin 	struct thread *td;
2368b149b51SJohn Baldwin 	u_int newsize, oldsize, wantsize;
237ea3fc8e4SJohn Baldwin 	int error;
238ea3fc8e4SJohn Baldwin 
239ea3fc8e4SJohn Baldwin 	/* Handle easy read-only case first to avoid warnings from GCC. */
240ea3fc8e4SJohn Baldwin 	if (!req->newptr) {
241ea3fc8e4SJohn Baldwin 		oldsize = ktr_requestpool;
2428b149b51SJohn Baldwin 		return (SYSCTL_OUT(req, &oldsize, sizeof(u_int)));
243ea3fc8e4SJohn Baldwin 	}
244ea3fc8e4SJohn Baldwin 
2458b149b51SJohn Baldwin 	error = SYSCTL_IN(req, &wantsize, sizeof(u_int));
246ea3fc8e4SJohn Baldwin 	if (error)
247ea3fc8e4SJohn Baldwin 		return (error);
248ea3fc8e4SJohn Baldwin 	td = curthread;
2492c255e9dSRobert Watson 	ktrace_enter(td);
250ea3fc8e4SJohn Baldwin 	oldsize = ktr_requestpool;
251b4c20e5eSDmitry Chagin 	newsize = ktrace_resize_pool(oldsize, wantsize);
2522c255e9dSRobert Watson 	ktrace_exit(td);
2538b149b51SJohn Baldwin 	error = SYSCTL_OUT(req, &oldsize, sizeof(u_int));
254ea3fc8e4SJohn Baldwin 	if (error)
255ea3fc8e4SJohn Baldwin 		return (error);
256a5896914SJoseph Koshy 	if (wantsize > oldsize && newsize < wantsize)
257ea3fc8e4SJohn Baldwin 		return (ENOSPC);
258ea3fc8e4SJohn Baldwin 	return (0);
259ea3fc8e4SJohn Baldwin }
2607029da5cSPawel Biernacki SYSCTL_PROC(_kern_ktrace, OID_AUTO, request_pool,
2617029da5cSPawel Biernacki     CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, &ktr_requestpool, 0,
2627029da5cSPawel Biernacki     sysctl_kern_ktrace_request_pool, "IU",
263a0c87b74SGavin Atkinson     "Pool buffer size for ktrace(1)");
264ea3fc8e4SJohn Baldwin 
2658b149b51SJohn Baldwin static u_int
266b4c20e5eSDmitry Chagin ktrace_resize_pool(u_int oldsize, u_int newsize)
267ea3fc8e4SJohn Baldwin {
268b4c20e5eSDmitry Chagin 	STAILQ_HEAD(, ktr_request) ktr_new;
269ea3fc8e4SJohn Baldwin 	struct ktr_request *req;
270a5896914SJoseph Koshy 	int bound;
271ea3fc8e4SJohn Baldwin 
272ea3fc8e4SJohn Baldwin 	print_message = 1;
273b4c20e5eSDmitry Chagin 	bound = newsize - oldsize;
274a5896914SJoseph Koshy 	if (bound == 0)
275a5896914SJoseph Koshy 		return (ktr_requestpool);
276b4c20e5eSDmitry Chagin 	if (bound < 0) {
277b4c20e5eSDmitry Chagin 		mtx_lock(&ktrace_mtx);
278ea3fc8e4SJohn Baldwin 		/* Shrink pool down to newsize if possible. */
279a5896914SJoseph Koshy 		while (bound++ < 0) {
280ea3fc8e4SJohn Baldwin 			req = STAILQ_FIRST(&ktr_free);
281ea3fc8e4SJohn Baldwin 			if (req == NULL)
282b4c20e5eSDmitry Chagin 				break;
283ea3fc8e4SJohn Baldwin 			STAILQ_REMOVE_HEAD(&ktr_free, ktr_list);
284ea3fc8e4SJohn Baldwin 			ktr_requestpool--;
285ea3fc8e4SJohn Baldwin 			free(req, M_KTRACE);
286ea3fc8e4SJohn Baldwin 		}
287b4c20e5eSDmitry Chagin 	} else {
288ea3fc8e4SJohn Baldwin 		/* Grow pool up to newsize. */
289b4c20e5eSDmitry Chagin 		STAILQ_INIT(&ktr_new);
290a5896914SJoseph Koshy 		while (bound-- > 0) {
291ea3fc8e4SJohn Baldwin 			req = malloc(sizeof(struct ktr_request), M_KTRACE,
2925c18bf9dSMark Johnston 			    M_WAITOK | M_ZERO);
293b4c20e5eSDmitry Chagin 			STAILQ_INSERT_HEAD(&ktr_new, req, ktr_list);
294ea3fc8e4SJohn Baldwin 		}
295b4c20e5eSDmitry Chagin 		mtx_lock(&ktrace_mtx);
296b4c20e5eSDmitry Chagin 		STAILQ_CONCAT(&ktr_free, &ktr_new);
297b4c20e5eSDmitry Chagin 		ktr_requestpool += (newsize - oldsize);
298b4c20e5eSDmitry Chagin 	}
299b4c20e5eSDmitry Chagin 	mtx_unlock(&ktrace_mtx);
300ea3fc8e4SJohn Baldwin 	return (ktr_requestpool);
301ea3fc8e4SJohn Baldwin }
302ea3fc8e4SJohn Baldwin 
3035ca4819dSJohn Baldwin /* ktr_getrequest() assumes that ktr_comm[] is the same size as td_name[]. */
3045ca4819dSJohn Baldwin CTASSERT(sizeof(((struct ktr_header *)NULL)->ktr_comm) ==
3055ca4819dSJohn Baldwin     (sizeof((struct thread *)NULL)->td_name));
3065ca4819dSJohn Baldwin 
307ea3fc8e4SJohn Baldwin static struct ktr_request *
30822ec0406SDmitry Chagin ktr_getrequest_entered(struct thread *td, int type)
309ea3fc8e4SJohn Baldwin {
310ea3fc8e4SJohn Baldwin 	struct ktr_request *req;
311ea3fc8e4SJohn Baldwin 	struct proc *p = td->td_proc;
312ea3fc8e4SJohn Baldwin 	int pm;
313ea3fc8e4SJohn Baldwin 
314c5c9bd5bSRobert Watson 	mtx_lock(&ktrace_mtx);
315ea3fc8e4SJohn Baldwin 	if (!KTRCHECK(td, type)) {
316c5c9bd5bSRobert Watson 		mtx_unlock(&ktrace_mtx);
317ea3fc8e4SJohn Baldwin 		return (NULL);
318ea3fc8e4SJohn Baldwin 	}
319ea3fc8e4SJohn Baldwin 	req = STAILQ_FIRST(&ktr_free);
320ea3fc8e4SJohn Baldwin 	if (req != NULL) {
321ea3fc8e4SJohn Baldwin 		STAILQ_REMOVE_HEAD(&ktr_free, ktr_list);
322ea3fc8e4SJohn Baldwin 		req->ktr_header.ktr_type = type;
32375768576SJohn Baldwin 		if (p->p_traceflag & KTRFAC_DROP) {
32475768576SJohn Baldwin 			req->ktr_header.ktr_type |= KTR_DROP;
32575768576SJohn Baldwin 			p->p_traceflag &= ~KTRFAC_DROP;
32675768576SJohn Baldwin 		}
327c5c9bd5bSRobert Watson 		mtx_unlock(&ktrace_mtx);
328fc90f3a2SDmitry Chagin 		nanotime(&req->ktr_header.ktr_time);
329fc90f3a2SDmitry Chagin 		req->ktr_header.ktr_type |= KTR_VERSIONED;
330ea3fc8e4SJohn Baldwin 		req->ktr_header.ktr_pid = p->p_pid;
3312bdeb3f9SRobert Watson 		req->ktr_header.ktr_tid = td->td_tid;
332fc90f3a2SDmitry Chagin 		req->ktr_header.ktr_cpu = PCPU_GET(cpuid);
333fc90f3a2SDmitry Chagin 		req->ktr_header.ktr_version = KTR_VERSION1;
3345ca4819dSJohn Baldwin 		bcopy(td->td_name, req->ktr_header.ktr_comm,
3355ca4819dSJohn Baldwin 		    sizeof(req->ktr_header.ktr_comm));
336d977a583SRobert Watson 		req->ktr_buffer = NULL;
337ea3fc8e4SJohn Baldwin 		req->ktr_header.ktr_len = 0;
338ea3fc8e4SJohn Baldwin 	} else {
33975768576SJohn Baldwin 		p->p_traceflag |= KTRFAC_DROP;
340ea3fc8e4SJohn Baldwin 		pm = print_message;
341ea3fc8e4SJohn Baldwin 		print_message = 0;
342ea3fc8e4SJohn Baldwin 		mtx_unlock(&ktrace_mtx);
343ea3fc8e4SJohn Baldwin 		if (pm)
344ea3fc8e4SJohn Baldwin 			printf("Out of ktrace request objects.\n");
345ea3fc8e4SJohn Baldwin 	}
346ea3fc8e4SJohn Baldwin 	return (req);
347ea3fc8e4SJohn Baldwin }
348ea3fc8e4SJohn Baldwin 
3497705d4b2SDmitry Chagin static struct ktr_request *
3507705d4b2SDmitry Chagin ktr_getrequest(int type)
3517705d4b2SDmitry Chagin {
3527705d4b2SDmitry Chagin 	struct thread *td = curthread;
3537705d4b2SDmitry Chagin 	struct ktr_request *req;
3547705d4b2SDmitry Chagin 
3557705d4b2SDmitry Chagin 	ktrace_enter(td);
35622ec0406SDmitry Chagin 	req = ktr_getrequest_entered(td, type);
3577705d4b2SDmitry Chagin 	if (req == NULL)
3587705d4b2SDmitry Chagin 		ktrace_exit(td);
3597705d4b2SDmitry Chagin 
3607705d4b2SDmitry Chagin 	return (req);
3617705d4b2SDmitry Chagin }
3627705d4b2SDmitry Chagin 
3632c255e9dSRobert Watson /*
3642c255e9dSRobert Watson  * Some trace generation environments don't permit direct access to VFS,
3652c255e9dSRobert Watson  * such as during a context switch where sleeping is not allowed.  Under these
3662c255e9dSRobert Watson  * circumstances, queue a request to the thread to be written asynchronously
3672c255e9dSRobert Watson  * later.
3682c255e9dSRobert Watson  */
369ea3fc8e4SJohn Baldwin static void
3702c255e9dSRobert Watson ktr_enqueuerequest(struct thread *td, struct ktr_request *req)
371ea3fc8e4SJohn Baldwin {
372ea3fc8e4SJohn Baldwin 
373ea3fc8e4SJohn Baldwin 	mtx_lock(&ktrace_mtx);
3742c255e9dSRobert Watson 	STAILQ_INSERT_TAIL(&td->td_proc->p_ktr, req, ktr_list);
375ea3fc8e4SJohn Baldwin 	mtx_unlock(&ktrace_mtx);
376c6d31b83SKonstantin Belousov 	ast_sched(td, TDA_KTRACE);
3772c255e9dSRobert Watson }
3782c255e9dSRobert Watson 
3792c255e9dSRobert Watson /*
3802c255e9dSRobert Watson  * Drain any pending ktrace records from the per-thread queue to disk.  This
3812c255e9dSRobert Watson  * is used both internally before committing other records, and also on
3822c255e9dSRobert Watson  * system call return.  We drain all the ones we can find at the time when
3832c255e9dSRobert Watson  * drain is requested, but don't keep draining after that as those events
384a56be37eSJohn Baldwin  * may be approximately "after" the current event.
3852c255e9dSRobert Watson  */
3862c255e9dSRobert Watson static void
3872c255e9dSRobert Watson ktr_drain(struct thread *td)
3882c255e9dSRobert Watson {
3892c255e9dSRobert Watson 	struct ktr_request *queued_req;
3902c255e9dSRobert Watson 	STAILQ_HEAD(, ktr_request) local_queue;
3912c255e9dSRobert Watson 
3922c255e9dSRobert Watson 	ktrace_assert(td);
3932c255e9dSRobert Watson 	sx_assert(&ktrace_sx, SX_XLOCKED);
3942c255e9dSRobert Watson 
3952b3fb615SJohn Baldwin 	STAILQ_INIT(&local_queue);
3962c255e9dSRobert Watson 
3972c255e9dSRobert Watson 	if (!STAILQ_EMPTY(&td->td_proc->p_ktr)) {
3982c255e9dSRobert Watson 		mtx_lock(&ktrace_mtx);
3992c255e9dSRobert Watson 		STAILQ_CONCAT(&local_queue, &td->td_proc->p_ktr);
4002c255e9dSRobert Watson 		mtx_unlock(&ktrace_mtx);
4012c255e9dSRobert Watson 
4022c255e9dSRobert Watson 		while ((queued_req = STAILQ_FIRST(&local_queue))) {
4032c255e9dSRobert Watson 			STAILQ_REMOVE_HEAD(&local_queue, ktr_list);
4042c255e9dSRobert Watson 			ktr_writerequest(td, queued_req);
4052c255e9dSRobert Watson 			ktr_freerequest(queued_req);
4062c255e9dSRobert Watson 		}
4072c255e9dSRobert Watson 	}
4082c255e9dSRobert Watson }
4092c255e9dSRobert Watson 
4102c255e9dSRobert Watson /*
4112c255e9dSRobert Watson  * Submit a trace record for immediate commit to disk -- to be used only
4122c255e9dSRobert Watson  * where entering VFS is OK.  First drain any pending records that may have
4132c255e9dSRobert Watson  * been cached in the thread.
4142c255e9dSRobert Watson  */
4152c255e9dSRobert Watson static void
41622ec0406SDmitry Chagin ktr_submitrequest(struct thread *td, struct ktr_request *req)
4172c255e9dSRobert Watson {
4182c255e9dSRobert Watson 
4192c255e9dSRobert Watson 	ktrace_assert(td);
4202c255e9dSRobert Watson 
4212c255e9dSRobert Watson 	sx_xlock(&ktrace_sx);
4222c255e9dSRobert Watson 	ktr_drain(td);
4232c255e9dSRobert Watson 	ktr_writerequest(td, req);
4242c255e9dSRobert Watson 	ktr_freerequest(req);
4252c255e9dSRobert Watson 	sx_xunlock(&ktrace_sx);
4262c255e9dSRobert Watson 	ktrace_exit(td);
427ea3fc8e4SJohn Baldwin }
428ea3fc8e4SJohn Baldwin 
429ea3fc8e4SJohn Baldwin static void
430ea3fc8e4SJohn Baldwin ktr_freerequest(struct ktr_request *req)
431ea3fc8e4SJohn Baldwin {
432ea3fc8e4SJohn Baldwin 
433d680caabSJohn Baldwin 	mtx_lock(&ktrace_mtx);
434d680caabSJohn Baldwin 	ktr_freerequest_locked(req);
435d680caabSJohn Baldwin 	mtx_unlock(&ktrace_mtx);
436d680caabSJohn Baldwin }
437d680caabSJohn Baldwin 
438d680caabSJohn Baldwin static void
439d680caabSJohn Baldwin ktr_freerequest_locked(struct ktr_request *req)
440d680caabSJohn Baldwin {
441d680caabSJohn Baldwin 
442d680caabSJohn Baldwin 	mtx_assert(&ktrace_mtx, MA_OWNED);
443d977a583SRobert Watson 	if (req->ktr_buffer != NULL)
444d977a583SRobert Watson 		free(req->ktr_buffer, M_KTRACE);
445ea3fc8e4SJohn Baldwin 	STAILQ_INSERT_HEAD(&ktr_free, req, ktr_list);
446d680caabSJohn Baldwin }
447d680caabSJohn Baldwin 
4481762f674SKonstantin Belousov static void
4491762f674SKonstantin Belousov ktr_io_params_ref(struct ktr_io_params *kiop)
4501762f674SKonstantin Belousov {
4511762f674SKonstantin Belousov 	mtx_assert(&ktrace_mtx, MA_OWNED);
4521762f674SKonstantin Belousov 	kiop->refs++;
4531762f674SKonstantin Belousov }
4541762f674SKonstantin Belousov 
4551762f674SKonstantin Belousov static struct ktr_io_params *
4561762f674SKonstantin Belousov ktr_io_params_rele(struct ktr_io_params *kiop)
4571762f674SKonstantin Belousov {
4581762f674SKonstantin Belousov 	mtx_assert(&ktrace_mtx, MA_OWNED);
4591762f674SKonstantin Belousov 	if (kiop == NULL)
4601762f674SKonstantin Belousov 		return (NULL);
4611762f674SKonstantin Belousov 	KASSERT(kiop->refs > 0, ("kiop ref == 0 %p", kiop));
4621762f674SKonstantin Belousov 	return (--(kiop->refs) == 0 ? kiop : NULL);
4631762f674SKonstantin Belousov }
4641762f674SKonstantin Belousov 
4651762f674SKonstantin Belousov void
4661762f674SKonstantin Belousov ktr_io_params_free(struct ktr_io_params *kiop)
4671762f674SKonstantin Belousov {
4681762f674SKonstantin Belousov 	if (kiop == NULL)
4691762f674SKonstantin Belousov 		return;
4701762f674SKonstantin Belousov 
4711762f674SKonstantin Belousov 	MPASS(kiop->refs == 0);
4721762f674SKonstantin Belousov 	vn_close(kiop->vp, FWRITE, kiop->cr, curthread);
4731762f674SKonstantin Belousov 	crfree(kiop->cr);
4741762f674SKonstantin Belousov 	free(kiop, M_KTRACE);
4751762f674SKonstantin Belousov }
4761762f674SKonstantin Belousov 
4771762f674SKonstantin Belousov static struct ktr_io_params *
4781762f674SKonstantin Belousov ktr_io_params_alloc(struct thread *td, struct vnode *vp)
4791762f674SKonstantin Belousov {
4801762f674SKonstantin Belousov 	struct ktr_io_params *res;
4811762f674SKonstantin Belousov 
4821762f674SKonstantin Belousov 	res = malloc(sizeof(struct ktr_io_params), M_KTRACE, M_WAITOK);
4831762f674SKonstantin Belousov 	res->vp = vp;
4841762f674SKonstantin Belousov 	res->cr = crhold(td->td_ucred);
48502645b88SKonstantin Belousov 	res->lim = lim_cur(td, RLIMIT_FSIZE);
4861762f674SKonstantin Belousov 	res->refs = 1;
4871762f674SKonstantin Belousov 	return (res);
4881762f674SKonstantin Belousov }
4891762f674SKonstantin Belousov 
490d680caabSJohn Baldwin /*
491d680caabSJohn Baldwin  * Disable tracing for a process and release all associated resources.
492d680caabSJohn Baldwin  * The caller is responsible for releasing a reference on the returned
493d680caabSJohn Baldwin  * vnode and credentials.
494d680caabSJohn Baldwin  */
4951762f674SKonstantin Belousov static struct ktr_io_params *
4961762f674SKonstantin Belousov ktr_freeproc(struct proc *p)
497d680caabSJohn Baldwin {
4981762f674SKonstantin Belousov 	struct ktr_io_params *kiop;
499d680caabSJohn Baldwin 	struct ktr_request *req;
500d680caabSJohn Baldwin 
501d680caabSJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
502d680caabSJohn Baldwin 	mtx_assert(&ktrace_mtx, MA_OWNED);
5031762f674SKonstantin Belousov 	kiop = ktr_io_params_rele(p->p_ktrioparms);
5041762f674SKonstantin Belousov 	p->p_ktrioparms = NULL;
505d680caabSJohn Baldwin 	p->p_traceflag = 0;
506d680caabSJohn Baldwin 	while ((req = STAILQ_FIRST(&p->p_ktr)) != NULL) {
507d680caabSJohn Baldwin 		STAILQ_REMOVE_HEAD(&p->p_ktr, ktr_list);
508d680caabSJohn Baldwin 		ktr_freerequest_locked(req);
509d680caabSJohn Baldwin 	}
5101762f674SKonstantin Belousov 	return (kiop);
5111762f674SKonstantin Belousov }
5121762f674SKonstantin Belousov 
5131762f674SKonstantin Belousov struct vnode *
5141762f674SKonstantin Belousov ktr_get_tracevp(struct proc *p, bool ref)
5151762f674SKonstantin Belousov {
5161762f674SKonstantin Belousov 	struct vnode *vp;
5171762f674SKonstantin Belousov 
5181762f674SKonstantin Belousov 	PROC_LOCK_ASSERT(p, MA_OWNED);
5191762f674SKonstantin Belousov 
5201762f674SKonstantin Belousov 	if (p->p_ktrioparms != NULL) {
5211762f674SKonstantin Belousov 		vp = p->p_ktrioparms->vp;
5221762f674SKonstantin Belousov 		if (ref)
5231762f674SKonstantin Belousov 			vrefact(vp);
5241762f674SKonstantin Belousov 	} else {
5251762f674SKonstantin Belousov 		vp = NULL;
5261762f674SKonstantin Belousov 	}
5271762f674SKonstantin Belousov 	return (vp);
528ea3fc8e4SJohn Baldwin }
529ea3fc8e4SJohn Baldwin 
53026f9a767SRodney W. Grimes void
531b1ad6a90SBrooks Davis ktrsyscall(int code, int narg, syscallarg_t args[])
532df8bae1dSRodney W. Grimes {
533ea3fc8e4SJohn Baldwin 	struct ktr_request *req;
534df8bae1dSRodney W. Grimes 	struct ktr_syscall *ktp;
535ea3fc8e4SJohn Baldwin 	size_t buflen;
5364b3aac3dSJohn Baldwin 	char *buf = NULL;
537df8bae1dSRodney W. Grimes 
538ad738f37SMatt Macy 	if (__predict_false(curthread->td_pflags & TDP_INKTRACE))
539ad738f37SMatt Macy 		return;
540ad738f37SMatt Macy 
5414b3aac3dSJohn Baldwin 	buflen = sizeof(register_t) * narg;
5424b3aac3dSJohn Baldwin 	if (buflen > 0) {
543a163d034SWarner Losh 		buf = malloc(buflen, M_KTRACE, M_WAITOK);
5444b3aac3dSJohn Baldwin 		bcopy(args, buf, buflen);
5454b3aac3dSJohn Baldwin 	}
546ea3fc8e4SJohn Baldwin 	req = ktr_getrequest(KTR_SYSCALL);
54750c22331SPoul-Henning Kamp 	if (req == NULL) {
54850c22331SPoul-Henning Kamp 		if (buf != NULL)
54950c22331SPoul-Henning Kamp 			free(buf, M_KTRACE);
550ea3fc8e4SJohn Baldwin 		return;
55150c22331SPoul-Henning Kamp 	}
552ea3fc8e4SJohn Baldwin 	ktp = &req->ktr_data.ktr_syscall;
553df8bae1dSRodney W. Grimes 	ktp->ktr_code = code;
554df8bae1dSRodney W. Grimes 	ktp->ktr_narg = narg;
555ea3fc8e4SJohn Baldwin 	if (buflen > 0) {
556ea3fc8e4SJohn Baldwin 		req->ktr_header.ktr_len = buflen;
557d977a583SRobert Watson 		req->ktr_buffer = buf;
558ea3fc8e4SJohn Baldwin 	}
5592c255e9dSRobert Watson 	ktr_submitrequest(curthread, req);
560df8bae1dSRodney W. Grimes }
561df8bae1dSRodney W. Grimes 
56226f9a767SRodney W. Grimes void
563039644ecSEd Maste ktrsysret(int code, int error, register_t retval)
564df8bae1dSRodney W. Grimes {
565ea3fc8e4SJohn Baldwin 	struct ktr_request *req;
566ea3fc8e4SJohn Baldwin 	struct ktr_sysret *ktp;
567df8bae1dSRodney W. Grimes 
568ad738f37SMatt Macy 	if (__predict_false(curthread->td_pflags & TDP_INKTRACE))
569ad738f37SMatt Macy 		return;
570ad738f37SMatt Macy 
571ea3fc8e4SJohn Baldwin 	req = ktr_getrequest(KTR_SYSRET);
572ea3fc8e4SJohn Baldwin 	if (req == NULL)
573ea3fc8e4SJohn Baldwin 		return;
574ea3fc8e4SJohn Baldwin 	ktp = &req->ktr_data.ktr_sysret;
575ea3fc8e4SJohn Baldwin 	ktp->ktr_code = code;
576ea3fc8e4SJohn Baldwin 	ktp->ktr_error = error;
5775a01b726SEitan Adler 	ktp->ktr_retval = ((error == 0) ? retval: 0);		/* what about val2 ? */
5782c255e9dSRobert Watson 	ktr_submitrequest(curthread, req);
5792c255e9dSRobert Watson }
5802c255e9dSRobert Watson 
5812c255e9dSRobert Watson /*
582d680caabSJohn Baldwin  * When a setuid process execs, disable tracing.
583d680caabSJohn Baldwin  *
584d680caabSJohn Baldwin  * XXX: We toss any pending asynchronous records.
585d680caabSJohn Baldwin  */
5861762f674SKonstantin Belousov struct ktr_io_params *
5871762f674SKonstantin Belousov ktrprocexec(struct proc *p)
588d680caabSJohn Baldwin {
5891762f674SKonstantin Belousov 	struct ktr_io_params *kiop;
590d680caabSJohn Baldwin 
591d680caabSJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
5921762f674SKonstantin Belousov 
5931762f674SKonstantin Belousov 	kiop = p->p_ktrioparms;
594*166b7573SMark Johnston 	if (kiop == NULL || priv_check_cred(kiop->cr, PRIV_DEBUG_DIFFCRED) == 0)
5951762f674SKonstantin Belousov 		return (NULL);
5961762f674SKonstantin Belousov 
597d680caabSJohn Baldwin 	mtx_lock(&ktrace_mtx);
5981762f674SKonstantin Belousov 	kiop = ktr_freeproc(p);
599d680caabSJohn Baldwin 	mtx_unlock(&ktrace_mtx);
6001762f674SKonstantin Belousov 	return (kiop);
601d680caabSJohn Baldwin }
602d680caabSJohn Baldwin 
603d680caabSJohn Baldwin /*
604d680caabSJohn Baldwin  * When a process exits, drain per-process asynchronous trace records
605d680caabSJohn Baldwin  * and disable tracing.
6062c255e9dSRobert Watson  */
6072c255e9dSRobert Watson void
6082c255e9dSRobert Watson ktrprocexit(struct thread *td)
6092c255e9dSRobert Watson {
6107705d4b2SDmitry Chagin 	struct ktr_request *req;
611d680caabSJohn Baldwin 	struct proc *p;
6121762f674SKonstantin Belousov 	struct ktr_io_params *kiop;
613d680caabSJohn Baldwin 
614d680caabSJohn Baldwin 	p = td->td_proc;
615d680caabSJohn Baldwin 	if (p->p_traceflag == 0)
616d680caabSJohn Baldwin 		return;
6172c255e9dSRobert Watson 
6182c255e9dSRobert Watson 	ktrace_enter(td);
61922ec0406SDmitry Chagin 	req = ktr_getrequest_entered(td, KTR_PROCDTOR);
62022ec0406SDmitry Chagin 	if (req != NULL)
62122ec0406SDmitry Chagin 		ktr_enqueuerequest(td, req);
6222c255e9dSRobert Watson 	sx_xlock(&ktrace_sx);
6232c255e9dSRobert Watson 	ktr_drain(td);
6242c255e9dSRobert Watson 	sx_xunlock(&ktrace_sx);
625d680caabSJohn Baldwin 	PROC_LOCK(p);
626d680caabSJohn Baldwin 	mtx_lock(&ktrace_mtx);
6271762f674SKonstantin Belousov 	kiop = ktr_freeproc(p);
628d680caabSJohn Baldwin 	mtx_unlock(&ktrace_mtx);
629d680caabSJohn Baldwin 	PROC_UNLOCK(p);
6301762f674SKonstantin Belousov 	ktr_io_params_free(kiop);
6312c255e9dSRobert Watson 	ktrace_exit(td);
6322c255e9dSRobert Watson }
6332c255e9dSRobert Watson 
6347705d4b2SDmitry Chagin static void
63522ec0406SDmitry Chagin ktrprocctor_entered(struct thread *td, struct proc *p)
6367705d4b2SDmitry Chagin {
6377705d4b2SDmitry Chagin 	struct ktr_proc_ctor *ktp;
6387705d4b2SDmitry Chagin 	struct ktr_request *req;
639de60a5f3SDmitry Chagin 	struct thread *td2;
6407705d4b2SDmitry Chagin 
6417705d4b2SDmitry Chagin 	ktrace_assert(td);
6427705d4b2SDmitry Chagin 	td2 = FIRST_THREAD_IN_PROC(p);
64322ec0406SDmitry Chagin 	req = ktr_getrequest_entered(td2, KTR_PROCCTOR);
6447705d4b2SDmitry Chagin 	if (req == NULL)
6457705d4b2SDmitry Chagin 		return;
6467705d4b2SDmitry Chagin 	ktp = &req->ktr_data.ktr_proc_ctor;
6477705d4b2SDmitry Chagin 	ktp->sv_flags = p->p_sysent->sv_flags;
64822ec0406SDmitry Chagin 	ktr_enqueuerequest(td2, req);
6497705d4b2SDmitry Chagin }
6507705d4b2SDmitry Chagin 
6517705d4b2SDmitry Chagin void
6527705d4b2SDmitry Chagin ktrprocctor(struct proc *p)
6537705d4b2SDmitry Chagin {
6547705d4b2SDmitry Chagin 	struct thread *td = curthread;
6557705d4b2SDmitry Chagin 
6567705d4b2SDmitry Chagin 	if ((p->p_traceflag & KTRFAC_MASK) == 0)
6577705d4b2SDmitry Chagin 		return;
6587705d4b2SDmitry Chagin 
6597705d4b2SDmitry Chagin 	ktrace_enter(td);
66022ec0406SDmitry Chagin 	ktrprocctor_entered(td, p);
6617705d4b2SDmitry Chagin 	ktrace_exit(td);
6627705d4b2SDmitry Chagin }
6637705d4b2SDmitry Chagin 
6642c255e9dSRobert Watson /*
665d680caabSJohn Baldwin  * When a process forks, enable tracing in the new process if needed.
666d680caabSJohn Baldwin  */
667d680caabSJohn Baldwin void
668d680caabSJohn Baldwin ktrprocfork(struct proc *p1, struct proc *p2)
669d680caabSJohn Baldwin {
670d680caabSJohn Baldwin 
6711762f674SKonstantin Belousov 	MPASS(p2->p_ktrioparms == NULL);
6727c34b35bSMateusz Guzik 	MPASS(p2->p_traceflag == 0);
6737c34b35bSMateusz Guzik 
6747c34b35bSMateusz Guzik 	if (p1->p_traceflag == 0)
6757c34b35bSMateusz Guzik 		return;
6767c34b35bSMateusz Guzik 
6777705d4b2SDmitry Chagin 	PROC_LOCK(p1);
678d680caabSJohn Baldwin 	mtx_lock(&ktrace_mtx);
679d680caabSJohn Baldwin 	if (p1->p_traceflag & KTRFAC_INHERIT) {
680d680caabSJohn Baldwin 		p2->p_traceflag = p1->p_traceflag;
6811762f674SKonstantin Belousov 		if ((p2->p_ktrioparms = p1->p_ktrioparms) != NULL)
6821762f674SKonstantin Belousov 			p1->p_ktrioparms->refs++;
683d680caabSJohn Baldwin 	}
684d680caabSJohn Baldwin 	mtx_unlock(&ktrace_mtx);
6857705d4b2SDmitry Chagin 	PROC_UNLOCK(p1);
6867705d4b2SDmitry Chagin 
6877705d4b2SDmitry Chagin 	ktrprocctor(p2);
688d680caabSJohn Baldwin }
689d680caabSJohn Baldwin 
690d680caabSJohn Baldwin /*
6912c255e9dSRobert Watson  * When a thread returns, drain any asynchronous records generated by the
6922c255e9dSRobert Watson  * system call.
6932c255e9dSRobert Watson  */
6942c255e9dSRobert Watson void
6952c255e9dSRobert Watson ktruserret(struct thread *td)
6962c255e9dSRobert Watson {
6972c255e9dSRobert Watson 
6982c255e9dSRobert Watson 	ktrace_enter(td);
6992c255e9dSRobert Watson 	sx_xlock(&ktrace_sx);
7002c255e9dSRobert Watson 	ktr_drain(td);
7012c255e9dSRobert Watson 	sx_xunlock(&ktrace_sx);
7022c255e9dSRobert Watson 	ktrace_exit(td);
703df8bae1dSRodney W. Grimes }
704df8bae1dSRodney W. Grimes 
70526f9a767SRodney W. Grimes void
706e4b16f2fSMark Johnston ktrnamei(const char *path)
707df8bae1dSRodney W. Grimes {
708ea3fc8e4SJohn Baldwin 	struct ktr_request *req;
709ea3fc8e4SJohn Baldwin 	int namelen;
7104b3aac3dSJohn Baldwin 	char *buf = NULL;
711df8bae1dSRodney W. Grimes 
7124b3aac3dSJohn Baldwin 	namelen = strlen(path);
7134b3aac3dSJohn Baldwin 	if (namelen > 0) {
714a163d034SWarner Losh 		buf = malloc(namelen, M_KTRACE, M_WAITOK);
7154b3aac3dSJohn Baldwin 		bcopy(path, buf, namelen);
7164b3aac3dSJohn Baldwin 	}
717ea3fc8e4SJohn Baldwin 	req = ktr_getrequest(KTR_NAMEI);
71850c22331SPoul-Henning Kamp 	if (req == NULL) {
71950c22331SPoul-Henning Kamp 		if (buf != NULL)
72050c22331SPoul-Henning Kamp 			free(buf, M_KTRACE);
721ea3fc8e4SJohn Baldwin 		return;
72250c22331SPoul-Henning Kamp 	}
723ea3fc8e4SJohn Baldwin 	if (namelen > 0) {
724ea3fc8e4SJohn Baldwin 		req->ktr_header.ktr_len = namelen;
725d977a583SRobert Watson 		req->ktr_buffer = buf;
726ea3fc8e4SJohn Baldwin 	}
7272c255e9dSRobert Watson 	ktr_submitrequest(curthread, req);
728df8bae1dSRodney W. Grimes }
729df8bae1dSRodney W. Grimes 
73026f9a767SRodney W. Grimes void
731039644ecSEd Maste ktrsysctl(int *name, u_int namelen)
732a56be37eSJohn Baldwin {
733a56be37eSJohn Baldwin 	struct ktr_request *req;
734a56be37eSJohn Baldwin 	u_int mib[CTL_MAXNAME + 2];
735a56be37eSJohn Baldwin 	char *mibname;
736a56be37eSJohn Baldwin 	size_t mibnamelen;
737a56be37eSJohn Baldwin 	int error;
738a56be37eSJohn Baldwin 
739a56be37eSJohn Baldwin 	/* Lookup name of mib. */
740a56be37eSJohn Baldwin 	KASSERT(namelen <= CTL_MAXNAME, ("sysctl MIB too long"));
741a56be37eSJohn Baldwin 	mib[0] = 0;
742a56be37eSJohn Baldwin 	mib[1] = 1;
743a56be37eSJohn Baldwin 	bcopy(name, mib + 2, namelen * sizeof(*name));
744a56be37eSJohn Baldwin 	mibnamelen = 128;
745a56be37eSJohn Baldwin 	mibname = malloc(mibnamelen, M_KTRACE, M_WAITOK);
746a56be37eSJohn Baldwin 	error = kernel_sysctl(curthread, mib, namelen + 2, mibname, &mibnamelen,
747a56be37eSJohn Baldwin 	    NULL, 0, &mibnamelen, 0);
748a56be37eSJohn Baldwin 	if (error) {
749a56be37eSJohn Baldwin 		free(mibname, M_KTRACE);
750a56be37eSJohn Baldwin 		return;
751a56be37eSJohn Baldwin 	}
752a56be37eSJohn Baldwin 	req = ktr_getrequest(KTR_SYSCTL);
753a56be37eSJohn Baldwin 	if (req == NULL) {
754a56be37eSJohn Baldwin 		free(mibname, M_KTRACE);
755a56be37eSJohn Baldwin 		return;
756a56be37eSJohn Baldwin 	}
757a56be37eSJohn Baldwin 	req->ktr_header.ktr_len = mibnamelen;
758a56be37eSJohn Baldwin 	req->ktr_buffer = mibname;
759a56be37eSJohn Baldwin 	ktr_submitrequest(curthread, req);
760a56be37eSJohn Baldwin }
761a56be37eSJohn Baldwin 
762a56be37eSJohn Baldwin void
763039644ecSEd Maste ktrgenio(int fd, enum uio_rw rw, struct uio *uio, int error)
764df8bae1dSRodney W. Grimes {
765ea3fc8e4SJohn Baldwin 	struct ktr_request *req;
766ea3fc8e4SJohn Baldwin 	struct ktr_genio *ktg;
767b92584a6SJohn Baldwin 	int datalen;
768b92584a6SJohn Baldwin 	char *buf;
769df8bae1dSRodney W. Grimes 
77047ad4f2dSKyle Evans 	if (error != 0 && (rw == UIO_READ || error == EFAULT)) {
77161cc4830SAlfredo Mazzinghi 		freeuio(uio);
772df8bae1dSRodney W. Grimes 		return;
773552afd9cSPoul-Henning Kamp 	}
774b92584a6SJohn Baldwin 	uio->uio_offset = 0;
775b92584a6SJohn Baldwin 	uio->uio_rw = UIO_WRITE;
776526d0bd5SKonstantin Belousov 	datalen = MIN(uio->uio_resid, ktr_geniosize);
777a163d034SWarner Losh 	buf = malloc(datalen, M_KTRACE, M_WAITOK);
778552afd9cSPoul-Henning Kamp 	error = uiomove(buf, datalen, uio);
77961cc4830SAlfredo Mazzinghi 	freeuio(uio);
780552afd9cSPoul-Henning Kamp 	if (error) {
781b92584a6SJohn Baldwin 		free(buf, M_KTRACE);
782ea3fc8e4SJohn Baldwin 		return;
783b92584a6SJohn Baldwin 	}
784b92584a6SJohn Baldwin 	req = ktr_getrequest(KTR_GENIO);
785b92584a6SJohn Baldwin 	if (req == NULL) {
786b92584a6SJohn Baldwin 		free(buf, M_KTRACE);
787b92584a6SJohn Baldwin 		return;
788b92584a6SJohn Baldwin 	}
789ea3fc8e4SJohn Baldwin 	ktg = &req->ktr_data.ktr_genio;
790ea3fc8e4SJohn Baldwin 	ktg->ktr_fd = fd;
791ea3fc8e4SJohn Baldwin 	ktg->ktr_rw = rw;
792b92584a6SJohn Baldwin 	req->ktr_header.ktr_len = datalen;
793d977a583SRobert Watson 	req->ktr_buffer = buf;
7942c255e9dSRobert Watson 	ktr_submitrequest(curthread, req);
795df8bae1dSRodney W. Grimes }
796df8bae1dSRodney W. Grimes 
79726f9a767SRodney W. Grimes void
798039644ecSEd Maste ktrpsig(int sig, sig_t action, sigset_t *mask, int code)
799df8bae1dSRodney W. Grimes {
80022ec0406SDmitry Chagin 	struct thread *td = curthread;
801ea3fc8e4SJohn Baldwin 	struct ktr_request *req;
802ea3fc8e4SJohn Baldwin 	struct ktr_psig	*kp;
803df8bae1dSRodney W. Grimes 
804ea3fc8e4SJohn Baldwin 	req = ktr_getrequest(KTR_PSIG);
805ea3fc8e4SJohn Baldwin 	if (req == NULL)
806ea3fc8e4SJohn Baldwin 		return;
807ea3fc8e4SJohn Baldwin 	kp = &req->ktr_data.ktr_psig;
808ea3fc8e4SJohn Baldwin 	kp->signo = (char)sig;
809ea3fc8e4SJohn Baldwin 	kp->action = action;
810ea3fc8e4SJohn Baldwin 	kp->mask = *mask;
811ea3fc8e4SJohn Baldwin 	kp->code = code;
81222ec0406SDmitry Chagin 	ktr_enqueuerequest(td, req);
81322ec0406SDmitry Chagin 	ktrace_exit(td);
814df8bae1dSRodney W. Grimes }
815df8bae1dSRodney W. Grimes 
81626f9a767SRodney W. Grimes void
817039644ecSEd Maste ktrcsw(int out, int user, const char *wmesg)
818df8bae1dSRodney W. Grimes {
81922ec0406SDmitry Chagin 	struct thread *td = curthread;
820ea3fc8e4SJohn Baldwin 	struct ktr_request *req;
821ea3fc8e4SJohn Baldwin 	struct ktr_csw *kc;
822df8bae1dSRodney W. Grimes 
823ad738f37SMatt Macy 	if (__predict_false(curthread->td_pflags & TDP_INKTRACE))
824ad738f37SMatt Macy 		return;
825ad738f37SMatt Macy 
826ea3fc8e4SJohn Baldwin 	req = ktr_getrequest(KTR_CSW);
827ea3fc8e4SJohn Baldwin 	if (req == NULL)
828ea3fc8e4SJohn Baldwin 		return;
829ea3fc8e4SJohn Baldwin 	kc = &req->ktr_data.ktr_csw;
830ea3fc8e4SJohn Baldwin 	kc->out = out;
831ea3fc8e4SJohn Baldwin 	kc->user = user;
83288bf5036SJohn Baldwin 	if (wmesg != NULL)
83388bf5036SJohn Baldwin 		strlcpy(kc->wmesg, wmesg, sizeof(kc->wmesg));
83488bf5036SJohn Baldwin 	else
83588bf5036SJohn Baldwin 		bzero(kc->wmesg, sizeof(kc->wmesg));
83622ec0406SDmitry Chagin 	ktr_enqueuerequest(td, req);
83722ec0406SDmitry Chagin 	ktrace_exit(td);
838df8bae1dSRodney W. Grimes }
83960e15db9SDag-Erling Smørgrav 
84060e15db9SDag-Erling Smørgrav void
841ffb66079SJohn Baldwin ktrstruct(const char *name, const void *data, size_t datalen)
84260e15db9SDag-Erling Smørgrav {
84360e15db9SDag-Erling Smørgrav 	struct ktr_request *req;
8444dd3a21fSMateusz Guzik 	char *buf;
8454dd3a21fSMateusz Guzik 	size_t buflen, namelen;
84660e15db9SDag-Erling Smørgrav 
847ad738f37SMatt Macy 	if (__predict_false(curthread->td_pflags & TDP_INKTRACE))
848ad738f37SMatt Macy 		return;
849ad738f37SMatt Macy 
8504dd3a21fSMateusz Guzik 	if (data == NULL)
85160e15db9SDag-Erling Smørgrav 		datalen = 0;
8524dd3a21fSMateusz Guzik 	namelen = strlen(name) + 1;
8534dd3a21fSMateusz Guzik 	buflen = namelen + datalen;
85460e15db9SDag-Erling Smørgrav 	buf = malloc(buflen, M_KTRACE, M_WAITOK);
855a3052d6eSJohn Baldwin 	strcpy(buf, name);
8564dd3a21fSMateusz Guzik 	bcopy(data, buf + namelen, datalen);
85760e15db9SDag-Erling Smørgrav 	if ((req = ktr_getrequest(KTR_STRUCT)) == NULL) {
85860e15db9SDag-Erling Smørgrav 		free(buf, M_KTRACE);
85960e15db9SDag-Erling Smørgrav 		return;
86060e15db9SDag-Erling Smørgrav 	}
86160e15db9SDag-Erling Smørgrav 	req->ktr_buffer = buf;
86260e15db9SDag-Erling Smørgrav 	req->ktr_header.ktr_len = buflen;
86360e15db9SDag-Erling Smørgrav 	ktr_submitrequest(curthread, req);
86460e15db9SDag-Erling Smørgrav }
865c601ad8eSDag-Erling Smørgrav 
866c601ad8eSDag-Erling Smørgrav void
8670a1427c5SMateusz Guzik ktrstruct_error(const char *name, const void *data, size_t datalen, int error)
8680a1427c5SMateusz Guzik {
8690a1427c5SMateusz Guzik 
8700a1427c5SMateusz Guzik 	if (error == 0)
8710a1427c5SMateusz Guzik 		ktrstruct(name, data, datalen);
8720a1427c5SMateusz Guzik }
8730a1427c5SMateusz Guzik 
8740a1427c5SMateusz Guzik void
875ffb66079SJohn Baldwin ktrstructarray(const char *name, enum uio_seg seg, const void *data,
876ffb66079SJohn Baldwin     int num_items, size_t struct_size)
877ffb66079SJohn Baldwin {
878ffb66079SJohn Baldwin 	struct ktr_request *req;
879ffb66079SJohn Baldwin 	struct ktr_struct_array *ksa;
880ffb66079SJohn Baldwin 	char *buf;
881ffb66079SJohn Baldwin 	size_t buflen, datalen, namelen;
882ffb66079SJohn Baldwin 	int max_items;
883ffb66079SJohn Baldwin 
884ad738f37SMatt Macy 	if (__predict_false(curthread->td_pflags & TDP_INKTRACE))
885ad738f37SMatt Macy 		return;
886f8851007SMark Johnston 	if (num_items < 0)
887f8851007SMark Johnston 		return;
888ad738f37SMatt Macy 
889ffb66079SJohn Baldwin 	/* Trim array length to genio size. */
890ffb66079SJohn Baldwin 	max_items = ktr_geniosize / struct_size;
891ffb66079SJohn Baldwin 	if (num_items > max_items) {
892ffb66079SJohn Baldwin 		if (max_items == 0)
893ffb66079SJohn Baldwin 			num_items = 1;
894ffb66079SJohn Baldwin 		else
895ffb66079SJohn Baldwin 			num_items = max_items;
896ffb66079SJohn Baldwin 	}
897ffb66079SJohn Baldwin 	datalen = num_items * struct_size;
898ffb66079SJohn Baldwin 
899ffb66079SJohn Baldwin 	if (data == NULL)
900ffb66079SJohn Baldwin 		datalen = 0;
901ffb66079SJohn Baldwin 
902ffb66079SJohn Baldwin 	namelen = strlen(name) + 1;
903ffb66079SJohn Baldwin 	buflen = namelen + datalen;
904ffb66079SJohn Baldwin 	buf = malloc(buflen, M_KTRACE, M_WAITOK);
905ffb66079SJohn Baldwin 	strcpy(buf, name);
906ffb66079SJohn Baldwin 	if (seg == UIO_SYSSPACE)
907ffb66079SJohn Baldwin 		bcopy(data, buf + namelen, datalen);
908ffb66079SJohn Baldwin 	else {
909ffb66079SJohn Baldwin 		if (copyin(data, buf + namelen, datalen) != 0) {
910ffb66079SJohn Baldwin 			free(buf, M_KTRACE);
911ffb66079SJohn Baldwin 			return;
912ffb66079SJohn Baldwin 		}
913ffb66079SJohn Baldwin 	}
914ffb66079SJohn Baldwin 	if ((req = ktr_getrequest(KTR_STRUCT_ARRAY)) == NULL) {
915ffb66079SJohn Baldwin 		free(buf, M_KTRACE);
916ffb66079SJohn Baldwin 		return;
917ffb66079SJohn Baldwin 	}
918ffb66079SJohn Baldwin 	ksa = &req->ktr_data.ktr_struct_array;
919ffb66079SJohn Baldwin 	ksa->struct_size = struct_size;
920ffb66079SJohn Baldwin 	req->ktr_buffer = buf;
921ffb66079SJohn Baldwin 	req->ktr_header.ktr_len = buflen;
922ffb66079SJohn Baldwin 	ktr_submitrequest(curthread, req);
923ffb66079SJohn Baldwin }
924ffb66079SJohn Baldwin 
925ffb66079SJohn Baldwin void
9269bec8413SJake Freeland ktrcapfail(enum ktr_cap_violation type, const void *data)
927c601ad8eSDag-Erling Smørgrav {
928c601ad8eSDag-Erling Smørgrav 	struct thread *td = curthread;
929c601ad8eSDag-Erling Smørgrav 	struct ktr_request *req;
930c601ad8eSDag-Erling Smørgrav 	struct ktr_cap_fail *kcf;
9319bec8413SJake Freeland 	union ktr_cap_data *kcd;
932c601ad8eSDag-Erling Smørgrav 
9339bec8413SJake Freeland 	if (__predict_false(td->td_pflags & TDP_INKTRACE))
9349bec8413SJake Freeland 		return;
9359bec8413SJake Freeland 	if (type != CAPFAIL_SYSCALL &&
9369bec8413SJake Freeland 	    (td->td_sa.callp->sy_flags & SYF_CAPENABLED) == 0)
937ad738f37SMatt Macy 		return;
938ad738f37SMatt Macy 
939c601ad8eSDag-Erling Smørgrav 	req = ktr_getrequest(KTR_CAPFAIL);
940c601ad8eSDag-Erling Smørgrav 	if (req == NULL)
941c601ad8eSDag-Erling Smørgrav 		return;
942c601ad8eSDag-Erling Smørgrav 	kcf = &req->ktr_data.ktr_cap_fail;
943e141be6fSDag-Erling Smørgrav 	kcf->cap_type = type;
9449bec8413SJake Freeland 	kcf->cap_code = td->td_sa.code;
9459bec8413SJake Freeland 	kcf->cap_svflags = td->td_proc->p_sysent->sv_flags;
9469bec8413SJake Freeland 	if (data != NULL) {
9479bec8413SJake Freeland 		kcd = &kcf->cap_data;
9489bec8413SJake Freeland 		switch (type) {
9499bec8413SJake Freeland 		case CAPFAIL_NOTCAPABLE:
9509bec8413SJake Freeland 		case CAPFAIL_INCREASE:
9519bec8413SJake Freeland 			kcd->cap_needed = *(const cap_rights_t *)data;
9529bec8413SJake Freeland 			kcd->cap_held = *((const cap_rights_t *)data + 1);
9539bec8413SJake Freeland 			break;
9549bec8413SJake Freeland 		case CAPFAIL_SYSCALL:
9559bec8413SJake Freeland 		case CAPFAIL_SIGNAL:
9569bec8413SJake Freeland 		case CAPFAIL_PROTO:
9579bec8413SJake Freeland 			kcd->cap_int = *(const int *)data;
9589bec8413SJake Freeland 			break;
9599bec8413SJake Freeland 		case CAPFAIL_SOCKADDR:
9609bec8413SJake Freeland 			kcd->cap_sockaddr = *(const struct sockaddr *)data;
9619bec8413SJake Freeland 			break;
9629bec8413SJake Freeland 		case CAPFAIL_NAMEI:
9639bec8413SJake Freeland 			strlcpy(kcd->cap_path, data, MAXPATHLEN);
9649bec8413SJake Freeland 			break;
9659bec8413SJake Freeland 		case CAPFAIL_CPUSET:
9669bec8413SJake Freeland 		default:
9679bec8413SJake Freeland 			break;
9689bec8413SJake Freeland 		}
9699bec8413SJake Freeland 	}
970c601ad8eSDag-Erling Smørgrav 	ktr_enqueuerequest(td, req);
971c601ad8eSDag-Erling Smørgrav 	ktrace_exit(td);
972c601ad8eSDag-Erling Smørgrav }
97335818d2eSJohn Baldwin 
97435818d2eSJohn Baldwin void
975039644ecSEd Maste ktrfault(vm_offset_t vaddr, int type)
97635818d2eSJohn Baldwin {
97735818d2eSJohn Baldwin 	struct thread *td = curthread;
97835818d2eSJohn Baldwin 	struct ktr_request *req;
97935818d2eSJohn Baldwin 	struct ktr_fault *kf;
98035818d2eSJohn Baldwin 
981ad738f37SMatt Macy 	if (__predict_false(curthread->td_pflags & TDP_INKTRACE))
982ad738f37SMatt Macy 		return;
983ad738f37SMatt Macy 
98435818d2eSJohn Baldwin 	req = ktr_getrequest(KTR_FAULT);
98535818d2eSJohn Baldwin 	if (req == NULL)
98635818d2eSJohn Baldwin 		return;
98735818d2eSJohn Baldwin 	kf = &req->ktr_data.ktr_fault;
98835818d2eSJohn Baldwin 	kf->vaddr = vaddr;
98935818d2eSJohn Baldwin 	kf->type = type;
99035818d2eSJohn Baldwin 	ktr_enqueuerequest(td, req);
99135818d2eSJohn Baldwin 	ktrace_exit(td);
99235818d2eSJohn Baldwin }
99335818d2eSJohn Baldwin 
99435818d2eSJohn Baldwin void
995039644ecSEd Maste ktrfaultend(int result)
99635818d2eSJohn Baldwin {
99735818d2eSJohn Baldwin 	struct thread *td = curthread;
99835818d2eSJohn Baldwin 	struct ktr_request *req;
99935818d2eSJohn Baldwin 	struct ktr_faultend *kf;
100035818d2eSJohn Baldwin 
1001ad738f37SMatt Macy 	if (__predict_false(curthread->td_pflags & TDP_INKTRACE))
1002ad738f37SMatt Macy 		return;
1003ad738f37SMatt Macy 
100435818d2eSJohn Baldwin 	req = ktr_getrequest(KTR_FAULTEND);
100535818d2eSJohn Baldwin 	if (req == NULL)
100635818d2eSJohn Baldwin 		return;
100735818d2eSJohn Baldwin 	kf = &req->ktr_data.ktr_faultend;
100835818d2eSJohn Baldwin 	kf->result = result;
100935818d2eSJohn Baldwin 	ktr_enqueuerequest(td, req);
101035818d2eSJohn Baldwin 	ktrace_exit(td);
101135818d2eSJohn Baldwin }
101264cc6a13SJohn Baldwin #endif /* KTRACE */
1013df8bae1dSRodney W. Grimes 
1014df8bae1dSRodney W. Grimes /* Interface and common routines */
1015df8bae1dSRodney W. Grimes 
1016d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_
1017df8bae1dSRodney W. Grimes struct ktrace_args {
1018df8bae1dSRodney W. Grimes 	char	*fname;
1019df8bae1dSRodney W. Grimes 	int	ops;
1020df8bae1dSRodney W. Grimes 	int	facs;
1021df8bae1dSRodney W. Grimes 	int	pid;
1022df8bae1dSRodney W. Grimes };
1023d2d3e875SBruce Evans #endif
1024df8bae1dSRodney W. Grimes /* ARGSUSED */
102526f9a767SRodney W. Grimes int
1026039644ecSEd Maste sys_ktrace(struct thread *td, struct ktrace_args *uap)
1027df8bae1dSRodney W. Grimes {
1028db6a20e2SGarrett Wollman #ifdef KTRACE
1029039644ecSEd Maste 	struct vnode *vp = NULL;
1030039644ecSEd Maste 	struct proc *p;
1031df8bae1dSRodney W. Grimes 	struct pgrp *pg;
1032df8bae1dSRodney W. Grimes 	int facs = uap->facs & ~KTRFAC_ROOT;
1033df8bae1dSRodney W. Grimes 	int ops = KTROP(uap->ops);
1034df8bae1dSRodney W. Grimes 	int descend = uap->ops & KTRFLAG_DESCEND;
1035f3851b23SMark Johnston 	int ret = 0;
10365050aa86SKonstantin Belousov 	int flags, error = 0;
1037df8bae1dSRodney W. Grimes 	struct nameidata nd;
10381762f674SKonstantin Belousov 	struct ktr_io_params *kiop, *old_kiop;
1039df8bae1dSRodney W. Grimes 
104064cc6a13SJohn Baldwin 	/*
104164cc6a13SJohn Baldwin 	 * Need something to (un)trace.
104264cc6a13SJohn Baldwin 	 */
104364cc6a13SJohn Baldwin 	if (ops != KTROP_CLEARFILE && facs == 0)
104464cc6a13SJohn Baldwin 		return (EINVAL);
104564cc6a13SJohn Baldwin 
10461762f674SKonstantin Belousov 	kiop = NULL;
1047df8bae1dSRodney W. Grimes 	if (ops != KTROP_CLEAR) {
1048df8bae1dSRodney W. Grimes 		/*
1049df8bae1dSRodney W. Grimes 		 * an operation which requires a file argument.
1050df8bae1dSRodney W. Grimes 		 */
10517e1d3eefSMateusz Guzik 		NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname);
1052e6796b67SKirk McKusick 		flags = FREAD | FWRITE | O_NOFOLLOW;
10539e223287SKonstantin Belousov 		error = vn_open(&nd, &flags, 0, NULL);
1054e4b16f2fSMark Johnston 		if (error)
1055df8bae1dSRodney W. Grimes 			return (error);
1056bb92cd7bSMateusz Guzik 		NDFREE_PNBUF(&nd);
1057df8bae1dSRodney W. Grimes 		vp = nd.ni_vp;
1058b249ce48SMateusz Guzik 		VOP_UNLOCK(vp);
1059df8bae1dSRodney W. Grimes 		if (vp->v_type != VREG) {
1060a854ed98SJohn Baldwin 			(void)vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
1061df8bae1dSRodney W. Grimes 			return (EACCES);
1062df8bae1dSRodney W. Grimes 		}
10631762f674SKonstantin Belousov 		kiop = ktr_io_params_alloc(td, vp);
1064df8bae1dSRodney W. Grimes 	}
1065e4b16f2fSMark Johnston 
1066df8bae1dSRodney W. Grimes 	/*
106779deba82SMatthew Dillon 	 * Clear all uses of the tracefile.
1068df8bae1dSRodney W. Grimes 	 */
1069e4b16f2fSMark Johnston 	ktrace_enter(td);
1070df8bae1dSRodney W. Grimes 	if (ops == KTROP_CLEARFILE) {
10711762f674SKonstantin Belousov restart:
10721005a129SJohn Baldwin 		sx_slock(&allproc_lock);
10734f506694SXin LI 		FOREACH_PROC_IN_SYSTEM(p) {
10741762f674SKonstantin Belousov 			old_kiop = NULL;
1075a7ff7443SJohn Baldwin 			PROC_LOCK(p);
10761762f674SKonstantin Belousov 			if (p->p_ktrioparms != NULL &&
10771762f674SKonstantin Belousov 			    p->p_ktrioparms->vp == vp) {
1078ea3fc8e4SJohn Baldwin 				if (ktrcanset(td, p)) {
1079ea3fc8e4SJohn Baldwin 					mtx_lock(&ktrace_mtx);
10801762f674SKonstantin Belousov 					old_kiop = ktr_freeproc(p);
1081ea3fc8e4SJohn Baldwin 					mtx_unlock(&ktrace_mtx);
108251fd6380SMike Pritchard 				} else
1083df8bae1dSRodney W. Grimes 					error = EPERM;
1084df8bae1dSRodney W. Grimes 			}
1085a7ff7443SJohn Baldwin 			PROC_UNLOCK(p);
10861762f674SKonstantin Belousov 			if (old_kiop != NULL) {
10871762f674SKonstantin Belousov 				sx_sunlock(&allproc_lock);
10881762f674SKonstantin Belousov 				ktr_io_params_free(old_kiop);
10891762f674SKonstantin Belousov 				goto restart;
10901762f674SKonstantin Belousov 			}
109179deba82SMatthew Dillon 		}
10921005a129SJohn Baldwin 		sx_sunlock(&allproc_lock);
1093df8bae1dSRodney W. Grimes 		goto done;
1094df8bae1dSRodney W. Grimes 	}
1095df8bae1dSRodney W. Grimes 	/*
1096df8bae1dSRodney W. Grimes 	 * do it
1097df8bae1dSRodney W. Grimes 	 */
109864cc6a13SJohn Baldwin 	sx_slock(&proctree_lock);
1099df8bae1dSRodney W. Grimes 	if (uap->pid < 0) {
1100df8bae1dSRodney W. Grimes 		/*
1101df8bae1dSRodney W. Grimes 		 * by process group
1102df8bae1dSRodney W. Grimes 		 */
1103df8bae1dSRodney W. Grimes 		pg = pgfind(-uap->pid);
1104df8bae1dSRodney W. Grimes 		if (pg == NULL) {
1105ba626c1dSJohn Baldwin 			sx_sunlock(&proctree_lock);
1106df8bae1dSRodney W. Grimes 			error = ESRCH;
1107df8bae1dSRodney W. Grimes 			goto done;
1108df8bae1dSRodney W. Grimes 		}
1109f3851b23SMark Johnston 
1110f591779bSSeigo Tanimura 		/*
1111f591779bSSeigo Tanimura 		 * ktrops() may call vrele(). Lock pg_members
1112ba626c1dSJohn Baldwin 		 * by the proctree_lock rather than pg_mtx.
1113f591779bSSeigo Tanimura 		 */
1114f591779bSSeigo Tanimura 		PGRP_UNLOCK(pg);
1115f3851b23SMark Johnston 		if (LIST_EMPTY(&pg->pg_members)) {
1116f3851b23SMark Johnston 			sx_sunlock(&proctree_lock);
1117f3851b23SMark Johnston 			error = ESRCH;
1118f3851b23SMark Johnston 			goto done;
1119f3851b23SMark Johnston 		}
1120400a74bfSPawel Jakub Dawidek 		LIST_FOREACH(p, &pg->pg_members, p_pglist) {
1121400a74bfSPawel Jakub Dawidek 			PROC_LOCK(p);
1122df8bae1dSRodney W. Grimes 			if (descend)
11231762f674SKonstantin Belousov 				ret |= ktrsetchildren(td, p, ops, facs, kiop);
1124df8bae1dSRodney W. Grimes 			else
11251762f674SKonstantin Belousov 				ret |= ktrops(td, p, ops, facs, kiop);
1126400a74bfSPawel Jakub Dawidek 		}
1127df8bae1dSRodney W. Grimes 	} else {
1128df8bae1dSRodney W. Grimes 		/*
1129df8bae1dSRodney W. Grimes 		 * by pid
1130df8bae1dSRodney W. Grimes 		 */
1131df8bae1dSRodney W. Grimes 		p = pfind(uap->pid);
1132f3851b23SMark Johnston 		if (p == NULL) {
1133df8bae1dSRodney W. Grimes 			error = ESRCH;
1134b0d9aeddSPawel Jakub Dawidek 			sx_sunlock(&proctree_lock);
11354eb7c9f6SPawel Jakub Dawidek 			goto done;
1136b0d9aeddSPawel Jakub Dawidek 		}
1137df8bae1dSRodney W. Grimes 		if (descend)
11381762f674SKonstantin Belousov 			ret |= ktrsetchildren(td, p, ops, facs, kiop);
1139df8bae1dSRodney W. Grimes 		else
11401762f674SKonstantin Belousov 			ret |= ktrops(td, p, ops, facs, kiop);
1141df8bae1dSRodney W. Grimes 	}
114264cc6a13SJohn Baldwin 	sx_sunlock(&proctree_lock);
1143df8bae1dSRodney W. Grimes 	if (!ret)
1144df8bae1dSRodney W. Grimes 		error = EPERM;
1145df8bae1dSRodney W. Grimes done:
11461762f674SKonstantin Belousov 	if (kiop != NULL) {
11471762f674SKonstantin Belousov 		mtx_lock(&ktrace_mtx);
11481762f674SKonstantin Belousov 		kiop = ktr_io_params_rele(kiop);
11491762f674SKonstantin Belousov 		mtx_unlock(&ktrace_mtx);
11501762f674SKonstantin Belousov 		ktr_io_params_free(kiop);
11511762f674SKonstantin Belousov 	}
11522c255e9dSRobert Watson 	ktrace_exit(td);
1153df8bae1dSRodney W. Grimes 	return (error);
115464cc6a13SJohn Baldwin #else /* !KTRACE */
115564cc6a13SJohn Baldwin 	return (ENOSYS);
115664cc6a13SJohn Baldwin #endif /* KTRACE */
1157df8bae1dSRodney W. Grimes }
1158df8bae1dSRodney W. Grimes 
1159e6c4b9baSPoul-Henning Kamp /* ARGSUSED */
1160e6c4b9baSPoul-Henning Kamp int
1161039644ecSEd Maste sys_utrace(struct thread *td, struct utrace_args *uap)
1162e6c4b9baSPoul-Henning Kamp {
1163b40ce416SJulian Elischer 
1164e6c4b9baSPoul-Henning Kamp #ifdef KTRACE
1165ea3fc8e4SJohn Baldwin 	struct ktr_request *req;
11667f05b035SAlfred Perlstein 	void *cp;
1167c9e7d28eSJohn Baldwin 	int error;
1168e6c4b9baSPoul-Henning Kamp 
1169c9e7d28eSJohn Baldwin 	if (!KTRPOINT(td, KTR_USER))
1170c9e7d28eSJohn Baldwin 		return (0);
1171bdfa4f04SAlfred Perlstein 	if (uap->len > KTR_USER_MAXLEN)
11720bad156aSAlfred Perlstein 		return (EINVAL);
1173a163d034SWarner Losh 	cp = malloc(uap->len, M_KTRACE, M_WAITOK);
1174c9e7d28eSJohn Baldwin 	error = copyin(uap->addr, cp, uap->len);
117550c22331SPoul-Henning Kamp 	if (error) {
117650c22331SPoul-Henning Kamp 		free(cp, M_KTRACE);
1177c9e7d28eSJohn Baldwin 		return (error);
117850c22331SPoul-Henning Kamp 	}
1179ea3fc8e4SJohn Baldwin 	req = ktr_getrequest(KTR_USER);
118050c22331SPoul-Henning Kamp 	if (req == NULL) {
118150c22331SPoul-Henning Kamp 		free(cp, M_KTRACE);
1182b10221ffSJoseph Koshy 		return (ENOMEM);
118350c22331SPoul-Henning Kamp 	}
1184d977a583SRobert Watson 	req->ktr_buffer = cp;
1185ea3fc8e4SJohn Baldwin 	req->ktr_header.ktr_len = uap->len;
11862c255e9dSRobert Watson 	ktr_submitrequest(td, req);
1187e6c4b9baSPoul-Henning Kamp 	return (0);
118864cc6a13SJohn Baldwin #else /* !KTRACE */
1189e6c4b9baSPoul-Henning Kamp 	return (ENOSYS);
119064cc6a13SJohn Baldwin #endif /* KTRACE */
1191e6c4b9baSPoul-Henning Kamp }
1192e6c4b9baSPoul-Henning Kamp 
1193db6a20e2SGarrett Wollman #ifdef KTRACE
119487b6de2bSPoul-Henning Kamp static int
11951762f674SKonstantin Belousov ktrops(struct thread *td, struct proc *p, int ops, int facs,
11961762f674SKonstantin Belousov     struct ktr_io_params *new_kiop)
1197df8bae1dSRodney W. Grimes {
11981762f674SKonstantin Belousov 	struct ktr_io_params *old_kiop;
1199df8bae1dSRodney W. Grimes 
1200fe41d17aSJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
1201a7ff7443SJohn Baldwin 	if (!ktrcanset(td, p)) {
1202a7ff7443SJohn Baldwin 		PROC_UNLOCK(p);
1203df8bae1dSRodney W. Grimes 		return (0);
1204a7ff7443SJohn Baldwin 	}
1205283e60fbSMark Johnston 	if ((ops == KTROP_SET && p->p_state == PRS_NEW) ||
1206283e60fbSMark Johnston 	    p_cansee(td, p) != 0) {
1207f3851b23SMark Johnston 		/*
1208f3851b23SMark Johnston 		 * Disallow setting trace points if the process is being born.
1209f3851b23SMark Johnston 		 * This avoids races with trace point inheritance in
1210f3851b23SMark Johnston 		 * ktrprocfork().
1211f3851b23SMark Johnston 		 */
1212f3851b23SMark Johnston 		PROC_UNLOCK(p);
1213f3851b23SMark Johnston 		return (0);
1214f3851b23SMark Johnston 	}
1215f3851b23SMark Johnston 	if ((p->p_flag & P_WEXIT) != 0) {
1216f3851b23SMark Johnston 		/*
1217f3851b23SMark Johnston 		 * There's nothing to do if the process is exiting, but avoid
1218f3851b23SMark Johnston 		 * signaling an error.
1219f3851b23SMark Johnston 		 */
1220fe41d17aSJohn Baldwin 		PROC_UNLOCK(p);
1221fe41d17aSJohn Baldwin 		return (1);
1222fe41d17aSJohn Baldwin 	}
12231762f674SKonstantin Belousov 	old_kiop = NULL;
1224ea3fc8e4SJohn Baldwin 	mtx_lock(&ktrace_mtx);
1225df8bae1dSRodney W. Grimes 	if (ops == KTROP_SET) {
12261762f674SKonstantin Belousov 		if (p->p_ktrioparms != NULL &&
12271762f674SKonstantin Belousov 		    p->p_ktrioparms->vp != new_kiop->vp) {
12281762f674SKonstantin Belousov 			/* if trace file already in use, relinquish below */
12291762f674SKonstantin Belousov 			old_kiop = ktr_io_params_rele(p->p_ktrioparms);
12301762f674SKonstantin Belousov 			p->p_ktrioparms = NULL;
1231a5881ea5SJohn Baldwin 		}
12321762f674SKonstantin Belousov 		if (p->p_ktrioparms == NULL) {
12331762f674SKonstantin Belousov 			p->p_ktrioparms = new_kiop;
12341762f674SKonstantin Belousov 			ktr_io_params_ref(new_kiop);
1235df8bae1dSRodney W. Grimes 		}
1236df8bae1dSRodney W. Grimes 		p->p_traceflag |= facs;
123732f9753cSRobert Watson 		if (priv_check(td, PRIV_KTRACE) == 0)
1238df8bae1dSRodney W. Grimes 			p->p_traceflag |= KTRFAC_ROOT;
1239df8bae1dSRodney W. Grimes 	} else {
1240df8bae1dSRodney W. Grimes 		/* KTROP_CLEAR */
1241d680caabSJohn Baldwin 		if (((p->p_traceflag &= ~facs) & KTRFAC_MASK) == 0)
1242df8bae1dSRodney W. Grimes 			/* no more tracing */
12431762f674SKonstantin Belousov 			old_kiop = ktr_freeproc(p);
1244a7ff7443SJohn Baldwin 	}
1245ea3fc8e4SJohn Baldwin 	mtx_unlock(&ktrace_mtx);
124622ec0406SDmitry Chagin 	if ((p->p_traceflag & KTRFAC_MASK) != 0)
124722ec0406SDmitry Chagin 		ktrprocctor_entered(td, p);
1248a7ff7443SJohn Baldwin 	PROC_UNLOCK(p);
12491762f674SKonstantin Belousov 	ktr_io_params_free(old_kiop);
1250df8bae1dSRodney W. Grimes 
1251df8bae1dSRodney W. Grimes 	return (1);
1252df8bae1dSRodney W. Grimes }
1253df8bae1dSRodney W. Grimes 
125487b6de2bSPoul-Henning Kamp static int
1255039644ecSEd Maste ktrsetchildren(struct thread *td, struct proc *top, int ops, int facs,
12561762f674SKonstantin Belousov     struct ktr_io_params *new_kiop)
1257df8bae1dSRodney W. Grimes {
1258039644ecSEd Maste 	struct proc *p;
1259039644ecSEd Maste 	int ret = 0;
1260df8bae1dSRodney W. Grimes 
1261df8bae1dSRodney W. Grimes 	p = top;
1262fe41d17aSJohn Baldwin 	PROC_LOCK_ASSERT(p, MA_OWNED);
126364cc6a13SJohn Baldwin 	sx_assert(&proctree_lock, SX_LOCKED);
1264df8bae1dSRodney W. Grimes 	for (;;) {
12651762f674SKonstantin Belousov 		ret |= ktrops(td, p, ops, facs, new_kiop);
1266df8bae1dSRodney W. Grimes 		/*
1267df8bae1dSRodney W. Grimes 		 * If this process has children, descend to them next,
1268df8bae1dSRodney W. Grimes 		 * otherwise do any siblings, and if done with this level,
1269df8bae1dSRodney W. Grimes 		 * follow back up the tree (but not past top).
1270df8bae1dSRodney W. Grimes 		 */
12712e3c8fcbSPoul-Henning Kamp 		if (!LIST_EMPTY(&p->p_children))
12722e3c8fcbSPoul-Henning Kamp 			p = LIST_FIRST(&p->p_children);
1273df8bae1dSRodney W. Grimes 		else for (;;) {
127464cc6a13SJohn Baldwin 			if (p == top)
1275df8bae1dSRodney W. Grimes 				return (ret);
12762e3c8fcbSPoul-Henning Kamp 			if (LIST_NEXT(p, p_sibling)) {
12772e3c8fcbSPoul-Henning Kamp 				p = LIST_NEXT(p, p_sibling);
1278df8bae1dSRodney W. Grimes 				break;
1279df8bae1dSRodney W. Grimes 			}
1280b75356e1SJeffrey Hsu 			p = p->p_pptr;
1281df8bae1dSRodney W. Grimes 		}
1282fe41d17aSJohn Baldwin 		PROC_LOCK(p);
1283df8bae1dSRodney W. Grimes 	}
1284df8bae1dSRodney W. Grimes 	/*NOTREACHED*/
1285df8bae1dSRodney W. Grimes }
1286df8bae1dSRodney W. Grimes 
128787b6de2bSPoul-Henning Kamp static void
12882c255e9dSRobert Watson ktr_writerequest(struct thread *td, struct ktr_request *req)
1289df8bae1dSRodney W. Grimes {
1290fc369a35SKonstantin Belousov 	struct ktr_io_params *kiop, *kiop1;
1291ea3fc8e4SJohn Baldwin 	struct ktr_header *kth;
1292ea3fc8e4SJohn Baldwin 	struct vnode *vp;
1293ea3fc8e4SJohn Baldwin 	struct proc *p;
1294ea3fc8e4SJohn Baldwin 	struct ucred *cred;
1295df8bae1dSRodney W. Grimes 	struct uio auio;
1296ea3fc8e4SJohn Baldwin 	struct iovec aiov[3];
1297f2a2857bSKirk McKusick 	struct mount *mp;
129802645b88SKonstantin Belousov 	off_t lim;
1299a6144f71SKonstantin Belousov 	int datalen, buflen;
13005050aa86SKonstantin Belousov 	int error;
1301df8bae1dSRodney W. Grimes 
13021762f674SKonstantin Belousov 	p = td->td_proc;
13031762f674SKonstantin Belousov 
13042c255e9dSRobert Watson 	/*
1305fc369a35SKonstantin Belousov 	 * We reference the kiop for use in I/O in case ktrace is
13062c255e9dSRobert Watson 	 * disabled on the process as we write out the request.
13072c255e9dSRobert Watson 	 */
13082c255e9dSRobert Watson 	mtx_lock(&ktrace_mtx);
13091762f674SKonstantin Belousov 	kiop = p->p_ktrioparms;
13102c255e9dSRobert Watson 
1311ea3fc8e4SJohn Baldwin 	/*
13121762f674SKonstantin Belousov 	 * If kiop is NULL, it has been cleared out from under this
13131762f674SKonstantin Belousov 	 * request, so just drop it.
1314ea3fc8e4SJohn Baldwin 	 */
13151762f674SKonstantin Belousov 	if (kiop == NULL) {
1316118258f5SBjoern A. Zeeb 		mtx_unlock(&ktrace_mtx);
1317df8bae1dSRodney W. Grimes 		return;
13182c255e9dSRobert Watson 	}
13191762f674SKonstantin Belousov 
1320fc369a35SKonstantin Belousov 	ktr_io_params_ref(kiop);
13211762f674SKonstantin Belousov 	vp = kiop->vp;
13221762f674SKonstantin Belousov 	cred = kiop->cr;
132302645b88SKonstantin Belousov 	lim = kiop->lim;
13241762f674SKonstantin Belousov 
13252c255e9dSRobert Watson 	KASSERT(cred != NULL, ("ktr_writerequest: cred == NULL"));
1326118258f5SBjoern A. Zeeb 	mtx_unlock(&ktrace_mtx);
13272c255e9dSRobert Watson 
1328ea3fc8e4SJohn Baldwin 	kth = &req->ktr_header;
1329fc90f3a2SDmitry Chagin 	KASSERT(((u_short)kth->ktr_type & ~KTR_TYPE) < nitems(data_lengths),
1330a56be37eSJohn Baldwin 	    ("data_lengths array overflow"));
1331fc90f3a2SDmitry Chagin 	datalen = data_lengths[(u_short)kth->ktr_type & ~KTR_TYPE];
1332ea3fc8e4SJohn Baldwin 	buflen = kth->ktr_len;
1333df8bae1dSRodney W. Grimes 	auio.uio_iov = &aiov[0];
1334df8bae1dSRodney W. Grimes 	auio.uio_offset = 0;
1335df8bae1dSRodney W. Grimes 	auio.uio_segflg = UIO_SYSSPACE;
1336df8bae1dSRodney W. Grimes 	auio.uio_rw = UIO_WRITE;
1337df8bae1dSRodney W. Grimes 	aiov[0].iov_base = (caddr_t)kth;
1338df8bae1dSRodney W. Grimes 	aiov[0].iov_len = sizeof(struct ktr_header);
1339df8bae1dSRodney W. Grimes 	auio.uio_resid = sizeof(struct ktr_header);
1340df8bae1dSRodney W. Grimes 	auio.uio_iovcnt = 1;
1341ea3fc8e4SJohn Baldwin 	auio.uio_td = td;
1342ea3fc8e4SJohn Baldwin 	if (datalen != 0) {
1343ea3fc8e4SJohn Baldwin 		aiov[1].iov_base = (caddr_t)&req->ktr_data;
1344ea3fc8e4SJohn Baldwin 		aiov[1].iov_len = datalen;
1345ea3fc8e4SJohn Baldwin 		auio.uio_resid += datalen;
1346df8bae1dSRodney W. Grimes 		auio.uio_iovcnt++;
1347ea3fc8e4SJohn Baldwin 		kth->ktr_len += datalen;
1348ea3fc8e4SJohn Baldwin 	}
1349ea3fc8e4SJohn Baldwin 	if (buflen != 0) {
1350d977a583SRobert Watson 		KASSERT(req->ktr_buffer != NULL, ("ktrace: nothing to write"));
1351d977a583SRobert Watson 		aiov[auio.uio_iovcnt].iov_base = req->ktr_buffer;
1352ea3fc8e4SJohn Baldwin 		aiov[auio.uio_iovcnt].iov_len = buflen;
1353ea3fc8e4SJohn Baldwin 		auio.uio_resid += buflen;
1354ea3fc8e4SJohn Baldwin 		auio.uio_iovcnt++;
1355b92584a6SJohn Baldwin 	}
13562c255e9dSRobert Watson 
1357f2a2857bSKirk McKusick 	vn_start_write(vp, &mp, V_WAIT);
1358cb05b60aSAttilio Rao 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
135902645b88SKonstantin Belousov 	td->td_ktr_io_lim = lim;
1360467a273cSRobert Watson #ifdef MAC
136130d239bcSRobert Watson 	error = mac_vnode_check_write(cred, NOCRED, vp);
1362467a273cSRobert Watson 	if (error == 0)
1363467a273cSRobert Watson #endif
1364ea3fc8e4SJohn Baldwin 		error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, cred);
1365b249ce48SMateusz Guzik 	VOP_UNLOCK(vp);
1366f2a2857bSKirk McKusick 	vn_finished_write(mp);
13671762f674SKonstantin Belousov 	if (error == 0) {
1368fc369a35SKonstantin Belousov 		mtx_lock(&ktrace_mtx);
1369fc369a35SKonstantin Belousov 		kiop = ktr_io_params_rele(kiop);
1370fc369a35SKonstantin Belousov 		mtx_unlock(&ktrace_mtx);
1371fc369a35SKonstantin Belousov 		ktr_io_params_free(kiop);
1372df8bae1dSRodney W. Grimes 		return;
1373118258f5SBjoern A. Zeeb 	}
1374118258f5SBjoern A. Zeeb 
1375df8bae1dSRodney W. Grimes 	/*
1376a6144f71SKonstantin Belousov 	 * If error encountered, give up tracing on this vnode on this
1377a6144f71SKonstantin Belousov 	 * process.  Other processes might still be suitable for
1378a6144f71SKonstantin Belousov 	 * writes to this vnode.
1379df8bae1dSRodney W. Grimes 	 */
1380a6144f71SKonstantin Belousov 	log(LOG_NOTICE,
1381a6144f71SKonstantin Belousov 	    "ktrace write failed, errno %d, tracing stopped for pid %d\n",
1382a6144f71SKonstantin Belousov 	    error, p->p_pid);
13831762f674SKonstantin Belousov 
1384fc369a35SKonstantin Belousov 	kiop1 = NULL;
1385ea3fc8e4SJohn Baldwin 	PROC_LOCK(p);
1386ea3fc8e4SJohn Baldwin 	mtx_lock(&ktrace_mtx);
13871762f674SKonstantin Belousov 	if (p->p_ktrioparms != NULL && p->p_ktrioparms->vp == vp)
1388fc369a35SKonstantin Belousov 		kiop1 = ktr_freeproc(p);
1389fc369a35SKonstantin Belousov 	kiop = ktr_io_params_rele(kiop);
1390ea3fc8e4SJohn Baldwin 	mtx_unlock(&ktrace_mtx);
1391ea3fc8e4SJohn Baldwin 	PROC_UNLOCK(p);
1392fc369a35SKonstantin Belousov 	ktr_io_params_free(kiop1);
13931762f674SKonstantin Belousov 	ktr_io_params_free(kiop);
1394df8bae1dSRodney W. Grimes }
1395df8bae1dSRodney W. Grimes 
1396df8bae1dSRodney W. Grimes /*
1397df8bae1dSRodney W. Grimes  * Return true if caller has permission to set the ktracing state
1398df8bae1dSRodney W. Grimes  * of target.  Essentially, the target can't possess any
1399df8bae1dSRodney W. Grimes  * more permissions than the caller.  KTRFAC_ROOT signifies that
1400df8bae1dSRodney W. Grimes  * root previously set the tracing status on the target process, and
1401df8bae1dSRodney W. Grimes  * so, only root may further change it.
1402df8bae1dSRodney W. Grimes  */
140387b6de2bSPoul-Henning Kamp static int
1404039644ecSEd Maste ktrcanset(struct thread *td, struct proc *targetp)
1405df8bae1dSRodney W. Grimes {
1406df8bae1dSRodney W. Grimes 
1407a7ff7443SJohn Baldwin 	PROC_LOCK_ASSERT(targetp, MA_OWNED);
1408a0f75161SRobert Watson 	if (targetp->p_traceflag & KTRFAC_ROOT &&
140932f9753cSRobert Watson 	    priv_check(td, PRIV_KTRACE))
141075c13541SPoul-Henning Kamp 		return (0);
1411a0f75161SRobert Watson 
1412f44d9e24SJohn Baldwin 	if (p_candebug(td, targetp) != 0)
1413a0f75161SRobert Watson 		return (0);
1414a0f75161SRobert Watson 
1415df8bae1dSRodney W. Grimes 	return (1);
1416df8bae1dSRodney W. Grimes }
1417df8bae1dSRodney W. Grimes 
1418db6a20e2SGarrett Wollman #endif /* KTRACE */
1419