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
This commit is contained in:
Tom 2020-12-30 17:00:49 -07:00 committed by Andreas Kling
parent 4f1db41a6c
commit 22250780ff
Notes: sideshowbarker 2024-07-19 00:19:34 +09:00

View file

@ -52,6 +52,8 @@
static RecursiveSpinLock s_lock; // needs to be recursive because of dump_backtrace() static RecursiveSpinLock s_lock; // needs to be recursive because of dump_backtrace()
static void kmalloc_allocate_backup_memory();
struct KmallocGlobalHeap { struct KmallocGlobalHeap {
struct ExpandGlobalHeap { struct ExpandGlobalHeap {
KmallocGlobalHeap& m_global_heap; KmallocGlobalHeap& m_global_heap;
@ -94,7 +96,11 @@ struct KmallocGlobalHeap {
// backup heap before returning. Otherwise we potentially lose // backup heap before returning. Otherwise we potentially lose
// the ability to expand the heap next time we get called. // the ability to expand the heap next time we get called.
ScopeGuard guard([&]() { 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 // 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_next_eternal_ptr;
static u8* s_end_of_eternal_range; static u8* s_end_of_eternal_range;
static void kmalloc_allocate_backup_memory()
{
g_kmalloc_global->allocate_backup_memory();
}
void kmalloc_enable_expand() void kmalloc_enable_expand()
{ {
g_kmalloc_global->allocate_backup_memory(); g_kmalloc_global->allocate_backup_memory();