提交 5e3c72c4 创建 作者: Austin Clements's avatar Austin Clements

Fix concurrent unmap/page fault in radix

Previously we just looked at whether the fauling VMA was deleted once we had the PTE lock, but that's not enough since a VMA can be partially deleted. Instead, we check the radix tree again after taking the PTE lock.
上级 6a5aee25
...@@ -243,6 +243,8 @@ struct radix_iterator { ...@@ -243,6 +243,8 @@ struct radix_iterator {
} }
radix_elem* operator*() const { radix_elem* operator*() const {
// XXX(austin) If we don't hold a lock on this element, it's
// possible it will morph into a node under us.
return path_[level_]->load().elem(); return path_[level_]->load().elem();
} }
......
...@@ -618,7 +618,12 @@ vmap::pagefault(uptr va, u32 err) ...@@ -618,7 +618,12 @@ vmap::pagefault(uptr va, u32 err)
} }
scoped_gc_epoch gc; scoped_gc_epoch gc;
#if VM_CRANGE
vma *m = lookup(va, 1); vma *m = lookup(va, 1);
#elif VM_RADIX
auto vma_it = vmas.find(va);
vma *m = static_cast<vma*>(*vma_it);
#endif
if (m == 0) if (m == 0)
return -1; return -1;
...@@ -659,10 +664,20 @@ vmap::pagefault(uptr va, u32 err) ...@@ -659,10 +664,20 @@ vmap::pagefault(uptr va, u32 err)
if (!cmpxch(pte, ptev, ptev | PTE_LOCK)) if (!cmpxch(pte, ptev, ptev | PTE_LOCK))
goto retry; goto retry;
#if VM_CRANGE
if (m->deleted()) { if (m->deleted()) {
*pte = ptev; *pte = ptev;
goto retry; goto retry;
} }
#elif VM_RADIX
// The radix tree is the source of truth about where the VMA is
// mapped. It might have been unmapped from this va but still be
// around, so we can't just test if it's deleted.
if (*vma_it != m) {
*pte = ptev;
goto retry;
}
#endif
if (m->va_type == COW) { if (m->va_type == COW) {
*pte = v2p(m->n->page[npg]) | PTE_P | PTE_U | PTE_COW; *pte = v2p(m->n->page[npg]) | PTE_P | PTE_U | PTE_COW;
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论