diff options
Diffstat (limited to 'kernel/exit.c')
| -rw-r--r-- | kernel/exit.c | 16 | 
1 files changed, 15 insertions, 1 deletions
| diff --git a/kernel/exit.c b/kernel/exit.c index 1f236ed375f8..3594291a8542 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -478,10 +478,24 @@ static void exit_mm(void)  	BUG_ON(mm != current->active_mm);  	/* more a memory barrier than a real lock */  	task_lock(current); +	/* +	 * When a thread stops operating on an address space, the loop +	 * in membarrier_private_expedited() may not observe that +	 * tsk->mm, and the loop in membarrier_global_expedited() may +	 * not observe a MEMBARRIER_STATE_GLOBAL_EXPEDITED +	 * rq->membarrier_state, so those would not issue an IPI. +	 * Membarrier requires a memory barrier after accessing +	 * user-space memory, before clearing tsk->mm or the +	 * rq->membarrier_state. +	 */ +	smp_mb__after_spinlock(); +	local_irq_disable();  	current->mm = NULL; -	mmap_read_unlock(mm); +	membarrier_update_current_mm(NULL);  	enter_lazy_tlb(mm, current); +	local_irq_enable();  	task_unlock(current); +	mmap_read_unlock(mm);  	mm_update_next_owner(mm);  	mmput(mm);  	if (test_thread_flag(TIF_MEMDIE)) | 
