Repost of an older diff. This may conflict with otto's diff, we'll sort that out.
This isn't useful day to day, but allows a developer to insert tracing points and log data with very low overhead. Suggestions and bug reports welcome. Index: kern/kern_ktrace.c =================================================================== RCS file: /home/tedu/cvs/src/sys/kern/kern_ktrace.c,v retrieving revision 1.51 diff -u -p -r1.51 kern_ktrace.c --- kern/kern_ktrace.c 2 Jun 2011 16:29:20 -0000 1.51 +++ kern/kern_ktrace.c 6 Jul 2011 19:07:28 -0000 @@ -45,6 +45,7 @@ #include <sys/malloc.h> #include <sys/syslog.h> #include <sys/sysctl.h> +#include <sys/workq.h> #include <sys/mount.h> #include <sys/syscall.h> @@ -59,6 +60,120 @@ int ktrsetchildren(struct proc *, struct int ktrwrite(struct proc *, struct ktr_header *); int ktrcanset(struct proc *, struct proc *); + +/* + * special fast ring for kernel events + */ +int ktrkern_active; +struct ktrkern_event *ktrkern_buf, *ktrkern_buf_start, *ktrkern_buf_end; +int ktrkern_flushing; +int ktrkern_bufsize = 32768; +struct mutex ktrkern_mtx; +struct vnode *ktrkern_vp; +void ktrkern_flush(void); + +void +ktrkern_log(struct proc *p, int event, unsigned long data) +{ + struct ktrkern_event *kev; + + if (!ktrkern_active) + return; + + mtx_enter(&ktrkern_mtx); + if (ktrkern_active && ktrkern_buf < ktrkern_buf_end) { + kev = ktrkern_buf++; + ktrinitheader(&kev->ktr_head, p ? p : &proc0, KTR_KERN); + kev->ktr_event = event; + kev->ktr_data = data; + /* start flushing at half way full */ + if (ktrkern_buf_end - ktrkern_buf < ktrkern_bufsize / 2 && + !ktrkern_flushing) { + workq_add_task(NULL, 0, (workq_fn)ktrkern_flush, + NULL, NULL); + } + } + mtx_leave(&ktrkern_mtx); +} + +void +ktrkern_flush(void) +{ + struct vnode *vp = ktrkern_vp; + struct proc *p = curproc; + struct ktrkern_event *start, *end, *realend; + struct uio auio; + struct iovec aiov[2]; + int error; + int len; + + if (vp == NULL) + return; + + /* first copy out the front half */ + mtx_enter(&ktrkern_mtx); + start = ktrkern_buf_start; + end = ktrkern_buf; + realend = ktrkern_buf_end; + mtx_leave(&ktrkern_mtx); + + len = (char *)end - (char *)start; + auio.uio_iov = &aiov[0]; + auio.uio_offset = 0; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_WRITE; + aiov[0].iov_base = start; + aiov[0].iov_len = len; + auio.uio_resid = len; + auio.uio_iovcnt = 1; + auio.uio_procp = p; + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred); + if (error) + printf("error writing %d\n", error); + else + printf("flushing done\n"); + if (!error) { + /* + * now write out what we missed. we swizzle pointers around + * so that the buffer can (almost) always be used, + * without danger of corruption. + * the just written part above can now be reused. + */ + mtx_enter(&ktrkern_mtx); + start = end; + end = ktrkern_buf; + ktrkern_buf = ktrkern_buf_start; + ktrkern_buf_end = start - 1; + mtx_leave(&ktrkern_mtx); + + len = (char *)end - (char *)start; + auio.uio_iov = &aiov[0]; + auio.uio_offset = 0; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_WRITE; + aiov[0].iov_base = start; + aiov[0].iov_len = len; + auio.uio_resid = len; + auio.uio_iovcnt = 1; + auio.uio_procp = p; + error = VOP_WRITE(vp, &auio, IO_UNIT|IO_APPEND, p->p_ucred); + } + + /* now make the whole buffer available again */ + mtx_enter(&ktrkern_mtx); + ktrkern_buf_end = realend; + ktrkern_flushing = 0; + mtx_leave(&ktrkern_mtx); + + if (error) { + vrele(vp); + ktrkern_vp = NULL; + } + VOP_UNLOCK(vp, 0, p); +} + + /* * Change the trace vnode in a correct way (to avoid races). */ @@ -297,10 +412,11 @@ sys_ktrace(struct proc *curp, void *v, r int descend = SCARG(uap, ops) & KTRFLAG_DESCEND; int ret = 0; int error = 0; + int flushing; struct nameidata nd; curp->p_traceflag |= KTRFAC_ACTIVE; - if (ops != KTROP_CLEAR) { + if (ops != KTROP_CLEAR && ops != KTROP_KERNCLEAR) { /* * an operation which requires a file argument. */ @@ -333,7 +449,37 @@ sys_ktrace(struct proc *curp, void *v, r } } goto done; + } else if (ops == KTROP_KERNCLEAR) { + if (ktrkern_vp) { + mtx_enter(&ktrkern_mtx); + flushing = ktrkern_flushing++; + ktrkern_active = 0; + mtx_leave(&ktrkern_mtx); + + /* flushing will not happen above if it's not active */ + if (!flushing) + ktrkern_flush(); + vrele(ktrkern_vp); + ktrkern_vp = NULL; + } + } else if (ops == KTROP_KERN) { + if (ktrkern_vp) { + error = EBUSY; + goto done; + } + vref(vp); + ktrkern_vp = vp; + if (!ktrkern_buf_start) { + mtx_init(&ktrkern_mtx, IPL_HIGH); + ktrkern_buf_start = malloc(ktrkern_bufsize * + sizeof(*ktrkern_buf), M_TEMP, M_WAITOK); + } + ktrkern_buf = ktrkern_buf_start; + ktrkern_buf_end = ktrkern_buf_start + ktrkern_bufsize - 1; + ktrkern_active = 1; + goto done; } + /* * need something to (un)trace (XXX - why is this here?) */ @@ -521,5 +667,6 @@ ktrcanset(struct proc *callp, struct pro return (0); } + #endif Index: sys/ktrace.h =================================================================== RCS file: /home/tedu/cvs/src/sys/sys/ktrace.h,v retrieving revision 1.10 diff -u -p -r1.10 ktrace.h --- sys/ktrace.h 2 Jun 2011 16:19:12 -0000 1.10 +++ sys/ktrace.h 6 Jul 2011 19:07:28 -0000 @@ -38,11 +38,13 @@ #define KTROP_SET 0 /* set trace points */ #define KTROP_CLEAR 1 /* clear trace points */ #define KTROP_CLEARFILE 2 /* stop all tracing to file */ -#define KTROP(o) ((o)&3) /* macro to extract operation */ +#define KTROP_KERN 3 +#define KTROP_KERNCLEAR 4 +#define KTROP(o) ((o)&0xff) /* macro to extract operation */ /* * flags (ORed in with operation) */ -#define KTRFLAG_DESCEND 4 /* perform op on all children too */ +#define KTRFLAG_DESCEND 0x100 /* perform op on all children too */ /* * ktrace record header @@ -56,6 +58,14 @@ struct ktr_header { caddr_t ktr_buf; }; +/* builtin header */ +struct ktrkern_event { + struct ktr_header ktr_head; + int ktr_event; + long ktr_data; +}; + + /* * Test for kernel trace point */ @@ -134,6 +144,8 @@ struct ktr_csw { #define KTR_EMUL 7 /* record contains emulation name */ +#define KTR_KERN 8 + /* * kernel trace points (in p_traceflag) @@ -146,6 +158,7 @@ struct ktr_csw { #define KTRFAC_PSIG (1<<KTR_PSIG) #define KTRFAC_CSW (1<<KTR_CSW) #define KTRFAC_EMUL (1<<KTR_EMUL) +#define KTRFAC_KERN (1<<KTR_KERN) /* * trace flags (also in p_traceflags) */ @@ -170,6 +183,9 @@ void ktrnamei(struct proc *, char *); void ktrpsig(struct proc *, int, sig_t, int, int, siginfo_t *); void ktrsyscall(struct proc *, register_t, size_t, register_t []); void ktrsysret(struct proc *, register_t, int, register_t); + +extern int ktrkern_active; +void ktrkern_log(struct proc *, int, unsigned long); void ktrsettracevnode(struct proc *, struct vnode *);