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 *);