From: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: Peter Xu <peterx@redhat.com>,
Alexander Viro <viro@zeniv.linux.org.uk>,
Christian Brauner <brauner@kernel.org>, Jan Kara <jack@suse.cz>,
"Liam R . Howlett" <Liam.Howlett@oracle.com>,
Vlastimil Babka <vbabka@suse.cz>, Jann Horn <jannh@google.com>,
Pedro Falcato <pfalcato@suse.de>, Rik van Riel <riel@surriel.com>,
linux-mm@kvack.org, linux-fsdevel@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org
Subject: [PATCH v3 05/10] mm/mremap: use an explicit uffd failure path for mremap
Date: Fri, 11 Jul 2025 12:38:19 +0100 [thread overview]
Message-ID: <255f9604d3973f85b7d7fbcca396cbb6841a676a.1752232673.git.lorenzo.stoakes@oracle.com> (raw)
In-Reply-To: <cover.1752232673.git.lorenzo.stoakes@oracle.com>
Right now it appears that the code is relying upon the returned destination
address having bits outside PAGE_MASK to indicate whether an error value is
specified, and decrementing the increased refcount on the uffd ctx if so.
This is not a safe means of determining an error value, so instead, be
specific. It makes far more sense to do so in a dedicated error path, so
add mremap_userfaultfd_fail() for this purpose and use this when an error
arises.
A vm_userfaultfd_ctx is not established until we are at the point where
mremap_userfaultfd_prep() is invoked in copy_vma_and_data(), so this is a
no-op until this happens.
That is - uffd remap notification only occurs if the VMA is actually moved
- at which point a UFFD_EVENT_REMAP event is raised.
No errors can occur after this point currently, though it's certainly not
guaranteed this will always remain the case, and we mustn't rely on this.
However, the reason for needing to handle this case is that, when an error
arises on a VMA move at the point of adjusting page tables, we revert this
operation, and propagate the error.
At this point, it is not correct to raise a uffd remap event, and we must
handle it.
This refactoring makes it abundantly clear what we are doing.
We assume vrm->new_addr is always valid, which a prior change made the case
even for mremap() invocations which don't move the VMA, however given no
uffd context would be set up in this case it's immaterial to this change
anyway.
No functional change intended.
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Vlastimil Babka <vbabka@suse.cz>
---
fs/userfaultfd.c | 15 ++++++++++-----
include/linux/userfaultfd_k.h | 5 +++++
mm/mremap.c | 16 ++++++++++++----
3 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index 2a644aa1a510..54c6cc7fe9c6 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -750,11 +750,6 @@ void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *vm_ctx,
if (!ctx)
return;
- if (to & ~PAGE_MASK) {
- userfaultfd_ctx_put(ctx);
- return;
- }
-
msg_init(&ewq.msg);
ewq.msg.event = UFFD_EVENT_REMAP;
@@ -765,6 +760,16 @@ void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *vm_ctx,
userfaultfd_event_wait_completion(ctx, &ewq);
}
+void mremap_userfaultfd_fail(struct vm_userfaultfd_ctx *vm_ctx)
+{
+ struct userfaultfd_ctx *ctx = vm_ctx->ctx;
+
+ if (!ctx)
+ return;
+
+ userfaultfd_ctx_put(ctx);
+}
+
bool userfaultfd_remove(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index df85330bcfa6..c0e716aec26a 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -259,6 +259,7 @@ extern void mremap_userfaultfd_prep(struct vm_area_struct *,
extern void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *,
unsigned long from, unsigned long to,
unsigned long len);
+void mremap_userfaultfd_fail(struct vm_userfaultfd_ctx *);
extern bool userfaultfd_remove(struct vm_area_struct *vma,
unsigned long start,
@@ -371,6 +372,10 @@ static inline void mremap_userfaultfd_complete(struct vm_userfaultfd_ctx *ctx,
{
}
+static inline void mremap_userfaultfd_fail(struct vm_userfaultfd_ctx *ctx)
+{
+}
+
static inline bool userfaultfd_remove(struct vm_area_struct *vma,
unsigned long start,
unsigned long end)
diff --git a/mm/mremap.c b/mm/mremap.c
index 87cab223f2bb..b2ee95182b36 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -1731,12 +1731,17 @@ static int check_prep_vma(struct vma_remap_struct *vrm)
return 0;
}
-static void notify_uffd(struct vma_remap_struct *vrm, unsigned long to)
+static void notify_uffd(struct vma_remap_struct *vrm, bool failed)
{
struct mm_struct *mm = current->mm;
+ /* Regardless of success/failure, we always notify of any unmaps. */
userfaultfd_unmap_complete(mm, vrm->uf_unmap_early);
- mremap_userfaultfd_complete(vrm->uf, vrm->addr, to, vrm->old_len);
+ if (failed)
+ mremap_userfaultfd_fail(vrm->uf);
+ else
+ mremap_userfaultfd_complete(vrm->uf, vrm->addr,
+ vrm->new_addr, vrm->old_len);
userfaultfd_unmap_complete(mm, vrm->uf_unmap);
}
@@ -1744,6 +1749,7 @@ static unsigned long do_mremap(struct vma_remap_struct *vrm)
{
struct mm_struct *mm = current->mm;
unsigned long res;
+ bool failed;
vrm->old_len = PAGE_ALIGN(vrm->old_len);
vrm->new_len = PAGE_ALIGN(vrm->new_len);
@@ -1765,13 +1771,15 @@ static unsigned long do_mremap(struct vma_remap_struct *vrm)
res = vrm_implies_new_addr(vrm) ? mremap_to(vrm) : mremap_at(vrm);
out:
+ failed = IS_ERR_VALUE(res);
+
if (vrm->mmap_locked)
mmap_write_unlock(mm);
- if (!IS_ERR_VALUE(res) && vrm->mlocked && vrm->new_len > vrm->old_len)
+ if (!failed && vrm->mlocked && vrm->new_len > vrm->old_len)
mm_populate(vrm->new_addr + vrm->old_len, vrm->delta);
- notify_uffd(vrm, res);
+ notify_uffd(vrm, failed);
return res;
}
--
2.50.0
next prev parent reply other threads:[~2025-07-11 11:39 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-11 11:38 [PATCH v3 00/10] mm/mremap: permit mremap() move of multiple VMAs Lorenzo Stoakes
2025-07-11 11:38 ` [PATCH v3 01/10] mm/mremap: perform some simple cleanups Lorenzo Stoakes
2025-07-11 11:38 ` [PATCH v3 02/10] mm/mremap: refactor initial parameter sanity checks Lorenzo Stoakes
2025-07-11 11:38 ` [PATCH v3 03/10] mm/mremap: put VMA check and prep logic into helper function Lorenzo Stoakes
2025-07-11 11:38 ` [PATCH v3 04/10] mm/mremap: cleanup post-processing stage of mremap Lorenzo Stoakes
2025-07-11 11:38 ` Lorenzo Stoakes [this message]
2025-07-11 11:38 ` [PATCH v3 06/10] mm/mremap: check remap conditions earlier Lorenzo Stoakes
2025-07-11 11:38 ` [PATCH v3 07/10] mm/mremap: move remap_is_valid() into check_prep_vma() Lorenzo Stoakes
2025-07-11 11:38 ` [PATCH v3 08/10] mm/mremap: clean up mlock populate behaviour Lorenzo Stoakes
2025-07-11 11:38 ` [PATCH v3 09/10] mm/mremap: permit mremap() move of multiple VMAs Lorenzo Stoakes
2025-07-11 13:34 ` Vlastimil Babka
2025-07-11 13:49 ` Lorenzo Stoakes
2025-07-11 14:14 ` Lorenzo Stoakes
2025-07-16 19:36 ` Lorenzo Stoakes
2025-07-25 17:11 ` Jann Horn
2025-07-25 17:27 ` Lorenzo Stoakes
2025-07-25 19:10 ` Jann Horn
2025-07-25 19:59 ` Lorenzo Stoakes
2025-07-11 11:38 ` [PATCH v3 10/10] tools/testing/selftests: extend mremap_test to test multi-VMA mremap Lorenzo Stoakes
2025-07-11 13:45 ` [PATCH v3 00/10] mm/mremap: permit mremap() move of multiple VMAs Lorenzo Stoakes
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=255f9604d3973f85b7d7fbcca396cbb6841a676a.1752232673.git.lorenzo.stoakes@oracle.com \
--to=lorenzo.stoakes@oracle.com \
--cc=Liam.Howlett@oracle.com \
--cc=akpm@linux-foundation.org \
--cc=brauner@kernel.org \
--cc=jack@suse.cz \
--cc=jannh@google.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=peterx@redhat.com \
--cc=pfalcato@suse.de \
--cc=riel@surriel.com \
--cc=vbabka@suse.cz \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox