Skip to content

Commit 61d2d18

Browse files
mrutland-armwilldeacon
authored andcommitted
arm64: mm: don't acquire mutex when rewriting swapper
Since commit: 47546a1 ("arm64: mm: install KPTI nG mappings with MMU enabled)" ... when building with CONFIG_DEBUG_ATOMIC_SLEEP=y and booting under QEMU TCG with '-cpu max', there's a boot-time splat: | BUG: sleeping function called from invalid context at kernel/locking/mutex.c:580 | in_atomic(): 1, irqs_disabled(): 128, non_block: 0, pid: 15, name: migration/0 | preempt_count: 1, expected: 0 | RCU nest depth: 0, expected: 0 | no locks held by migration/0/15. | irq event stamp: 28 | hardirqs last enabled at (27): [<ffff8000091ed180>] _raw_spin_unlock_irq+0x3c/0x7c | hardirqs last disabled at (28): [<ffff8000081b8d74>] multi_cpu_stop+0x150/0x18c | softirqs last enabled at (0): [<ffff80000809a314>] copy_process+0x594/0x1964 | softirqs last disabled at (0): [<0000000000000000>] 0x0 | CPU: 0 PID: 15 Comm: migration/0 Not tainted 6.0.0-rc3-00002-g419b42ff7eef #3 | Hardware name: linux,dummy-virt (DT) | Stopper: multi_cpu_stop+0x0/0x18c <- stop_cpus.constprop.0+0xa0/0xfc | Call trace: | dump_backtrace.part.0+0xd0/0xe0 | show_stack+0x1c/0x5c | dump_stack_lvl+0x88/0xb4 | dump_stack+0x1c/0x38 | __might_resched+0x180/0x230 | __might_sleep+0x4c/0xa0 | __mutex_lock+0x5c/0x450 | mutex_lock_nested+0x30/0x40 | create_kpti_ng_temp_pgd+0x4fc/0x6d0 | kpti_install_ng_mappings+0x2b8/0x3b0 | cpu_enable_non_boot_scope_capabilities+0x7c/0xd0 | multi_cpu_stop+0xa0/0x18c | cpu_stopper_thread+0x88/0x11c | smpboot_thread_fn+0x1ec/0x290 | kthread+0x118/0x120 | ret_from_fork+0x10/0x20 Since commit: ee017ee ("arm64/mm: avoid fixmap race condition when create pud mapping") ... once the kernel leave the SYSTEM_BOOTING state, the fixmap pagetable entries are protected by the fixmap_lock mutex. The new KPTI rewrite code uses __create_pgd_mapping() to create a temporary pagetable. This happens in atomic context, after secondary CPUs are brought up and the kernel has left the SYSTEM_BOOTING state. Hence we try to acquire a mutex in atomic context, which is generally unsound (though benign in this case as the mutex should be free and all other CPUs are quiescent). This patch avoids the issue by pulling the mutex out of alloc_init_pud() and calling it at a higher level in the pagetable manipulation code. This allows it to be used without locking where one CPU is known to be in exclusive control of the machine, even after having left the SYSTEM_BOOTING state. Fixes: 47546a1 ("arm64: mm: install KPTI nG mappings with MMU enabled") Signed-off-by: Mark Rutland <[email protected]> Cc: Ard Biesheuvel <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Will Deacon <[email protected]> Reviewed-by: Ard Biesheuvel <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 3fe3fd5 commit 61d2d18

File tree

1 file changed

+18
-14
lines changed

1 file changed

+18
-14
lines changed

arch/arm64/mm/mmu.c

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -331,12 +331,6 @@ static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end,
331331
}
332332
BUG_ON(p4d_bad(p4d));
333333

334-
/*
335-
* No need for locking during early boot. And it doesn't work as
336-
* expected with KASLR enabled.
337-
*/
338-
if (system_state != SYSTEM_BOOTING)
339-
mutex_lock(&fixmap_lock);
340334
pudp = pud_set_fixmap_offset(p4dp, addr);
341335
do {
342336
pud_t old_pud = READ_ONCE(*pudp);
@@ -368,15 +362,13 @@ static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end,
368362
} while (pudp++, addr = next, addr != end);
369363

370364
pud_clear_fixmap();
371-
if (system_state != SYSTEM_BOOTING)
372-
mutex_unlock(&fixmap_lock);
373365
}
374366

375-
static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
376-
unsigned long virt, phys_addr_t size,
377-
pgprot_t prot,
378-
phys_addr_t (*pgtable_alloc)(int),
379-
int flags)
367+
static void __create_pgd_mapping_locked(pgd_t *pgdir, phys_addr_t phys,
368+
unsigned long virt, phys_addr_t size,
369+
pgprot_t prot,
370+
phys_addr_t (*pgtable_alloc)(int),
371+
int flags)
380372
{
381373
unsigned long addr, end, next;
382374
pgd_t *pgdp = pgd_offset_pgd(pgdir, virt);
@@ -400,8 +392,20 @@ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
400392
} while (pgdp++, addr = next, addr != end);
401393
}
402394

395+
static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
396+
unsigned long virt, phys_addr_t size,
397+
pgprot_t prot,
398+
phys_addr_t (*pgtable_alloc)(int),
399+
int flags)
400+
{
401+
mutex_lock(&fixmap_lock);
402+
__create_pgd_mapping_locked(pgdir, phys, virt, size, prot,
403+
pgtable_alloc, flags);
404+
mutex_unlock(&fixmap_lock);
405+
}
406+
403407
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
404-
extern __alias(__create_pgd_mapping)
408+
extern __alias(__create_pgd_mapping_locked)
405409
void create_kpti_ng_temp_pgd(pgd_t *pgdir, phys_addr_t phys, unsigned long virt,
406410
phys_addr_t size, pgprot_t prot,
407411
phys_addr_t (*pgtable_alloc)(int), int flags);

0 commit comments

Comments
 (0)