diff options
Diffstat (limited to 'include/asm-generic/pgtable.h')
| -rw-r--r-- | include/asm-generic/pgtable.h | 22 | 
1 files changed, 20 insertions, 2 deletions
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index e2768f188f5..6f2b45a9b6b 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -445,6 +445,18 @@ static inline int pmd_write(pmd_t pmd)  #endif /* __HAVE_ARCH_PMD_WRITE */  #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +#ifndef pmd_read_atomic +static inline pmd_t pmd_read_atomic(pmd_t *pmdp) +{ +	/* +	 * Depend on compiler for an atomic pmd read. NOTE: this is +	 * only going to work, if the pmdval_t isn't larger than +	 * an unsigned long. +	 */ +	return *pmdp; +} +#endif +  /*   * This function is meant to be used by sites walking pagetables with   * the mmap_sem hold in read mode to protect against MADV_DONTNEED and @@ -458,11 +470,17 @@ static inline int pmd_write(pmd_t pmd)   * undefined so behaving like if the pmd was none is safe (because it   * can return none anyway). The compiler level barrier() is critically   * important to compute the two checks atomically on the same pmdval. + * + * For 32bit kernels with a 64bit large pmd_t this automatically takes + * care of reading the pmd atomically to avoid SMP race conditions + * against pmd_populate() when the mmap_sem is hold for reading by the + * caller (a special atomic read not done by "gcc" as in the generic + * version above, is also needed when THP is disabled because the page + * fault can populate the pmd from under us).   */  static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t *pmd)  { -	/* depend on compiler for an atomic pmd read */ -	pmd_t pmdval = *pmd; +	pmd_t pmdval = pmd_read_atomic(pmd);  	/*  	 * The barrier will stabilize the pmdval in a register or on  	 * the stack so that it will stop changing under the code.  |