aboutsummaryrefslogtreecommitdiffstats
path: root/include/asm-generic/pgtable.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/asm-generic/pgtable.h')
-rw-r--r--include/asm-generic/pgtable.h61
1 files changed, 61 insertions, 0 deletions
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 236b1056839..125c54e9851 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -426,6 +426,8 @@ extern void untrack_pfn_vma(struct vm_area_struct *vma, unsigned long pfn,
426 unsigned long size); 426 unsigned long size);
427#endif 427#endif
428 428
429#ifdef CONFIG_MMU
430
429#ifndef CONFIG_TRANSPARENT_HUGEPAGE 431#ifndef CONFIG_TRANSPARENT_HUGEPAGE
430static inline int pmd_trans_huge(pmd_t pmd) 432static inline int pmd_trans_huge(pmd_t pmd)
431{ 433{
@@ -442,7 +444,66 @@ static inline int pmd_write(pmd_t pmd)
442 return 0; 444 return 0;
443} 445}
444#endif /* __HAVE_ARCH_PMD_WRITE */ 446#endif /* __HAVE_ARCH_PMD_WRITE */
447#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
448
449/*
450 * This function is meant to be used by sites walking pagetables with
451 * the mmap_sem hold in read mode to protect against MADV_DONTNEED and
452 * transhuge page faults. MADV_DONTNEED can convert a transhuge pmd
453 * into a null pmd and the transhuge page fault can convert a null pmd
454 * into an hugepmd or into a regular pmd (if the hugepage allocation
455 * fails). While holding the mmap_sem in read mode the pmd becomes
456 * stable and stops changing under us only if it's not null and not a
457 * transhuge pmd. When those races occurs and this function makes a
458 * difference vs the standard pmd_none_or_clear_bad, the result is
459 * undefined so behaving like if the pmd was none is safe (because it
460 * can return none anyway). The compiler level barrier() is critically
461 * important to compute the two checks atomically on the same pmdval.
462 */
463static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t *pmd)
464{
465 /* depend on compiler for an atomic pmd read */
466 pmd_t pmdval = *pmd;
467 /*
468 * The barrier will stabilize the pmdval in a register or on
469 * the stack so that it will stop changing under the code.
470 */
471#ifdef CONFIG_TRANSPARENT_HUGEPAGE
472 barrier();
473#endif
474 if (pmd_none(pmdval))
475 return 1;
476 if (unlikely(pmd_bad(pmdval))) {
477 if (!pmd_trans_huge(pmdval))
478 pmd_clear_bad(pmd);
479 return 1;
480 }
481 return 0;
482}
483
484/*
485 * This is a noop if Transparent Hugepage Support is not built into
486 * the kernel. Otherwise it is equivalent to
487 * pmd_none_or_trans_huge_or_clear_bad(), and shall only be called in
488 * places that already verified the pmd is not none and they want to
489 * walk ptes while holding the mmap sem in read mode (write mode don't
490 * need this). If THP is not enabled, the pmd can't go away under the
491 * code even if MADV_DONTNEED runs, but if THP is enabled we need to
492 * run a pmd_trans_unstable before walking the ptes after
493 * split_huge_page_pmd returns (because it may have run when the pmd
494 * become null, but then a page fault can map in a THP and not a
495 * regular page).
496 */
497static inline int pmd_trans_unstable(pmd_t *pmd)
498{
499#ifdef CONFIG_TRANSPARENT_HUGEPAGE
500 return pmd_none_or_trans_huge_or_clear_bad(pmd);
501#else
502 return 0;
445#endif 503#endif
504}
505
506#endif /* CONFIG_MMU */
446 507
447#endif /* !__ASSEMBLY__ */ 508#endif /* !__ASSEMBLY__ */
448 509