Commit 4ec04321 authored by Matthew Wilcox (Oracle)'s avatar Matthew Wilcox (Oracle) Committed by Tong Tiangen
Browse files

mm: handle shared faults under the VMA lock

mainline inclusion
from mainline-v6.7-rc1
commit 4ed4379881aa62588aba6442a9f362a8cf7624e6
category: other
bugzilla: https://gitee.com/openeuler/kernel/issues/I8K7C7

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4ed4379881aa62588aba6442a9f362a8cf7624e6

--------------------------------

There are many implementations of ->fault and some of them depend on
mmap_lock being held.  All vm_ops that implement ->map_pages() end up
calling filemap_fault(), which I have audited to be sure it does not rely
on mmap_lock.  So (for now) key off ->map_pages existing as a flag to
indicate that it's safe to call ->fault while only holding the vma lock.

Link: https://lkml.kernel.org/r/20231006195318.4087158-4-willy@infradead.org


Signed-off-by: default avatarMatthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: default avatarSuren Baghdasaryan <surenb@google.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarTong Tiangen <tongtiangen@huawei.com>
parent 849b94c0
Loading
Loading
Loading
Loading
+18 −4
Original line number Diff line number Diff line
@@ -3044,6 +3044,21 @@ static inline void wp_page_reuse(struct vm_fault *vmf, struct folio *folio)
	count_vm_event(PGREUSE);
}

/*
 * We could add a bitflag somewhere, but for now, we know that all
 * vm_ops that have a ->map_pages have been audited and don't need
 * the mmap_lock to be held.
 */
static inline vm_fault_t vmf_can_call_fault(const struct vm_fault *vmf)
{
	struct vm_area_struct *vma = vmf->vma;

	if (vma->vm_ops->map_pages || !(vmf->flags & FAULT_FLAG_VMA_LOCK))
		return 0;
	vma_end_read(vma);
	return VM_FAULT_RETRY;
}

static vm_fault_t vmf_anon_prepare(struct vm_fault *vmf)
{
	struct vm_area_struct *vma = vmf->vma;
@@ -4655,10 +4670,9 @@ static vm_fault_t do_shared_fault(struct vm_fault *vmf)
	vm_fault_t ret, tmp;
	struct folio *folio;

	if (vmf->flags & FAULT_FLAG_VMA_LOCK) {
		vma_end_read(vma);
		return VM_FAULT_RETRY;
	}
	ret = vmf_can_call_fault(vmf);
	if (ret)
		return ret;

	ret = __do_fault(vmf);
	if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))