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)  	return 0;  } + +/** + * pud_free_pmd_page - Clear pud entry and free pmd page. + * @pud: Pointer to a PUD. + * + * Context: The pud range has been unmaped and TLB purged. + * Return: 1 if clearing the entry succeeded. 0 otherwise. + */ +int pud_free_pmd_page(pud_t *pud) +{ +	pmd_t *pmd; +	int i; + +	if (pud_none(*pud)) +		return 1; + +	pmd = (pmd_t *)pud_page_vaddr(*pud); + +	for (i = 0; i < PTRS_PER_PMD; i++) +		if (!pmd_free_pte_page(&pmd[i])) +			return 0; + +	pud_clear(pud); +	free_page((unsigned long)pmd); + +	return 1; +} + +/** + * pmd_free_pte_page - Clear pmd entry and free pte page. + * @pmd: Pointer to a PMD. + * + * Context: The pmd range has been unmaped and TLB purged. + * Return: 1 if clearing the entry succeeded. 0 otherwise. + */ +int pmd_free_pte_page(pmd_t *pmd) +{ +	pte_t *pte; + +	if (pmd_none(*pmd)) +		return 1; + +	pte = (pte_t *)pmd_page_vaddr(*pmd); +	pmd_clear(pmd); +	free_page((unsigned long)pte); + +	return 1; +}  #endif	/* CONFIG_HAVE_ARCH_HUGE_VMAP */  | 
