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.
This commit is contained in:
Justin Hibbits 2020-06-10 23:03:35 +00:00
parent 4149c6a3ec
commit ae672aa5e3

View File

@ -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) {