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

Reply via email to