summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLokesh Gidra <lokeshgidra@google.com>2024-03-08 10:04:39 -0800
committerJhih-Chen Huang <jhihchen@google.com>2024-03-27 05:53:51 +0000
commit91f8e0be1b13384eb22c9d2069cb142b785fa2ed (patch)
treee8018c535b10275507d91302be5c108e4eb784bf
parent144d37ff1bd258c944ba861b445485738d5ecf4b (diff)
downloadcommon-91f8e0be1b13384eb22c9d2069cb142b785fa2ed.tar.gz
ANDROID: userfaultfd: add MMAP_TRYLOCK mode for COPY/ZEROPAGE
In case mmap_lock is contended, it is possible that userspace can spend time performing other tasks rather than waiting in uninterruptible-sleep state for the lock to become available. Even if no other task is available, it is better to yield or sleep rather than adding contention to already contended lock. We introduce MMAP_TRYLOCK mode so that when possible, userspace can request to use mmap_read_trylock(), returning -EAGAIN if and when it fails. Bug: 320478828 Bug: 331529936 Signed-off-by: Lokesh Gidra <lokeshgidra@google.com> (cherry picked from https://android-review.googlesource.com/q/commit:3673533a09b6998bd0e3eafd14c1d6457bc23529) Merged-In: I2d196fd317e054af03dbd35ac1b0c7634cb370dc Change-Id: I2d196fd317e054af03dbd35ac1b0c7634cb370dc
-rw-r--r--fs/userfaultfd.c9
-rw-r--r--include/linux/userfaultfd_k.h8
-rw-r--r--include/uapi/linux/userfaultfd.h2
-rw-r--r--mm/userfaultfd.c13
4 files changed, 22 insertions, 10 deletions
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index b4c24753ec19..f8e138d903a2 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -1764,7 +1764,9 @@ static int userfaultfd_copy(struct userfaultfd_ctx *ctx,
ret = -EINVAL;
if (uffdio_copy.src + uffdio_copy.len <= uffdio_copy.src)
goto out;
- if (uffdio_copy.mode & ~(UFFDIO_COPY_MODE_DONTWAKE|UFFDIO_COPY_MODE_WP))
+ if (uffdio_copy.mode & ~(UFFDIO_COPY_MODE_DONTWAKE|
+ UFFDIO_COPY_MODE_WP|
+ UFFDIO_COPY_MODE_MMAP_TRYLOCK))
goto out;
if (mmget_not_zero(ctx->mm)) {
ret = mcopy_atomic(ctx->mm, uffdio_copy.dst, uffdio_copy.src,
@@ -1815,13 +1817,14 @@ static int userfaultfd_zeropage(struct userfaultfd_ctx *ctx,
if (ret)
goto out;
ret = -EINVAL;
- if (uffdio_zeropage.mode & ~UFFDIO_ZEROPAGE_MODE_DONTWAKE)
+ if (uffdio_zeropage.mode & ~(UFFDIO_ZEROPAGE_MODE_DONTWAKE|
+ UFFDIO_ZEROPAGE_MODE_MMAP_TRYLOCK))
goto out;
if (mmget_not_zero(ctx->mm)) {
ret = mfill_zeropage(ctx->mm, uffdio_zeropage.range.start,
uffdio_zeropage.range.len,
- &ctx->mmap_changing);
+ &ctx->mmap_changing, uffdio_zeropage.mode);
mmput(ctx->mm);
} else {
return -ESRCH;
diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index 8ea2827a4eba..14fdc2dd1532 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -33,6 +33,9 @@
#define UFFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK)
#define UFFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS)
+static_assert(UFFDIO_ZEROPAGE_MODE_MMAP_TRYLOCK == UFFDIO_COPY_MODE_MMAP_TRYLOCK);
+#define UFFDIO_MODE_MMAP_TRYLOCK UFFDIO_COPY_MODE_MMAP_TRYLOCK
+
extern int sysctl_unprivileged_userfaultfd;
extern vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason);
@@ -65,9 +68,8 @@ extern ssize_t mcopy_atomic(struct mm_struct *dst_mm, unsigned long dst_start,
unsigned long src_start, unsigned long len,
atomic_t *mmap_changing, __u64 mode);
extern ssize_t mfill_zeropage(struct mm_struct *dst_mm,
- unsigned long dst_start,
- unsigned long len,
- atomic_t *mmap_changing);
+ unsigned long dst_start, unsigned long len,
+ atomic_t *mmap_changing, __u64 mode);
extern ssize_t mcopy_continue(struct mm_struct *dst_mm, unsigned long dst_start,
unsigned long len, atomic_t *mmap_changing);
extern int mwriteprotect_range(struct mm_struct *dst_mm,
diff --git a/include/uapi/linux/userfaultfd.h b/include/uapi/linux/userfaultfd.h
index 05b31d60acf6..a13fa043c092 100644
--- a/include/uapi/linux/userfaultfd.h
+++ b/include/uapi/linux/userfaultfd.h
@@ -237,6 +237,7 @@ struct uffdio_copy {
* according to the uffdio_register.ioctls.
*/
#define UFFDIO_COPY_MODE_WP ((__u64)1<<1)
+#define UFFDIO_COPY_MODE_MMAP_TRYLOCK ((__u64)1<<63)
__u64 mode;
/*
@@ -249,6 +250,7 @@ struct uffdio_copy {
struct uffdio_zeropage {
struct uffdio_range range;
#define UFFDIO_ZEROPAGE_MODE_DONTWAKE ((__u64)1<<0)
+#define UFFDIO_ZEROPAGE_MODE_MMAP_TRYLOCK ((__u64)1<<63)
__u64 mode;
/*
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index d4175821dd29..522d88bd73ef 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -519,14 +519,19 @@ static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm,
copied = 0;
page = NULL;
retry:
- mmap_read_lock(dst_mm);
+ err = -EAGAIN;
+ if (mode & UFFDIO_MODE_MMAP_TRYLOCK) {
+ if (!mmap_read_trylock(dst_mm))
+ goto out;
+ } else {
+ mmap_read_lock(dst_mm);
+ }
/*
* If memory mappings are changing because of non-cooperative
* operation (e.g. mremap) running in parallel, bail out and
* request the user to retry later
*/
- err = -EAGAIN;
if (mmap_changing && atomic_read(mmap_changing))
goto out_unlock;
@@ -668,10 +673,10 @@ ssize_t mcopy_atomic(struct mm_struct *dst_mm, unsigned long dst_start,
}
ssize_t mfill_zeropage(struct mm_struct *dst_mm, unsigned long start,
- unsigned long len, atomic_t *mmap_changing)
+ unsigned long len, atomic_t *mmap_changing, __u64 mode)
{
return __mcopy_atomic(dst_mm, start, 0, len, MCOPY_ATOMIC_ZEROPAGE,
- mmap_changing, 0);
+ mmap_changing, mode);
}
ssize_t mcopy_continue(struct mm_struct *dst_mm, unsigned long start,