diff options
Diffstat (limited to 'arch/x86/mm/pgtable.c')
-rw-r--r-- | arch/x86/mm/pgtable.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index 004abf9ebf12..34cda7e0551b 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c | |||
@@ -702,4 +702,52 @@ int pmd_clear_huge(pmd_t *pmd) | |||
702 | 702 | ||
703 | return 0; | 703 | return 0; |
704 | } | 704 | } |
705 | |||
706 | /** | ||
707 | * pud_free_pmd_page - Clear pud entry and free pmd page. | ||
708 | * @pud: Pointer to a PUD. | ||
709 | * | ||
710 | * Context: The pud range has been unmaped and TLB purged. | ||
711 | * Return: 1 if clearing the entry succeeded. 0 otherwise. | ||
712 | */ | ||
713 | int pud_free_pmd_page(pud_t *pud) | ||
714 | { | ||
715 | pmd_t *pmd; | ||
716 | int i; | ||
717 | |||
718 | if (pud_none(*pud)) | ||
719 | return 1; | ||
720 | |||
721 | pmd = (pmd_t *)pud_page_vaddr(*pud); | ||
722 | |||
723 | for (i = 0; i < PTRS_PER_PMD; i++) | ||
724 | if (!pmd_free_pte_page(&pmd[i])) | ||
725 | return 0; | ||
726 | |||
727 | pud_clear(pud); | ||
728 | free_page((unsigned long)pmd); | ||
729 | |||
730 | return 1; | ||
731 | } | ||
732 | |||
733 | /** | ||
734 | * pmd_free_pte_page - Clear pmd entry and free pte page. | ||
735 | * @pmd: Pointer to a PMD. | ||
736 | * | ||
737 | * Context: The pmd range has been unmaped and TLB purged. | ||
738 | * Return: 1 if clearing the entry succeeded. 0 otherwise. | ||
739 | */ | ||
740 | int pmd_free_pte_page(pmd_t *pmd) | ||
741 | { | ||
742 | pte_t *pte; | ||
743 | |||
744 | if (pmd_none(*pmd)) | ||
745 | return 1; | ||
746 | |||
747 | pte = (pte_t *)pmd_page_vaddr(*pmd); | ||
748 | pmd_clear(pmd); | ||
749 | free_page((unsigned long)pte); | ||
750 | |||
751 | return 1; | ||
752 | } | ||
705 | #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */ | 753 | #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */ |