Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Carsten Otte and committed by
Martin Schwidefsky
499069e1 cc772456

+16 -2
+1
arch/s390/include/asm/pgtable.h
··· 696 696 int gmap_map_segment(struct gmap *gmap, unsigned long from, 697 697 unsigned long to, unsigned long length); 698 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 700 unsigned long gmap_fault(unsigned long address, struct gmap *); 700 701 701 702 /*
+1 -1
arch/s390/mm/fault.c
··· 307 307 308 308 #ifdef CONFIG_PGSTE 309 309 if (test_tsk_thread_flag(current, TIF_SIE) && S390_lowcore.gmap) { 310 - address = gmap_fault(address, 310 + address = __gmap_fault(address, 311 311 (struct gmap *) S390_lowcore.gmap); 312 312 if (address == -EFAULT) { 313 313 fault = VM_FAULT_BADMAP;
+14 -1
arch/s390/mm/pgtable.c
··· 393 393 } 394 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 401 unsigned long *table, vmaddr, segment; 399 402 struct mm_struct *mm; ··· 464 461 return vmaddr | (address & ~PMD_MASK); 465 462 } 466 463 return -EFAULT; 464 + } 467 465 466 + unsigned long gmap_fault(unsigned long address, struct gmap *gmap) 467 + { 468 + unsigned long rc; 469 + 470 + down_read(&gmap->mm->mmap_sem); 471 + rc = __gmap_fault(address, gmap); 472 + up_read(&gmap->mm->mmap_sem); 473 + 474 + return rc; 468 475 } 469 476 EXPORT_SYMBOL_GPL(gmap_fault); 470 477