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