Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 499069e1 authored by Carsten Otte's avatar Carsten Otte Committed by Martin Schwidefsky
Browse files

[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: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarCarsten Otte <cotte@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent cc772456
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -696,6 +696,7 @@ void gmap_disable(struct gmap *gmap);
int gmap_map_segment(struct gmap *gmap, unsigned long from,
int gmap_map_segment(struct gmap *gmap, unsigned long from,
		     unsigned long to, unsigned long length);
		     unsigned long to, unsigned long length);
int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len);
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 *);
unsigned long gmap_fault(unsigned long address, struct gmap *);


/*
/*
+1 −1
Original line number Original line Diff line number Diff line
@@ -307,7 +307,7 @@ static inline int do_exception(struct pt_regs *regs, int access,


#ifdef CONFIG_PGSTE
#ifdef CONFIG_PGSTE
	if (test_tsk_thread_flag(current, TIF_SIE) && S390_lowcore.gmap) {
	if (test_tsk_thread_flag(current, TIF_SIE) && S390_lowcore.gmap) {
		address = gmap_fault(address,
		address = __gmap_fault(address,
				     (struct gmap *) S390_lowcore.gmap);
				     (struct gmap *) S390_lowcore.gmap);
		if (address == -EFAULT) {
		if (address == -EFAULT) {
			fault = VM_FAULT_BADMAP;
			fault = VM_FAULT_BADMAP;
+14 −1
Original line number Original line Diff line number Diff line
@@ -393,7 +393,10 @@ int gmap_map_segment(struct gmap *gmap, unsigned long from,
}
}
EXPORT_SYMBOL_GPL(gmap_map_segment);
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;
	unsigned long *table, vmaddr, segment;
	struct mm_struct *mm;
	struct mm_struct *mm;
@@ -461,7 +464,17 @@ unsigned long gmap_fault(unsigned long address, struct gmap *gmap)
		return vmaddr | (address & ~PMD_MASK);
		return vmaddr | (address & ~PMD_MASK);
	}
	}
	return -EFAULT;
	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);
EXPORT_SYMBOL_GPL(gmap_fault);