userfaultfd: change mmap_changing to atomic
Patch series "userfaultfd: minor bug fixes".
Three unrelated bug fixes. The first two addresses possible issues (not
too theoretical ones), but I did not encounter them in practice.
The third patch addresses a test bug that causes the test to fail on my
system. It has been sent before as part of a bigger RFC.
This patch (of 3):
mmap_changing is currently a boolean variable, which is set and cleared
without any lock that protects against concurrent modifications.
mmap_changing is supposed to mark whether userfaultfd page-faults handling
should be retried since mappings are undergoing a change. However,
concurrent calls, for instance to madvise(MADV_DONTNEED), might cause
mmap_changing to be false, although the remove event was still not read
(hence acknowledged) by the user.
Change mmap_changing to atomic_t and increase/decrease appropriately. Add
a debug assertion to see whether mmap_changing is negative.
Link: https://lkml.kernel.org/r/20210808020724.1022515-1-namit@vmware.com
Link: https://lkml.kernel.org/r/20210808020724.1022515-2-namit@vmware.com
Fixes: df2cc96e77 ("userfaultfd: prevent non-cooperative events vs mcopy_atomic races")
Signed-off-by: Nadav Amit <namit@vmware.com>
Cc: Mike Rapoport <rppt@linux.vnet.ibm.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Axel Rasmussen <axelrasmussen@google.com>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
committed by
Linus Torvalds
parent
09a26e8327
commit
a759a909d4
@@ -483,7 +483,7 @@ static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm,
|
||||
unsigned long src_start,
|
||||
unsigned long len,
|
||||
enum mcopy_atomic_mode mcopy_mode,
|
||||
bool *mmap_changing,
|
||||
atomic_t *mmap_changing,
|
||||
__u64 mode)
|
||||
{
|
||||
struct vm_area_struct *dst_vma;
|
||||
@@ -517,7 +517,7 @@ retry:
|
||||
* request the user to retry later
|
||||
*/
|
||||
err = -EAGAIN;
|
||||
if (mmap_changing && READ_ONCE(*mmap_changing))
|
||||
if (mmap_changing && atomic_read(mmap_changing))
|
||||
goto out_unlock;
|
||||
|
||||
/*
|
||||
@@ -650,28 +650,29 @@ out:
|
||||
|
||||
ssize_t mcopy_atomic(struct mm_struct *dst_mm, unsigned long dst_start,
|
||||
unsigned long src_start, unsigned long len,
|
||||
bool *mmap_changing, __u64 mode)
|
||||
atomic_t *mmap_changing, __u64 mode)
|
||||
{
|
||||
return __mcopy_atomic(dst_mm, dst_start, src_start, len,
|
||||
MCOPY_ATOMIC_NORMAL, mmap_changing, mode);
|
||||
}
|
||||
|
||||
ssize_t mfill_zeropage(struct mm_struct *dst_mm, unsigned long start,
|
||||
unsigned long len, bool *mmap_changing)
|
||||
unsigned long len, atomic_t *mmap_changing)
|
||||
{
|
||||
return __mcopy_atomic(dst_mm, start, 0, len, MCOPY_ATOMIC_ZEROPAGE,
|
||||
mmap_changing, 0);
|
||||
}
|
||||
|
||||
ssize_t mcopy_continue(struct mm_struct *dst_mm, unsigned long start,
|
||||
unsigned long len, bool *mmap_changing)
|
||||
unsigned long len, atomic_t *mmap_changing)
|
||||
{
|
||||
return __mcopy_atomic(dst_mm, start, 0, len, MCOPY_ATOMIC_CONTINUE,
|
||||
mmap_changing, 0);
|
||||
}
|
||||
|
||||
int mwriteprotect_range(struct mm_struct *dst_mm, unsigned long start,
|
||||
unsigned long len, bool enable_wp, bool *mmap_changing)
|
||||
unsigned long len, bool enable_wp,
|
||||
atomic_t *mmap_changing)
|
||||
{
|
||||
struct vm_area_struct *dst_vma;
|
||||
pgprot_t newprot;
|
||||
@@ -694,7 +695,7 @@ int mwriteprotect_range(struct mm_struct *dst_mm, unsigned long start,
|
||||
* request the user to retry later
|
||||
*/
|
||||
err = -EAGAIN;
|
||||
if (mmap_changing && READ_ONCE(*mmap_changing))
|
||||
if (mmap_changing && atomic_read(mmap_changing))
|
||||
goto out_unlock;
|
||||
|
||||
err = -ENOENT;
|
||||
|
||||
Reference in New Issue
Block a user