Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests: mm: gup_longterm: test unsharing logic when R/O pinning

In our FOLL_LONGTERM tests, we prefault the page tables for the GUP-fast
test cases to be able to find a PTE and exercise the "longterm pinning
allowed" logic on the GUP-fast path where possible.

For now, we always prefault the page tables writable, resulting in PTEs
that are writable.

Let's cover more cases to also test if our unsharing logic works as
expected (and is able to make progress when there is nothing to unshare)
by mprotect'ing the range R/O when R/O-pinning, so we don't get PTEs that
are writable.

This change would have found an issue introduced by commit a12083d721d7
("mm/gup: handle hugepd for follow_page()"), whereby R/O pinning was not
able to make progress in all cases, because unsharing logic was not
provided with the VMA to decide at some point that long-term R/O pinning a
!anon page is fine.

Link: https://lkml.kernel.org/r/20240430131508.86924-1-david@redhat.com
Signed-off-by: David Hildenbrand <david@redhat.com>
Acked-by: Peter Xu <peterx@redhat.com>
Cc: Shuah Khan <shuah@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

David Hildenbrand and committed by
Andrew Morton
67f4c91a cc48be37

+12 -4
+12 -4
tools/testing/selftests/mm/gup_longterm.c
··· 118 118 return; 119 119 } 120 120 121 - /* 122 - * Fault in the page writable such that GUP-fast can eventually pin 123 - * it immediately. 124 - */ 121 + /* Fault in the page such that GUP-fast can pin it directly. */ 125 122 memset(mem, 0, size); 126 123 127 124 switch (type) { 128 125 case TEST_TYPE_RO: 129 126 case TEST_TYPE_RO_FAST: 127 + /* 128 + * Cover more cases regarding unsharing decisions when 129 + * long-term R/O pinning by mapping the page R/O. 130 + */ 131 + ret = mprotect(mem, size, PROT_READ); 132 + if (ret) { 133 + ksft_test_result_fail("mprotect() failed\n"); 134 + goto munmap; 135 + } 136 + /* FALLTHROUGH */ 130 137 case TEST_TYPE_RW: 131 138 case TEST_TYPE_RW_FAST: { 132 139 struct pin_longterm_test args; ··· 235 228 assert(false); 236 229 } 237 230 231 + munmap: 238 232 munmap(mem, size); 239 233 } 240 234