diff -urNp x-ref/include/linux/sched_runqueue.h x/include/linux/sched_runqueue.h
--- x-ref/include/linux/sched_runqueue.h	2003-03-11 23:16:26.000000000 +0100
+++ x/include/linux/sched_runqueue.h	2003-03-11 23:16:27.000000000 +0100
@@ -62,6 +62,7 @@ struct runqueue {
 	task_t *curr, *idle;
 	prio_array_t *active, *expired, arrays[2];
 	long nr_uninterruptible;
+	struct mm_struct * prev_mm;
 #ifdef CONFIG_SMP
 	long last_jiffy;
 	int prev_nr_running[NR_CPUS];
diff -urNp x-ref/kernel/sched.c x/kernel/sched.c
--- x-ref/kernel/sched.c	2003-03-11 23:16:26.000000000 +0100
+++ x/kernel/sched.c	2003-03-11 23:16:27.000000000 +0100
@@ -445,14 +445,20 @@ void sched_exit(task_t * p)
 	__sti();
 }
 
-#if CONFIG_SMP
 asmlinkage void schedule_tail(task_t *prev)
 {
-	finish_arch_switch(this_rq(), prev);
+	runqueue_t *rq = this_rq();
+	struct mm_struct *mm;
+
+	finish_arch_switch(rq, prev);
+
+	mm = rq->prev_mm;
+	rq->prev_mm = NULL;
+	if (mm)
+		mmdrop(mm);
 }
-#endif
 
-static inline task_t * context_switch(task_t *prev, task_t *next)
+static inline task_t * context_switch(runqueue_t * rq, task_t *prev, task_t *next)
 {
 	struct mm_struct *mm = next->mm;
 	struct mm_struct *oldmm = prev->active_mm;
@@ -466,7 +472,11 @@ static inline task_t * context_switch(ta
 
 	if (unlikely(!prev->mm)) {
 		prev->active_mm = NULL;
-		mmdrop(oldmm);
+		if (unlikely(rq->prev_mm)) {
+			printk(KERN_ERR "rq->prev_mm was %p set to %p - %s\n", rq->prev_mm, oldmm, current->comm);
+			dump_stack();
+		}
+		rq->prev_mm = oldmm;
 	}
 
 	/* Here we just switch the register state and the stack. */
@@ -941,10 +951,10 @@ switch_tasks:
 		rq->curr = next;
 	
 		prepare_arch_switch(rq, next);
-		prev = context_switch(prev, next);
+		prev = context_switch(rq, prev, next);
 		barrier();
-		rq = this_rq();
-		finish_arch_switch(rq, prev);
+		/* from this point "rq" is invalid in the stack */
+		schedule_tail(prev);
 	} else
 		spin_unlock_irq(&rq->lock);