svn commit: r186908 - in user/luigi/geom_sched/sys/geom: . sched

Luigi Rizzo luigi at FreeBSD.org
Thu Jan 8 10:24:05 PST 2009


Author: luigi
Date: Thu Jan  8 18:24:04 2009
New Revision: 186908
URL: http://svn.freebsd.org/changeset/base/186908

Log:
  make it work with a stock kernel

Modified:
  user/luigi/geom_sched/sys/geom/geom_io.c
  user/luigi/geom_sched/sys/geom/sched/g_sched.c

Modified: user/luigi/geom_sched/sys/geom/geom_io.c
==============================================================================
--- user/luigi/geom_sched/sys/geom/geom_io.c	Thu Jan  8 17:51:15 2009	(r186907)
+++ user/luigi/geom_sched/sys/geom/geom_io.c	Thu Jan  8 18:24:04 2009	(r186908)
@@ -369,6 +369,7 @@ g_io_request(struct bio *bp, struct g_co
 	bp->bio_error = 0;
 	bp->bio_completed = 0;
 
+#if 0
 	/*
 	 * Scheduler support: if this is the first element in the geom
 	 * chain (we know from bp->bio_parent == NULL), store
@@ -382,6 +383,7 @@ g_io_request(struct bio *bp, struct g_co
 		else
 			bp->bio_caller1 = (void *)curthread->td_tid;
 	}
+#endif
 
 	KASSERT(!(bp->bio_flags & BIO_ONQUEUE),
 	    ("Bio already on queue bp=%p", bp));

Modified: user/luigi/geom_sched/sys/geom/sched/g_sched.c
==============================================================================
--- user/luigi/geom_sched/sys/geom/sched/g_sched.c	Thu Jan  8 17:51:15 2009	(r186907)
+++ user/luigi/geom_sched/sys/geom/sched/g_sched.c	Thu Jan  8 18:24:04 2009	(r186908)
@@ -35,6 +35,7 @@
 #include <sys/bio.h>
 #include <sys/sysctl.h>
 #include <sys/malloc.h>
+#include <sys/proc.h>	/* we access curthread */
 #include <geom/geom.h>
 #include "g_gsched.h"
 #include "g_sched.h"
@@ -396,18 +397,103 @@ g_sched_destroy_geom(struct gctl_req *re
 	return (g_sched_destroy(gp, 0));
 }
 
+/*
+ * The code below patches g_io_request() to call g_new_io_request() first.
+ * We must be careful with the compiler, as it may clobber the
+ * parameters on the stack so they are not preserved for the
+ * continuation of the original function.
+ * Ideally we should write everything in assembler:
+
+	mov 0x8(%esp), %edx	// load bp
+	mov    0x64(%edx),%eax	// load bp->bio_parent
+	test   %eax,%eax
+	jne	1f
+ 	mov    0x30(%edx),%eax	// load bp->bio_caller1
+	test   %eax,%eax
+	jne	1f
+	mov    %fs:0x0,%eax	// pcpu pointer
+	mov    0x34(%eax),%eax	// curthread
+	mov    %eax,0x30(%edx)	// store in bp->bio_caller1
+    1:  // old function
+	push %ebp
+	mov %esp, %ebp
+	push %edi
+	push %esi
+	  jmp x+5
+
+ */
+
+static unsigned char
+g_io_trampoline[] = {
+        0xe8, 0x00, 0x00, 0x00, 0x00,   /* call foo */
+        0x55,                           /* push %ebp */
+        0x89, 0xe5,                     /* mov    %esp,%ebp */
+        0x57,                           /* push %edi */
+        0x56,                           /* push %esi */
+        0xe9, 0x00, 0x00, 0x00, 0x00,   /* jmp x+5 */
+};
+
+static void
+g_new_io_request(const char *ret, struct bio *bp, struct g_consumer *cp)
+{
+
+        /*
+         * Scheduler support: if this is the first element in the geom
+         * chain (we know from bp->bio_parent == NULL), store
+         * the thread that originated the request in bp->bio_caller1,
+         * which should be unused in this particular entry (at least
+         * with the code in 7.1/8.0).
+         */
+        if (bp->bio_parent == NULL && bp->bio_caller1 == NULL)
+		bp->bio_caller1 = (void *)curthread->td_tid;
+}
+
+static int g_io_patched = 0;
+static int
+g_io_patch(void *f, void *p, void *new_f)
+{
+	int found = bcmp(f, (const char *)p + 5, 5);
+	printf("match result %d\n", found);
+        if (found == 0) {
+                int ofs;
+
+		printf("patching function\n");
+                /* link the trampoline to the new function */
+                ofs = (int)new_f - ((int)p + 5);
+                bcopy(&ofs, (char *)p + 1, 4);
+                /* jump back to the original + 5 */
+                ofs = ((int)f + 5) - ((int)p + 15);
+                bcopy(&ofs, (char *)p + 11, 4);
+                /* patch the original address with a jump to the trampoline */
+                *(unsigned char *)f = 0xe9;     /* jump opcode */
+                ofs = (int)p - ((int)f + 5);
+                bcopy(&ofs, (char *)f + 1, 4);
+		g_io_patched = 1;
+        }
+        return 0;
+}
+
 static void
 g_sched_init(struct g_class *mp)
 {
 
 	mtx_init(&g_gsched_mtx, "gsched", NULL, MTX_DEF);
 	LIST_INIT(&gsched_list);
+
+	printf("%s loading...\n", __FUNCTION__);
+	/* patch g_io_request to set the thread */
+	g_io_patch(g_io_request, g_io_trampoline, g_new_io_request);
 }
 
 static void
 g_sched_fini(struct g_class *mp)
 {
 
+	if (g_io_patched) {
+		/* restore the original g_io_request */
+		bcopy(g_io_trampoline + 5, (char *)g_io_request, 5);
+	}
+	printf("%s unloading...\n", __FUNCTION__);
 	KASSERT(LIST_EMPTY(&gsched_list), ("still registered schedulers"));
 	mtx_destroy(&g_gsched_mtx);
 }


More information about the svn-src-user mailing list