diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-09-11 04:28:57 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-09-11 04:29:53 -0400 |
commit | 50aa98bad056a17655864a4d71ebc32d95c629a7 (patch) | |
tree | bf8d22851d99583e2ea388766697bf64672d7926 /arch/s390/include | |
parent | c4de0c1a18237c2727dde8ad392e333539b0af3c (diff) |
[S390] fix recursive locking on page_table_lock
Suzuki Poulose reported the following recursive locking bug on s390:
Here is the stack trace : (see Appendix I for more info)
[<0000000000406ed6>] _spin_lock+0x52/0x94
[<0000000000103bde>] crst_table_free+0x14e/0x1a4
[<00000000001ba684>] __pmd_alloc+0x114/0x1ec
[<00000000001be8d0>] handle_mm_fault+0x2cc/0xb80
[<0000000000407d62>] do_dat_exception+0x2b6/0x3a0
[<0000000000114f8c>] sysc_return+0x0/0x8
[<00000200001642b2>] 0x200001642b2
The page_table_lock is already acquired in __pmd_alloc (mm/memory.c) and
it tries to populate the pud/pgd with a new pmd allocated. If another
thread populates it before we get a chance, we free the pmd using
pmd_free().
On s390x, pmd_free(even pud_free ) is #defined to crst_table_free(),
which acquires the page_table_lock to protect the crst_table index updates.
Hence this ends up in a recursive locking of the page_table_lock.
The solution suggested by Dave Hansen is to use a new spin lock in the mmu
context to protect the access to the crst_list and the pgtable_list.
Reported-by: Suzuki Poulose <suzuki@in.ibm.com>
Cc: Dave Hansen <dave@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/include')
-rw-r--r-- | arch/s390/include/asm/mmu.h | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/pgalloc.h | 1 |
2 files changed, 2 insertions, 0 deletions
diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h index 3b59216e6284..03be99919d62 100644 --- a/arch/s390/include/asm/mmu.h +++ b/arch/s390/include/asm/mmu.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define __MMU_H | 2 | #define __MMU_H |
3 | 3 | ||
4 | typedef struct { | 4 | typedef struct { |
5 | spinlock_t list_lock; | ||
5 | struct list_head crst_list; | 6 | struct list_head crst_list; |
6 | struct list_head pgtable_list; | 7 | struct list_head pgtable_list; |
7 | unsigned long asce_bits; | 8 | unsigned long asce_bits; |
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index b2658b9220fe..ddad5903341c 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h | |||
@@ -140,6 +140,7 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) | |||
140 | 140 | ||
141 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) | 141 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) |
142 | { | 142 | { |
143 | spin_lock_init(&mm->context.list_lock); | ||
143 | INIT_LIST_HEAD(&mm->context.crst_list); | 144 | INIT_LIST_HEAD(&mm->context.crst_list); |
144 | INIT_LIST_HEAD(&mm->context.pgtable_list); | 145 | INIT_LIST_HEAD(&mm->context.pgtable_list); |
145 | return (pgd_t *) crst_table_alloc(mm, s390_noexec); | 146 | return (pgd_t *) crst_table_alloc(mm, s390_noexec); |