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.

selftests/proc: test PROCMAP_QUERY ioctl while vma is concurrently modified

Patch series " execute PROCMAP_QUERY ioctl under per-vma lock", v4.

With /proc/pid/maps now being read under per-vma lock protection we can
reuse parts of that code to execute PROCMAP_QUERY ioctl also without
taking mmap_lock. The change is designed to reduce mmap_lock contention
and prevent PROCMAP_QUERY ioctl calls from blocking address space updates.

This patchset was split out of the original patchset [1] that introduced
per-vma lock usage for /proc/pid/maps reading. It contains PROCMAP_QUERY
tests, code refactoring patch to simplify the main change and the actual
transition to per-vma lock.


This patch (of 3):

Extend /proc/pid/maps tearing tests to verify PROCMAP_QUERY ioctl operation
correctness while the vma is being concurrently modified.

Link: https://lkml.kernel.org/r/20250808152850.2580887-1-surenb@google.com
Link: https://lkml.kernel.org/r/20250808152850.2580887-2-surenb@google.com
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
Tested-by: SeongJae Park <sj@kernel.org>
Acked-by: SeongJae Park <sj@kernel.org>
Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: David Hildenbrand <david@redhat.com>
Cc: Jann Horn <jannh@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Josef Bacik <josef@toxicpanda.com>
Cc: Kalesh Singh <kaleshsingh@google.com>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: "Paul E . McKenney" <paulmck@kernel.org>
Cc: Peter Xu <peterx@redhat.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Thomas Weißschuh <linux@weissschuh.net>
Cc: T.J. Mercier <tjmercier@google.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Ye Bin <yebin10@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Suren Baghdasaryan and committed by
Andrew Morton
41f10558 63f39737

+65
+65
tools/testing/selftests/proc/proc-maps-race.c
··· 32 32 #include <stdlib.h> 33 33 #include <string.h> 34 34 #include <unistd.h> 35 + #include <linux/fs.h> 36 + #include <sys/ioctl.h> 35 37 #include <sys/mman.h> 36 38 #include <sys/stat.h> 37 39 #include <sys/types.h> ··· 319 317 strcmp(restored_first_line->text, self->first_line.text) == 0; 320 318 } 321 319 320 + static bool query_addr_at(int maps_fd, void *addr, 321 + unsigned long *vma_start, unsigned long *vma_end) 322 + { 323 + struct procmap_query q; 324 + 325 + memset(&q, 0, sizeof(q)); 326 + q.size = sizeof(q); 327 + /* Find the VMA at the split address */ 328 + q.query_addr = (unsigned long long)addr; 329 + q.query_flags = 0; 330 + if (ioctl(maps_fd, PROCMAP_QUERY, &q)) 331 + return false; 332 + 333 + *vma_start = q.vma_start; 334 + *vma_end = q.vma_end; 335 + 336 + return true; 337 + } 338 + 322 339 static inline bool split_vma(FIXTURE_DATA(proc_maps_race) *self) 323 340 { 324 341 return mmap(self->mod_info->addr, self->page_size, self->mod_info->prot | PROT_EXEC, ··· 580 559 do { 581 560 bool last_line_changed; 582 561 bool first_line_changed; 562 + unsigned long vma_start; 563 + unsigned long vma_end; 583 564 584 565 ASSERT_TRUE(read_boundary_lines(self, &new_last_line, &new_first_line)); 585 566 ··· 617 594 last_line_changed = strcmp(new_last_line.text, self->last_line.text) != 0; 618 595 first_line_changed = strcmp(new_first_line.text, self->first_line.text) != 0; 619 596 ASSERT_EQ(last_line_changed, first_line_changed); 597 + 598 + /* Check if PROCMAP_QUERY ioclt() finds the right VMA */ 599 + ASSERT_TRUE(query_addr_at(self->maps_fd, mod_info->addr + self->page_size, 600 + &vma_start, &vma_end)); 601 + /* 602 + * The vma at the split address can be either the same as 603 + * original one (if read before the split) or the same as the 604 + * first line in the second page (if read after the split). 605 + */ 606 + ASSERT_TRUE((vma_start == self->last_line.start_addr && 607 + vma_end == self->last_line.end_addr) || 608 + (vma_start == split_first_line.start_addr && 609 + vma_end == split_first_line.end_addr)); 620 610 621 611 clock_gettime(CLOCK_MONOTONIC_COARSE, &end_ts); 622 612 end_test_iteration(&end_ts, self->verbose); ··· 672 636 clock_gettime(CLOCK_MONOTONIC_COARSE, &start_ts); 673 637 start_test_loop(&start_ts, self->verbose); 674 638 do { 639 + unsigned long vma_start; 640 + unsigned long vma_end; 641 + 675 642 ASSERT_TRUE(read_boundary_lines(self, &new_last_line, &new_first_line)); 676 643 677 644 /* Check if we read vmas after shrinking it */ ··· 700 661 strcmp(new_first_line.text, restored_first_line.text), 701 662 "Expand result invalid", self)); 702 663 } 664 + 665 + /* Check if PROCMAP_QUERY ioclt() finds the right VMA */ 666 + ASSERT_TRUE(query_addr_at(self->maps_fd, mod_info->addr, &vma_start, &vma_end)); 667 + /* 668 + * The vma should stay at the same address and have either the 669 + * original size of 3 pages or 1 page if read after shrinking. 670 + */ 671 + ASSERT_TRUE(vma_start == self->last_line.start_addr && 672 + (vma_end - vma_start == self->page_size * 3 || 673 + vma_end - vma_start == self->page_size)); 703 674 704 675 clock_gettime(CLOCK_MONOTONIC_COARSE, &end_ts); 705 676 end_test_iteration(&end_ts, self->verbose); ··· 752 703 clock_gettime(CLOCK_MONOTONIC_COARSE, &start_ts); 753 704 start_test_loop(&start_ts, self->verbose); 754 705 do { 706 + unsigned long vma_start; 707 + unsigned long vma_end; 708 + 755 709 ASSERT_TRUE(read_boundary_lines(self, &new_last_line, &new_first_line)); 756 710 757 711 /* Check if we read vmas after remapping it */ ··· 780 728 strcmp(new_first_line.text, restored_first_line.text), 781 729 "Remap restore result invalid", self)); 782 730 } 731 + 732 + /* Check if PROCMAP_QUERY ioclt() finds the right VMA */ 733 + ASSERT_TRUE(query_addr_at(self->maps_fd, mod_info->addr + self->page_size, 734 + &vma_start, &vma_end)); 735 + /* 736 + * The vma should either stay at the same address and have the 737 + * original size of 3 pages or we should find the remapped vma 738 + * at the remap destination address with size of 1 page. 739 + */ 740 + ASSERT_TRUE((vma_start == self->last_line.start_addr && 741 + vma_end - vma_start == self->page_size * 3) || 742 + (vma_start == self->last_line.start_addr + self->page_size && 743 + vma_end - vma_start == self->page_size)); 783 744 784 745 clock_gettime(CLOCK_MONOTONIC_COARSE, &end_ts); 785 746 end_test_iteration(&end_ts, self->verbose);