Implement pud_free_pmd_page() and pmd_free_pte_page() on x86, which clear a given pud/pmd entry and free up lower level page table(s). The address range associated with the pud/pmd entry must have been purged by INVLPG.
Unified · Split
| @@ -712,7 +712,22 @@ int pmd_clear_huge(pmd_t *pmd) · 711 unmodified lines | ||
| 712 | 712 | */ |
| 713 | 713 | int pud_free_pmd_page(pud_t *pud) |
| 714 | 714 | { |
| 715 | − return pud_none(*pud); | |
| 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; | |
| 716 | 731 | } |
| 717 | 732 | |
| 718 | 733 | /** |
| @@ -724,6 +739,15 @@ int pud_free_pmd_page(pud_t *pud) · 5 unmodified lines | ||
| 724 | 739 | */ |
| 725 | 740 | int pmd_free_pte_page(pmd_t *pmd) |
| 726 | 741 | { |
| 727 | − return pmd_none(*pmd); | |
| 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; | |
| 728 | 752 | } |
| 729 | 753 | #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */ |