Merge branch 'linus' into sched/core, to resolve semantic conflict
[linux-2.6-microblaze.git] / kernel / kthread.c
index 933a625..e6aa665 100644 (file)
@@ -1249,6 +1249,7 @@ void kthread_use_mm(struct mm_struct *mm)
                tsk->active_mm = mm;
        }
        tsk->mm = mm;
+       membarrier_update_current_mm(mm);
        switch_mm_irqs_off(active_mm, mm, tsk);
        local_irq_enable();
        task_unlock(tsk);
@@ -1256,8 +1257,19 @@ void kthread_use_mm(struct mm_struct *mm)
        finish_arch_post_lock_switch();
 #endif
 
+       /*
+        * When a kthread starts operating on an address space, the loop
+        * in membarrier_{private,global}_expedited() may not observe
+        * that tsk->mm, and not issue an IPI. Membarrier requires a
+        * memory barrier after storing to tsk->mm, before accessing
+        * user-space memory. A full memory barrier for membarrier
+        * {PRIVATE,GLOBAL}_EXPEDITED is implicitly provided by
+        * mmdrop(), or explicitly with smp_mb().
+        */
        if (active_mm != mm)
                mmdrop(active_mm);
+       else
+               smp_mb();
 
        to_kthread(tsk)->oldfs = force_uaccess_begin();
 }
@@ -1277,9 +1289,18 @@ void kthread_unuse_mm(struct mm_struct *mm)
        force_uaccess_end(to_kthread(tsk)->oldfs);
 
        task_lock(tsk);
+       /*
+        * When a kthread stops operating on an address space, the loop
+        * in membarrier_{private,global}_expedited() may not observe
+        * that tsk->mm, and not issue an IPI. Membarrier requires a
+        * memory barrier after accessing user-space memory, before
+        * clearing tsk->mm.
+        */
+       smp_mb__after_spinlock();
        sync_mm_rss(mm);
        local_irq_disable();
        tsk->mm = NULL;
+       membarrier_update_current_mm(NULL);
        /* active_mm is still 'mm' */
        enter_lazy_tlb(mm, tsk);
        local_irq_enable();