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

Configure Feed

Select the types of activity you want to include in your feed.

testing/selftests/mm: add soft-dirty merge self-test

Assert that we correctly merge VMAs containing VM_SOFTDIRTY flags now that
we correctly handle these as sticky.

In order to do so, we have to account for the fact the pagemap interface
checks soft dirty PTEs and additionally that newly merged VMAs are marked
VM_SOFTDIRTY.

We do this by using use unfaulted anon VMAs, establishing one and clearing
references on that one, before establishing another and merging the two
before checking that soft-dirty is propagated as expected.

We check that this functions correctly with mremap() and mprotect() as
sample cases, because VMA merge of adjacent newly mapped VMAs will
automatically be made soft-dirty due to existing logic which does so.

We are therefore exercising other means of merging VMAs.

Link: https://lkml.kernel.org/r/d5a0f735783fb4f30a604f570ede02ccc5e29be9.1763399675.git.lorenzo.stoakes@oracle.com
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Andrey Vagin <avagin@gmail.com>
Cc: David Hildenbrand (Red Hat) <david@kernel.org>
Cc: Jann Horn <jannh@google.com>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Cyrill Gorcunov <gorcunov@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Lorenzo Stoakes and committed by
Andrew Morton
c7ba92bc 6707915e

+126 -1
+126 -1
tools/testing/selftests/mm/soft-dirty.c
··· 184 184 close(test_fd); 185 185 } 186 186 187 + static void test_merge(int pagemap_fd, int pagesize) 188 + { 189 + char *reserved, *map, *map2; 190 + 191 + /* 192 + * Reserve space for tests: 193 + * 194 + * ---padding to --- 195 + * | avoid adj. | 196 + * v merge v 197 + * |---|---|---|---|---| 198 + * | | 1 | 2 | 3 | | 199 + * |---|---|---|---|---| 200 + */ 201 + reserved = mmap(NULL, 5 * pagesize, PROT_NONE, 202 + MAP_ANON | MAP_PRIVATE, -1, 0); 203 + if (reserved == MAP_FAILED) 204 + ksft_exit_fail_msg("mmap failed\n"); 205 + munmap(reserved, 4 * pagesize); 206 + 207 + /* 208 + * Establish initial VMA: 209 + * 210 + * S/D 211 + * |---|---|---|---|---| 212 + * | | 1 | | | | 213 + * |---|---|---|---|---| 214 + */ 215 + map = mmap(&reserved[pagesize], pagesize, PROT_READ | PROT_WRITE, 216 + MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); 217 + if (map == MAP_FAILED) 218 + ksft_exit_fail_msg("mmap failed\n"); 219 + 220 + /* This will clear VM_SOFTDIRTY too. */ 221 + clear_softdirty(); 222 + 223 + /* 224 + * Now place a new mapping which will be marked VM_SOFTDIRTY. Away from 225 + * map: 226 + * 227 + * - S/D 228 + * |---|---|---|---|---| 229 + * | | 1 | | 2 | | 230 + * |---|---|---|---|---| 231 + */ 232 + map2 = mmap(&reserved[3 * pagesize], pagesize, PROT_READ | PROT_WRITE, 233 + MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); 234 + if (map2 == MAP_FAILED) 235 + ksft_exit_fail_msg("mmap failed\n"); 236 + 237 + /* 238 + * Now remap it immediately adjacent to map, if the merge correctly 239 + * propagates VM_SOFTDIRTY, we should then observe the VMA as a whole 240 + * being marked soft-dirty: 241 + * 242 + * merge 243 + * S/D 244 + * |---|-------|---|---| 245 + * | | 1 | | | 246 + * |---|-------|---|---| 247 + */ 248 + map2 = mremap(map2, pagesize, pagesize, MREMAP_FIXED | MREMAP_MAYMOVE, 249 + &reserved[2 * pagesize]); 250 + if (map2 == MAP_FAILED) 251 + ksft_exit_fail_msg("mremap failed\n"); 252 + ksft_test_result(pagemap_is_softdirty(pagemap_fd, map) == 1, 253 + "Test %s-anon soft-dirty after remap merge 1st pg\n", 254 + __func__); 255 + ksft_test_result(pagemap_is_softdirty(pagemap_fd, map2) == 1, 256 + "Test %s-anon soft-dirty after remap merge 2nd pg\n", 257 + __func__); 258 + 259 + munmap(map, 2 * pagesize); 260 + 261 + /* 262 + * Now establish another VMA: 263 + * 264 + * S/D 265 + * |---|---|---|---|---| 266 + * | | 1 | | | | 267 + * |---|---|---|---|---| 268 + */ 269 + map = mmap(&reserved[pagesize], pagesize, PROT_READ | PROT_WRITE, 270 + MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); 271 + if (map == MAP_FAILED) 272 + ksft_exit_fail_msg("mmap failed\n"); 273 + 274 + /* Clear VM_SOFTDIRTY... */ 275 + clear_softdirty(); 276 + /* ...and establish incompatible adjacent VMA: 277 + * 278 + * - S/D 279 + * |---|---|---|---|---| 280 + * | | 1 | 2 | | | 281 + * |---|---|---|---|---| 282 + */ 283 + map2 = mmap(&reserved[2 * pagesize], pagesize, 284 + PROT_READ | PROT_WRITE | PROT_EXEC, 285 + MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); 286 + if (map2 == MAP_FAILED) 287 + ksft_exit_fail_msg("mmap failed\n"); 288 + 289 + /* 290 + * Now mprotect() VMA 1 so it's compatible with 2 and therefore merges: 291 + * 292 + * merge 293 + * S/D 294 + * |---|-------|---|---| 295 + * | | 1 | | | 296 + * |---|-------|---|---| 297 + */ 298 + if (mprotect(map, pagesize, PROT_READ | PROT_WRITE | PROT_EXEC)) 299 + ksft_exit_fail_msg("mprotect failed\n"); 300 + 301 + ksft_test_result(pagemap_is_softdirty(pagemap_fd, map) == 1, 302 + "Test %s-anon soft-dirty after mprotect merge 1st pg\n", 303 + __func__); 304 + ksft_test_result(pagemap_is_softdirty(pagemap_fd, map2) == 1, 305 + "Test %s-anon soft-dirty after mprotect merge 2nd pg\n", 306 + __func__); 307 + 308 + munmap(map, 2 * pagesize); 309 + } 310 + 187 311 static void test_mprotect_anon(int pagemap_fd, int pagesize) 188 312 { 189 313 test_mprotect(pagemap_fd, pagesize, true); ··· 328 204 if (!softdirty_supported()) 329 205 ksft_exit_skip("soft-dirty is not support\n"); 330 206 331 - ksft_set_plan(15); 207 + ksft_set_plan(19); 332 208 pagemap_fd = open(PAGEMAP_FILE_PATH, O_RDONLY); 333 209 if (pagemap_fd < 0) 334 210 ksft_exit_fail_msg("Failed to open %s\n", PAGEMAP_FILE_PATH); ··· 340 216 test_hugepage(pagemap_fd, pagesize); 341 217 test_mprotect_anon(pagemap_fd, pagesize); 342 218 test_mprotect_file(pagemap_fd, pagesize); 219 + test_merge(pagemap_fd, pagesize); 343 220 344 221 close(pagemap_fd); 345 222