[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>
This commit is contained in:
Родитель
cc772456ac
Коммит
499069e1a4
|
@ -696,6 +696,7 @@ void gmap_disable(struct gmap *gmap);
|
|||
int gmap_map_segment(struct gmap *gmap, unsigned long from,
|
||||
unsigned long to, unsigned long length);
|
||||
int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len);
|
||||
unsigned long __gmap_fault(unsigned long address, struct gmap *);
|
||||
unsigned long gmap_fault(unsigned long address, struct gmap *);
|
||||
|
||||
/*
|
||||
|
|
|
@ -307,7 +307,7 @@ static inline int do_exception(struct pt_regs *regs, int access,
|
|||
|
||||
#ifdef CONFIG_PGSTE
|
||||
if (test_tsk_thread_flag(current, TIF_SIE) && S390_lowcore.gmap) {
|
||||
address = gmap_fault(address,
|
||||
address = __gmap_fault(address,
|
||||
(struct gmap *) S390_lowcore.gmap);
|
||||
if (address == -EFAULT) {
|
||||
fault = VM_FAULT_BADMAP;
|
||||
|
|
|
@ -393,7 +393,10 @@ out_unmap:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(gmap_map_segment);
|
||||
|
||||
unsigned long gmap_fault(unsigned long address, struct gmap *gmap)
|
||||
/*
|
||||
* this function is assumed to be called with mmap_sem held
|
||||
*/
|
||||
unsigned long __gmap_fault(unsigned long address, struct gmap *gmap)
|
||||
{
|
||||
unsigned long *table, vmaddr, segment;
|
||||
struct mm_struct *mm;
|
||||
|
@ -461,7 +464,17 @@ unsigned long gmap_fault(unsigned long address, struct gmap *gmap)
|
|||
return vmaddr | (address & ~PMD_MASK);
|
||||
}
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
unsigned long gmap_fault(unsigned long address, struct gmap *gmap)
|
||||
{
|
||||
unsigned long rc;
|
||||
|
||||
down_read(&gmap->mm->mmap_sem);
|
||||
rc = __gmap_fault(address, gmap);
|
||||
up_read(&gmap->mm->mmap_sem);
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gmap_fault);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче