@@ -678,30 +678,33 @@ done:
static void ipmmu_clear_pud(struct ipmmu_vmsa_device *mmu, pud_t *pud)
{
- /* Free the page table. */
pgtable_t table = pud_pgtable(*pud);
- __free_page(table);
/* Clear the PUD. */
*pud = __pud(0);
ipmmu_flush_pgtable(mmu, pud, sizeof(*pud));
+
+ /* Free the page table. */
+ __free_page(table);
}
static void ipmmu_clear_pmd(struct ipmmu_vmsa_device *mmu, pud_t *pud,
pmd_t *pmd)
{
+ pmd_t pmdval = *pmd;
unsigned int i;
- /* Free the page table. */
- if (pmd_table(*pmd)) {
- pgtable_t table = pmd_pgtable(*pmd);
- __free_page(table);
- }
-
/* Clear the PMD. */
*pmd = __pmd(0);
ipmmu_flush_pgtable(mmu, pmd, sizeof(*pmd));
+ /* Free the page table. */
+ if (pmd_table(pmdval)) {
+ pgtable_t table = pmd_pgtable(pmdval);
+
+ __free_page(table);
+ }
+
/* Check whether the PUD is still needed. */
pmd = pmd_offset(pud, 0);
for (i = 0; i < IPMMU_PTRS_PER_PMD; ++i) {
When clearing PUD or PMD entries the child page table (if any) is freed and the PUD or PMD entry is then cleared. This result in a small race condition window during which a free page table could be accessed by the IPMMU. Fix it by clearing and flushing the PUD or PMD entry before freeing the child page table. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> --- drivers/iommu/ipmmu-vmsa.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)