mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
userfaultfd: use per-vma locks in userfaultfd operations
All userfaultfd operations, except write-protect, opportunistically use per-vma locks to lock vmas. On failure, attempt again inside mmap_lock critical section. Write-protect operation requires mmap_lock as it iterates over multiple vmas. Link: https://lkml.kernel.org/r/20240215182756.3448972-5-lokeshgidra@google.com Signed-off-by: Lokesh Gidra <lokeshgidra@google.com> Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Axel Rasmussen <axelrasmussen@google.com> Cc: Brian Geffon <bgeffon@google.com> Cc: David Hildenbrand <david@redhat.com> Cc: Jann Horn <jannh@google.com> Cc: Kalesh Singh <kaleshsingh@google.com> Cc: Matthew Wilcox (Oracle) <willy@infradead.org> Cc: Mike Rapoport (IBM) <rppt@kernel.org> Cc: Nicolas Geoffray <ngeoffray@google.com> Cc: Peter Xu <peterx@redhat.com> Cc: Ryan Roberts <ryan.roberts@arm.com> Cc: Suren Baghdasaryan <surenb@google.com> Cc: Tim Murray <timmurray@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
committed by
Andrew Morton
parent
32af81af2f
commit
867a43a34f
@@ -2005,17 +2005,8 @@ static int userfaultfd_move(struct userfaultfd_ctx *ctx,
|
||||
return -EINVAL;
|
||||
|
||||
if (mmget_not_zero(mm)) {
|
||||
mmap_read_lock(mm);
|
||||
|
||||
/* Re-check after taking map_changing_lock */
|
||||
down_read(&ctx->map_changing_lock);
|
||||
if (likely(!atomic_read(&ctx->mmap_changing)))
|
||||
ret = move_pages(ctx, mm, uffdio_move.dst, uffdio_move.src,
|
||||
uffdio_move.len, uffdio_move.mode);
|
||||
else
|
||||
ret = -EAGAIN;
|
||||
up_read(&ctx->map_changing_lock);
|
||||
mmap_read_unlock(mm);
|
||||
ret = move_pages(ctx, uffdio_move.dst, uffdio_move.src,
|
||||
uffdio_move.len, uffdio_move.mode);
|
||||
mmput(mm);
|
||||
} else {
|
||||
return -ESRCH;
|
||||
|
||||
@@ -138,9 +138,8 @@ extern long uffd_wp_range(struct vm_area_struct *vma,
|
||||
/* move_pages */
|
||||
void double_pt_lock(spinlock_t *ptl1, spinlock_t *ptl2);
|
||||
void double_pt_unlock(spinlock_t *ptl1, spinlock_t *ptl2);
|
||||
ssize_t move_pages(struct userfaultfd_ctx *ctx, struct mm_struct *mm,
|
||||
unsigned long dst_start, unsigned long src_start,
|
||||
unsigned long len, __u64 flags);
|
||||
ssize_t move_pages(struct userfaultfd_ctx *ctx, unsigned long dst_start,
|
||||
unsigned long src_start, unsigned long len, __u64 flags);
|
||||
int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pmd_t dst_pmdval,
|
||||
struct vm_area_struct *dst_vma,
|
||||
struct vm_area_struct *src_vma,
|
||||
|
||||
@@ -2158,7 +2158,7 @@ unlock:
|
||||
|
||||
#ifdef CONFIG_USERFAULTFD
|
||||
/*
|
||||
* The PT lock for src_pmd and the mmap_lock for reading are held by
|
||||
* The PT lock for src_pmd and dst_vma/src_vma (for reading) are locked by
|
||||
* the caller, but it must return after releasing the page_table_lock.
|
||||
* Just move the page from src_pmd to dst_pmd if possible.
|
||||
* Return zero if succeeded in moving the page, -EAGAIN if it needs to be
|
||||
@@ -2181,7 +2181,8 @@ int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pm
|
||||
src_ptl = pmd_lockptr(mm, src_pmd);
|
||||
|
||||
lockdep_assert_held(src_ptl);
|
||||
mmap_assert_locked(mm);
|
||||
vma_assert_locked(src_vma);
|
||||
vma_assert_locked(dst_vma);
|
||||
|
||||
/* Sanity checks before the operation */
|
||||
if (WARN_ON_ONCE(!pmd_none(dst_pmdval)) || WARN_ON_ONCE(src_addr & ~HPAGE_PMD_MASK) ||
|
||||
|
||||
384
mm/userfaultfd.c
384
mm/userfaultfd.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user