Skip to content

Commit b14d167

Browse files
48caakpm00
authored andcommitted
mm: add an explicit smp_wmb() to UFFDIO_CONTINUE
Users of UFFDIO_CONTINUE may reasonably assume that a write memory barrier is included as part of UFFDIO_CONTINUE. That is, a user may believe that all writes it has done to a page that it is now UFFDIO_CONTINUE'ing are guaranteed to be visible to anyone subsequently reading the page through the newly mapped virtual memory region. Today, such a user happens to be correct. mmget_not_zero(), for example, is called as part of UFFDIO_CONTINUE (and comes before any PTE updates), and it implicitly gives us a write barrier. To be resilient against future changes, include an explicit smp_wmb(). While we're at it, optimize the smp_wmb() that is already incidentally present for the HugeTLB case. Merely making a syscall does not generally imply the memory ordering constraints that we need (including on x86). Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: James Houghton <[email protected]> Reviewed-by: Peter Xu <[email protected]> Cc: Axel Rasmussen <[email protected]> Cc: Muchun Song <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent b555895 commit b14d167

File tree

2 files changed

+22
-4
lines changed

2 files changed

+22
-4
lines changed

mm/hugetlb.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6780,11 +6780,20 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,
67806780
}
67816781

67826782
/*
6783-
* The memory barrier inside __folio_mark_uptodate makes sure that
6784-
* preceding stores to the page contents become visible before
6785-
* the set_pte_at() write.
6783+
* If we just allocated a new page, we need a memory barrier to ensure
6784+
* that preceding stores to the page become visible before the
6785+
* set_pte_at() write. The memory barrier inside __folio_mark_uptodate
6786+
* is what we need.
6787+
*
6788+
* In the case where we have not allocated a new page (is_continue),
6789+
* the page must already be uptodate. UFFDIO_CONTINUE already includes
6790+
* an earlier smp_wmb() to ensure that prior stores will be visible
6791+
* before the set_pte_at() write.
67866792
*/
6787-
__folio_mark_uptodate(folio);
6793+
if (!is_continue)
6794+
__folio_mark_uptodate(folio);
6795+
else
6796+
WARN_ON_ONCE(!folio_test_uptodate(folio));
67886797

67896798
/* Add shared, newly allocated pages to the page cache. */
67906799
if (vm_shared && !is_continue) {

mm/userfaultfd.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,15 @@ ssize_t mfill_atomic_zeropage(struct userfaultfd_ctx *ctx,
845845
ssize_t mfill_atomic_continue(struct userfaultfd_ctx *ctx, unsigned long start,
846846
unsigned long len, uffd_flags_t flags)
847847
{
848+
849+
/*
850+
* A caller might reasonably assume that UFFDIO_CONTINUE contains an
851+
* smp_wmb() to ensure that any writes to the about-to-be-mapped page by
852+
* the thread doing the UFFDIO_CONTINUE are guaranteed to be visible to
853+
* subsequent loads from the page through the newly mapped address range.
854+
*/
855+
smp_wmb();
856+
848857
return mfill_atomic(ctx, start, 0, len,
849858
uffd_flags_set_mode(flags, MFILL_ATOMIC_CONTINUE));
850859
}

0 commit comments

Comments
 (0)