From 58d5d0d8dd52cbca988af24b5692a20b00285543 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 6 Feb 2008 22:39:45 +0100 Subject: x86: fix deadlock, make pgd_lock irq-safe lockdep just caught this one: ================================= [ INFO: inconsistent lock state ] 2.6.24 #38 --------------------------------- inconsistent {in-softirq-W} -> {softirq-on-W} usage. swapper/1 [HC0[0]:SC0[0]:HE1:SE1] takes: (pgd_lock){-+..}, at: [] mm_init+0x1da/0x250 {in-softirq-W} state was registered at: [] 0xffffffffffffffff irq event stamp: 394559 hardirqs last enabled at (394559): [] get_page_from_freelist+0x30a/0x4c0 hardirqs last disabled at (394558): [] get_page_from_freelist+0x125/0x4c0 softirqs last enabled at (393952): [] __do_softirq+0xce/0xe0 softirqs last disabled at (393945): [] call_softirq+0x1c/0x30 other info that might help us debug this: no locks held by swapper/1. stack backtrace: Pid: 1, comm: swapper Not tainted 2.6.24 #38 Call Trace: [] print_usage_bug+0x18b/0x190 [] mark_lock+0x53d/0x560 [] __lock_acquire+0x3ca/0xed0 [] lock_acquire+0xa8/0xe0 [] ? mm_init+0x1da/0x250 [] _spin_lock+0x30/0x70 [] mm_init+0x1da/0x250 [] mm_alloc+0x39/0x50 [] bprm_mm_init+0x2a/0x1a0 [] do_execve+0x7b/0x220 [] sys_execve+0x46/0x70 [] kernel_execve+0x64/0xd0 [] ? _stext+0x1e/0x20 [] init_post+0x9a/0xf0 [] ? trace_hardirqs_on_thunk+0x35/0x3a [] ? trace_hardirqs_on+0xba/0xd0 [] ? child_rip+0xa/0x12 [] ? restore_args+0x0/0x44 [] ? child_rip+0x0/0x12 turns out that pgd_lock has been used on 64-bit x86 in an irq-unsafe way for almost two years, since commit 8c914cb704a11460e. Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- include/asm-x86/pgalloc_64.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'include/asm-x86') diff --git a/include/asm-x86/pgalloc_64.h b/include/asm-x86/pgalloc_64.h index 315314ce4bf..4f6220db22b 100644 --- a/include/asm-x86/pgalloc_64.h +++ b/include/asm-x86/pgalloc_64.h @@ -42,19 +42,21 @@ static inline void pud_free(struct mm_struct *mm, pud_t *pud) static inline void pgd_list_add(pgd_t *pgd) { struct page *page = virt_to_page(pgd); + unsigned long flags; - spin_lock(&pgd_lock); + spin_lock_irqsave(&pgd_lock, flags); list_add(&page->lru, &pgd_list); - spin_unlock(&pgd_lock); + spin_unlock_irqrestore(&pgd_lock, flags); } static inline void pgd_list_del(pgd_t *pgd) { struct page *page = virt_to_page(pgd); + unsigned long flags; - spin_lock(&pgd_lock); + spin_lock_irqsave(&pgd_lock, flags); list_del(&page->lru); - spin_unlock(&pgd_lock); + spin_unlock_irqrestore(&pgd_lock, flags); } static inline pgd_t *pgd_alloc(struct mm_struct *mm) -- cgit v1.2.3