summaryrefslogtreecommitdiff
path: root/Kernel/Memory
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2021-08-09 02:21:04 +0200
committerAndreas Kling <kling@serenityos.org>2021-08-09 11:46:31 +0200
commit08b4d8f0de1b4274411e50c36d696b03fc8ccc25 (patch)
tree8b9610b0b99b47687a4a77abd0cad33b1243d950 /Kernel/Memory
parent95c8e421ae5c8771c48fba6e74b75528c67f45da (diff)
downloadserenity-08b4d8f0de1b4274411e50c36d696b03fc8ccc25.zip
Kernel: Fix deadlock in ~Memory::Region()
First off: unregister the region from MemoryManager before unmapping it. The order of operations here was a bit strange, presumably to avoid a situation where a fault would happen while unmapping, and the fault handler would find the MemoryManager region list in an invalid state. Unregistering it before unmapping sidesteps the whole problem, and allows us to easily fix another problem: a deadlock could occur due to inconsistent acquisition order (PageDirectory must come before MM.)
Diffstat (limited to 'Kernel/Memory')
-rw-r--r--Kernel/Memory/Region.cpp10
1 files changed, 4 insertions, 6 deletions
diff --git a/Kernel/Memory/Region.cpp b/Kernel/Memory/Region.cpp
index 648b20ba8a..aec04bc2d2 100644
--- a/Kernel/Memory/Region.cpp
+++ b/Kernel/Memory/Region.cpp
@@ -40,16 +40,14 @@ Region::~Region()
{
m_vmobject->remove_region(*this);
- // Make sure we disable interrupts so we don't get interrupted between unmapping and unregistering.
- // Unmapping the region will give the VM back to the VirtualRangeAllocator, so an interrupt handler would
- // find the address<->region mappings in an invalid state there.
- ScopedSpinLock lock(s_mm_lock);
+ MM.unregister_region(*this);
+
if (m_page_directory) {
+ ScopedSpinLock page_lock(m_page_directory->get_lock());
+ ScopedSpinLock lock(s_mm_lock);
unmap(ShouldDeallocateVirtualRange::Yes);
VERIFY(!m_page_directory);
}
-
- MM.unregister_region(*this);
}
OwnPtr<Region> Region::clone()