When waiting on PTE allocation, another thread could free the l2_dtable while

we're not looking at it.
Fix this by increasing l2->l2_occupancy before we try to alloc (and decrease
it if the allocation failed, or if another thread did a similar allocation).

Submitted by:	Kohji Okuno <okuno.kohji@jp.panasonic.com>
MFC after:	1 week
This commit is contained in:
cognet 2015-03-21 15:32:59 +00:00
parent 0f36a66254
commit 6ef314a10e
2 changed files with 6 additions and 2 deletions

View File

@ -758,6 +758,7 @@ pmap_alloc_l2_bucket(pmap_t pmap, vm_offset_t va)
* No L2 page table has been allocated. Chances are, this
* is because we just allocated the l2_dtable, above.
*/
l2->l2_occupancy++;
PMAP_UNLOCK(pmap);
rw_wunlock(&pvh_global_lock);
ptep = uma_zalloc(l2zone, M_NOWAIT);
@ -765,6 +766,7 @@ pmap_alloc_l2_bucket(pmap_t pmap, vm_offset_t va)
PMAP_LOCK(pmap);
if (l2b->l2b_kva != 0) {
/* We lost the race. */
l2->l2_occupancy--;
uma_zfree(l2zone, ptep);
return (l2b);
}
@ -775,6 +777,7 @@ pmap_alloc_l2_bucket(pmap_t pmap, vm_offset_t va)
* time. We may need to deallocate the l2_dtable
* if we allocated a new one above.
*/
l2->l2_occupancy--;
if (l2->l2_occupancy == 0) {
pmap->pm_l2[L2_IDX(l1idx)] = NULL;
uma_zfree(l2table_zone, l2);
@ -782,7 +785,6 @@ pmap_alloc_l2_bucket(pmap_t pmap, vm_offset_t va)
return (NULL);
}
l2->l2_occupancy++;
l2b->l2b_kva = ptep;
l2b->l2b_l1idx = l1idx;
}

View File

@ -878,6 +878,7 @@ pmap_alloc_l2_bucket(pmap_t pm, vm_offset_t va)
* No L2 page table has been allocated. Chances are, this
* is because we just allocated the l2_dtable, above.
*/
l2->l2_occupancy++;
PMAP_UNLOCK(pm);
rw_wunlock(&pvh_global_lock);
ptep = uma_zalloc(l2zone, M_NOWAIT);
@ -885,6 +886,7 @@ pmap_alloc_l2_bucket(pmap_t pm, vm_offset_t va)
PMAP_LOCK(pm);
if (l2b->l2b_kva != 0) {
/* We lost the race. */
l2->l2_occupancy--;
uma_zfree(l2zone, ptep);
return (l2b);
}
@ -895,6 +897,7 @@ pmap_alloc_l2_bucket(pmap_t pm, vm_offset_t va)
* time. We may need to deallocate the l2_dtable
* if we allocated a new one above.
*/
l2->l2_occupancy--;
if (l2->l2_occupancy == 0) {
pm->pm_l2[L2_IDX(l1idx)] = NULL;
uma_zfree(l2table_zone, l2);
@ -902,7 +905,6 @@ pmap_alloc_l2_bucket(pmap_t pm, vm_offset_t va)
return (NULL);
}
l2->l2_occupancy++;
l2b->l2b_kva = ptep;
l2b->l2b_l1idx = l1idx;
}