diff options
| author | Carsten Otte <cotte@de.ibm.com> | 2011-10-30 10:17:02 -0400 |
|---|---|---|
| committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2011-10-30 10:16:45 -0400 |
| commit | 499069e1a421e2a85e76846c3237f00f1a5cb435 (patch) | |
| tree | 01cf74636909b06b5a986f97a90bf0af5040212d | |
| parent | cc772456ac9b460693492b3a3d89e8c81eda5874 (diff) | |
[S390] take mmap_sem when walking guest page table
gmap_fault needs to walk the guest page table. However, parts of
that may change if some other thread does munmap. In that case
gmap_unmap_notifier will also unmap the corresponding parts from
the guest page table. We need to take mmap_sem in order to serialize
these operations.
do_exception now calls __gmap_fault with mmap_sem held which does
not get exported to modules. The exported function, which is called
from KVM, now takes mmap_sem.
Reported-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Carsten Otte <cotte@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
| -rw-r--r-- | arch/s390/include/asm/pgtable.h | 1 | ||||
| -rw-r--r-- | arch/s390/mm/fault.c | 2 | ||||
| -rw-r--r-- | arch/s390/mm/pgtable.c | 15 |
3 files changed, 16 insertions, 2 deletions
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index c0cb794bb365..bc5f520f6f87 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
| @@ -696,6 +696,7 @@ void gmap_disable(struct gmap *gmap); | |||
| 696 | int gmap_map_segment(struct gmap *gmap, unsigned long from, | 696 | int gmap_map_segment(struct gmap *gmap, unsigned long from, |
| 697 | unsigned long to, unsigned long length); | 697 | unsigned long to, unsigned long length); |
| 698 | int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len); | 698 | int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len); |
| 699 | unsigned long __gmap_fault(unsigned long address, struct gmap *); | ||
| 699 | unsigned long gmap_fault(unsigned long address, struct gmap *); | 700 | unsigned long gmap_fault(unsigned long address, struct gmap *); |
| 700 | 701 | ||
| 701 | /* | 702 | /* |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index de3af0c053c0..1766def5bc3f 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
| @@ -307,7 +307,7 @@ static inline int do_exception(struct pt_regs *regs, int access, | |||
| 307 | 307 | ||
| 308 | #ifdef CONFIG_PGSTE | 308 | #ifdef CONFIG_PGSTE |
| 309 | if (test_tsk_thread_flag(current, TIF_SIE) && S390_lowcore.gmap) { | 309 | if (test_tsk_thread_flag(current, TIF_SIE) && S390_lowcore.gmap) { |
| 310 | address = gmap_fault(address, | 310 | address = __gmap_fault(address, |
| 311 | (struct gmap *) S390_lowcore.gmap); | 311 | (struct gmap *) S390_lowcore.gmap); |
| 312 | if (address == -EFAULT) { | 312 | if (address == -EFAULT) { |
| 313 | fault = VM_FAULT_BADMAP; | 313 | fault = VM_FAULT_BADMAP; |
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 96e85ac89269..441d34445d0e 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
| @@ -393,7 +393,10 @@ out_unmap: | |||
| 393 | } | 393 | } |
| 394 | EXPORT_SYMBOL_GPL(gmap_map_segment); | 394 | EXPORT_SYMBOL_GPL(gmap_map_segment); |
| 395 | 395 | ||
| 396 | unsigned long gmap_fault(unsigned long address, struct gmap *gmap) | 396 | /* |
| 397 | * this function is assumed to be called with mmap_sem held | ||
| 398 | */ | ||
| 399 | unsigned long __gmap_fault(unsigned long address, struct gmap *gmap) | ||
| 397 | { | 400 | { |
| 398 | unsigned long *table, vmaddr, segment; | 401 | unsigned long *table, vmaddr, segment; |
| 399 | struct mm_struct *mm; | 402 | struct mm_struct *mm; |
| @@ -461,7 +464,17 @@ unsigned long gmap_fault(unsigned long address, struct gmap *gmap) | |||
| 461 | return vmaddr | (address & ~PMD_MASK); | 464 | return vmaddr | (address & ~PMD_MASK); |
| 462 | } | 465 | } |
| 463 | return -EFAULT; | 466 | return -EFAULT; |
| 467 | } | ||
| 468 | |||
| 469 | unsigned long gmap_fault(unsigned long address, struct gmap *gmap) | ||
| 470 | { | ||
| 471 | unsigned long rc; | ||
| 472 | |||
| 473 | down_read(&gmap->mm->mmap_sem); | ||
| 474 | rc = __gmap_fault(address, gmap); | ||
| 475 | up_read(&gmap->mm->mmap_sem); | ||
| 464 | 476 | ||
| 477 | return rc; | ||
| 465 | } | 478 | } |
| 466 | EXPORT_SYMBOL_GPL(gmap_fault); | 479 | EXPORT_SYMBOL_GPL(gmap_fault); |
| 467 | 480 | ||
