diff options
author | Christian Borntraeger <borntraeger@de.ibm.com> | 2011-12-27 14:25:47 +0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2011-12-27 14:25:48 +0400 |
commit | c86cce2a20207cbf2b3dfe97c985a1f5aa5d3798 (patch) | |
tree | ccfd31096b52184cf393a3da8813b7b728157c81 /arch/s390/mm | |
parent | 1fb810576f0e92451a5d46774bbd593946ca3526 (diff) | |
download | linux-c86cce2a20207cbf2b3dfe97c985a1f5aa5d3798.tar.xz |
[S390] kvm: fix sleeping function ... at mm/page_alloc.c:2260
commit cc772456ac9b460693492b3a3d89e8c81eda5874
[S390] fix list corruption in gmap reverse mapping
added a potential dead lock:
BUG: sleeping function called from invalid context at mm/page_alloc.c:2260
in_atomic(): 1, irqs_disabled(): 0, pid: 1108, name: qemu-system-s39
3 locks held by qemu-system-s39/1108:
#0: (&kvm->slots_lock){+.+.+.}, at: [<000003e004866542>] kvm_set_memory_region+0x3a/0x6c [kvm]
#1: (&mm->mmap_sem){++++++}, at: [<0000000000123790>] gmap_map_segment+0x9c/0x298
#2: (&(&mm->page_table_lock)->rlock){+.+.+.}, at: [<00000000001237a8>] gmap_map_segment+0xb4/0x298
CPU: 0 Not tainted 3.1.3 #45
Process qemu-system-s39 (pid: 1108, task: 00000004f8b3cb30, ksp: 00000004fd5978d0)
00000004fd5979a0 00000004fd597920 0000000000000002 0000000000000000
00000004fd5979c0 00000004fd597938 00000004fd597938 0000000000617e96
0000000000000000 00000004f8b3cf58 0000000000000000 0000000000000000
000000000000000d 000000000000000c 00000004fd597988 0000000000000000
0000000000000000 0000000000100a18 00000004fd597920 00000004fd597960
Call Trace:
([<0000000000100926>] show_trace+0xee/0x144)
[<0000000000131f3a>] __might_sleep+0x12a/0x158
[<0000000000217fb4>] __alloc_pages_nodemask+0x224/0xadc
[<0000000000123086>] gmap_alloc_table+0x46/0x114
[<000000000012395c>] gmap_map_segment+0x268/0x298
[<000003e00486b014>] kvm_arch_commit_memory_region+0x44/0x6c [kvm]
[<000003e004866414>] __kvm_set_memory_region+0x3b0/0x4a4 [kvm]
[<000003e004866554>] kvm_set_memory_region+0x4c/0x6c [kvm]
[<000003e004867c7a>] kvm_vm_ioctl+0x14a/0x314 [kvm]
[<0000000000292100>] do_vfs_ioctl+0x94/0x588
[<0000000000292688>] SyS_ioctl+0x94/0xac
[<000000000061e124>] sysc_noemu+0x22/0x28
[<000003fffcd5e7ca>] 0x3fffcd5e7ca
3 locks held by qemu-system-s39/1108:
#0: (&kvm->slots_lock){+.+.+.}, at: [<000003e004866542>] kvm_set_memory_region+0x3a/0x6c [kvm]
#1: (&mm->mmap_sem){++++++}, at: [<0000000000123790>] gmap_map_segment+0x9c/0x298
#2: (&(&mm->page_table_lock)->rlock){+.+.+.}, at: [<00000000001237a8>] gmap_map_segment+0xb4/0x298
Fix this by freeing the lock on the alloc path. This is ok, since the
gmap table is never freed until we call gmap_free, so the table we are
walking cannot go.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/mm')
-rw-r--r-- | arch/s390/mm/pgtable.c | 3 |
1 files changed, 3 insertions, 0 deletions
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 301c84d3b542..dc2269f1821c 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -267,7 +267,10 @@ static int gmap_alloc_table(struct gmap *gmap, struct page *page; unsigned long *new; + /* since we dont free the gmap table until gmap_free we can unlock */ + spin_unlock(&gmap->mm->page_table_lock); page = alloc_pages(GFP_KERNEL, ALLOC_ORDER); + spin_lock(&gmap->mm->page_table_lock); if (!page) return -ENOMEM; new = (unsigned long *) page_to_phys(page); |