Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 050eef36 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Martin Schwidefsky
Browse files

[S390] fix tlb flushing vs. concurrent /proc accesses



The tlb flushing code uses the mm_users field of the mm_struct to
decide if each page table entry needs to be flushed individually with
IPTE or if a global flush for the mm_struct is sufficient after all page
table updates have been done. The comment for mm_users says "How many
users with user space?" but the /proc code increases mm_users after it
found the process structure by pid without creating a new user process.
Which makes mm_users useless for the decision between the two tlb
flusing methods. The current code can be confused to not flush tlb
entries by a concurrent access to /proc files if e.g. a fork is in
progres. The solution for this problem is to make the tlb flushing
logic independent from the mm_users field.

Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 7af048dc
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
{
	pte_t pte = huge_ptep_get(ptep);

	mm->context.flush_mm = 1;
	pmd_clear((pmd_t *) ptep);
	return pte;
}
@@ -167,7 +168,8 @@ static inline void huge_ptep_invalidate(struct mm_struct *mm,
({									\
	pte_t __pte = huge_ptep_get(__ptep);				\
	if (pte_write(__pte)) {						\
		if (atomic_read(&(__mm)->mm_users) > 1 ||		\
		(__mm)->context.flush_mm = 1;				\
		if (atomic_read(&(__mm)->context.attach_count) > 1 ||	\
		    (__mm) != current->active_mm)			\
			huge_ptep_invalidate(__mm, __addr, __ptep);	\
		set_huge_pte_at(__mm, __addr, __ptep,			\
+2 −0
Original line number Diff line number Diff line
@@ -2,6 +2,8 @@
#define __MMU_H

typedef struct {
	atomic_t attach_count;
	unsigned int flush_mm;
	spinlock_t list_lock;
	struct list_head crst_list;
	struct list_head pgtable_list;
+9 −0
Original line number Diff line number Diff line
@@ -11,11 +11,14 @@

#include <asm/pgalloc.h>
#include <asm/uaccess.h>
#include <asm/tlbflush.h>
#include <asm-generic/mm_hooks.h>

static inline int init_new_context(struct task_struct *tsk,
				   struct mm_struct *mm)
{
	atomic_set(&mm->context.attach_count, 0);
	mm->context.flush_mm = 0;
	mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
#ifdef CONFIG_64BIT
	mm->context.asce_bits |= _ASCE_TYPE_REGION3;
@@ -76,6 +79,12 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
{
	cpumask_set_cpu(smp_processor_id(), mm_cpumask(next));
	update_mm(next, tsk);
	atomic_dec(&prev->context.attach_count);
	WARN_ON(atomic_read(&prev->context.attach_count) < 0);
	atomic_inc(&next->context.attach_count);
	/* Check for TLBs not flushed yet */
	if (next->context.flush_mm)
		__tlb_flush_mm(next);
}

#define enter_lazy_tlb(mm,tsk)	do { } while (0)
+4 −2
Original line number Diff line number Diff line
@@ -880,7 +880,8 @@ static inline void ptep_invalidate(struct mm_struct *mm,
#define ptep_get_and_clear(__mm, __address, __ptep)			\
({									\
	pte_t __pte = *(__ptep);					\
	if (atomic_read(&(__mm)->mm_users) > 1 ||			\
	(__mm)->context.flush_mm = 1;					\
	if (atomic_read(&(__mm)->context.attach_count) > 1 ||		\
	    (__mm) != current->active_mm)				\
		ptep_invalidate(__mm, __address, __ptep);		\
	else								\
@@ -923,7 +924,8 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
({									\
	pte_t __pte = *(__ptep);					\
	if (pte_write(__pte)) {						\
		if (atomic_read(&(__mm)->mm_users) > 1 ||		\
		(__mm)->context.flush_mm = 1;				\
		if (atomic_read(&(__mm)->context.attach_count) > 1 ||	\
		    (__mm) != current->active_mm)			\
			ptep_invalidate(__mm, __addr, __ptep);		\
		set_pte_at(__mm, __addr, __ptep, pte_wrprotect(__pte));	\
+1 −2
Original line number Diff line number Diff line
@@ -50,8 +50,7 @@ static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm,
	struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);

	tlb->mm = mm;
	tlb->fullmm = full_mm_flush || (num_online_cpus() == 1) ||
		(atomic_read(&mm->mm_users) <= 1 && mm == current->active_mm);
	tlb->fullmm = full_mm_flush;
	tlb->nr_ptes = 0;
	tlb->nr_pxds = TLB_NR_PTRS;
	if (tlb->fullmm)
Loading