Skip to content

Commit fe673d3

Browse files
committed
mm: gup: make fault_in_safe_writeable() use fixup_user_fault()
Instead of using GUP, make fault_in_safe_writeable() actually force a 'handle_mm_fault()' using the same fixup_user_fault() machinery that futexes already use. Using the GUP machinery meant that fault_in_safe_writeable() did not do everything that a real fault would do, ranging from not auto-expanding the stack segment, to not updating accessed or dirty flags in the page tables (GUP sets those flags on the pages themselves). The latter causes problems on architectures (like s390) that do accessed bit handling in software, which meant that fault_in_safe_writeable() didn't actually do all the fault handling it needed to, and trying to access the user address afterwards would still cause faults. Reported-and-tested-by: Andreas Gruenbacher <[email protected]> Fixes: cdd591f ("iov_iter: Introduce fault_in_iov_iter_writeable") Link: https://lore.kernel.org/all/CAHc6FU5nP+nziNGG0JAF1FUx-GV7kKFvM7aZuU_XD2_1v4vnvg@mail.gmail.com/ Acked-by: David Hildenbrand <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 1db333d commit fe673d3

File tree

1 file changed

+19
-38
lines changed

1 file changed

+19
-38
lines changed

mm/gup.c

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1729,11 +1729,11 @@ EXPORT_SYMBOL(fault_in_writeable);
17291729
* @uaddr: start of address range
17301730
* @size: length of address range
17311731
*
1732-
* Faults in an address range using get_user_pages, i.e., without triggering
1733-
* hardware page faults. This is primarily useful when we already know that
1734-
* some or all of the pages in the address range aren't in memory.
1732+
* Faults in an address range for writing. This is primarily useful when we
1733+
* already know that some or all of the pages in the address range aren't in
1734+
* memory.
17351735
*
1736-
* Other than fault_in_writeable(), this function is non-destructive.
1736+
* Unlike fault_in_writeable(), this function is non-destructive.
17371737
*
17381738
* Note that we don't pin or otherwise hold the pages referenced that we fault
17391739
* in. There's no guarantee that they'll stay in memory for any duration of
@@ -1744,46 +1744,27 @@ EXPORT_SYMBOL(fault_in_writeable);
17441744
*/
17451745
size_t fault_in_safe_writeable(const char __user *uaddr, size_t size)
17461746
{
1747-
unsigned long start = (unsigned long)untagged_addr(uaddr);
1748-
unsigned long end, nstart, nend;
1747+
unsigned long start = (unsigned long)uaddr, end;
17491748
struct mm_struct *mm = current->mm;
1750-
struct vm_area_struct *vma = NULL;
1751-
int locked = 0;
1749+
bool unlocked = false;
17521750

1753-
nstart = start & PAGE_MASK;
1751+
if (unlikely(size == 0))
1752+
return 0;
17541753
end = PAGE_ALIGN(start + size);
1755-
if (end < nstart)
1754+
if (end < start)
17561755
end = 0;
1757-
for (; nstart != end; nstart = nend) {
1758-
unsigned long nr_pages;
1759-
long ret;
17601756

1761-
if (!locked) {
1762-
locked = 1;
1763-
mmap_read_lock(mm);
1764-
vma = find_vma(mm, nstart);
1765-
} else if (nstart >= vma->vm_end)
1766-
vma = vma->vm_next;
1767-
if (!vma || vma->vm_start >= end)
1768-
break;
1769-
nend = end ? min(end, vma->vm_end) : vma->vm_end;
1770-
if (vma->vm_flags & (VM_IO | VM_PFNMAP))
1771-
continue;
1772-
if (nstart < vma->vm_start)
1773-
nstart = vma->vm_start;
1774-
nr_pages = (nend - nstart) / PAGE_SIZE;
1775-
ret = __get_user_pages_locked(mm, nstart, nr_pages,
1776-
NULL, NULL, &locked,
1777-
FOLL_TOUCH | FOLL_WRITE);
1778-
if (ret <= 0)
1757+
mmap_read_lock(mm);
1758+
do {
1759+
if (fixup_user_fault(mm, start, FAULT_FLAG_WRITE, &unlocked))
17791760
break;
1780-
nend = nstart + ret * PAGE_SIZE;
1781-
}
1782-
if (locked)
1783-
mmap_read_unlock(mm);
1784-
if (nstart == end)
1785-
return 0;
1786-
return size - min_t(size_t, nstart - start, size);
1761+
start = (start + PAGE_SIZE) & PAGE_MASK;
1762+
} while (start != end);
1763+
mmap_read_unlock(mm);
1764+
1765+
if (size > (unsigned long)uaddr - start)
1766+
return size - ((unsigned long)uaddr - start);
1767+
return 0;
17871768
}
17881769
EXPORT_SYMBOL(fault_in_safe_writeable);
17891770

0 commit comments

Comments
 (0)