From ae672aa5e38b87e955bfdb9b6f9586d261c91cc5 Mon Sep 17 00:00:00 2001 From: Justin Hibbits Date: Wed, 10 Jun 2020 23:03:35 +0000 Subject: [PATCH] powerpc/pmap: Fix pte_find_next() iterators for booke64 pmap After r361988 fixed the reference count leak on booke64, it became possible for an iteration somewhere in the middle of a page to become stale, with the page vanishing (correctly) due to all PTEs on that page going away. pte_find_next() would start at that iterator, and move along 'higher' order directory pages until it finds a valid one, without zeroing out the lower order pages. For instance: /* Find next pte at or above 0x10002000. */ pte = pte_find_next(pmap, &(0x10002000)); pte_remove(pmap, pte); /* This pte was the last reference in the page table page, page is * gone. */ pte = pte_find_next(pmap, 0x10002000); /* pte_find_next will see 0x10002000's page is gone, and jump to the * next one, but starting iteration at the '0x2000' slot, skipping * 0x0000 and 0x1000. */ This caused some processes, like git, to trip the KASSERT() in pmap_release(). Fix this by zeroing all lower order iterators at each level. --- sys/powerpc/booke/pmap_64.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sys/powerpc/booke/pmap_64.c b/sys/powerpc/booke/pmap_64.c index 6845baa30996..18aaf918f9d2 100644 --- a/sys/powerpc/booke/pmap_64.c +++ b/sys/powerpc/booke/pmap_64.c @@ -220,12 +220,13 @@ pte_find_next(pmap_t pmap, vm_offset_t *pva) k = PDIR_IDX(va); l = PTBL_IDX(va); pm_root = pmap->pm_root; + /* truncate the VA for later. */ va &= ~((1UL << (PG_ROOT_H + 1)) - 1); - for (; i < PG_ROOT_NENTRIES; i++, j = 0) { + for (; i < PG_ROOT_NENTRIES; i++, j = 0, k = 0, l = 0) { if (pm_root[i] == 0) continue; - for (; j < PDIR_L1_NENTRIES; j++, k = 0) { + for (; j < PDIR_L1_NENTRIES; j++, k = 0, l = 0) { if (pm_root[i][j] == 0) continue; for (; k < PDIR_NENTRIES; k++, l = 0) {