summaryrefslogtreecommitdiff
path: root/Kernel/Heap
diff options
context:
space:
mode:
authorTom <tomut@yahoo.com>2020-12-30 17:00:49 -0700
committerAndreas Kling <kling@serenityos.org>2020-12-31 01:15:37 +0100
commit22250780ffa755c48597c4930d62dfdcbf99f37f (patch)
treeb0a0e9ca2e9c64494b7cb5461864b641ceab80c2 /Kernel/Heap
parent4f1db41a6ce2a4262eab024815072c2b1717bb38 (diff)
downloadserenity-22250780ffa755c48597c4930d62dfdcbf99f37f.zip
Kernel: Fix heap expansions deadlock
If a heap expansion is triggered by allocating from e.g. the RangeAllocator, which may be holding a spin lock, we cannot immediately allocate another block of backup memory, which could require the same locks to be acquired. So, defer allocating the backup memory Fixes #4675
Diffstat (limited to 'Kernel/Heap')
-rw-r--r--Kernel/Heap/kmalloc.cpp13
1 files changed, 12 insertions, 1 deletions
diff --git a/Kernel/Heap/kmalloc.cpp b/Kernel/Heap/kmalloc.cpp
index bb46edc4f4..33210beafd 100644
--- a/Kernel/Heap/kmalloc.cpp
+++ b/Kernel/Heap/kmalloc.cpp
@@ -52,6 +52,8 @@
static RecursiveSpinLock s_lock; // needs to be recursive because of dump_backtrace()
+static void kmalloc_allocate_backup_memory();
+
struct KmallocGlobalHeap {
struct ExpandGlobalHeap {
KmallocGlobalHeap& m_global_heap;
@@ -94,7 +96,11 @@ struct KmallocGlobalHeap {
// backup heap before returning. Otherwise we potentially lose
// the ability to expand the heap next time we get called.
ScopeGuard guard([&]() {
- m_global_heap.allocate_backup_memory();
+ // We may need to defer allocating backup memory because the
+ // heap expansion may have been triggered while holding some
+ // other spinlock. If the expansion happens to need the same
+ // spinlock we would deadlock. So, if we're in any lock, defer
+ Processor::current().deferred_call_queue(kmalloc_allocate_backup_memory);
});
// Now that we added our backup memory, check if the backup heap
@@ -197,6 +203,11 @@ bool g_dump_kmalloc_stacks;
static u8* s_next_eternal_ptr;
static u8* s_end_of_eternal_range;
+static void kmalloc_allocate_backup_memory()
+{
+ g_kmalloc_global->allocate_backup_memory();
+}
+
void kmalloc_enable_expand()
{
g_kmalloc_global->allocate_backup_memory();