From: Suren Baghdasaryan <surenb@google.com>
To: akpm@linux-foundation.org
Cc: liam@infradead.org, ljs@kernel.org, vbabka@kernel.org,
david@redhat.com, willy@infradead.org, jannh@google.com,
paulmck@kernel.org, pfalcato@suse.de, shuah@kernel.org,
hsukrut3@gmail.com, richard.weiyang@gmail.com,
reddybalavignesh9979@gmail.com, linux-mm@kvack.org,
linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
linux-kselftest@vger.kernel.org, surenb@google.com
Subject: [PATCH v2 2/3] selftests/proc: ensure the test is performed at the right page boundary
Date: Sat, 25 Apr 2026 23:27:17 -0700 [thread overview]
Message-ID: <20260426062718.1238437-3-surenb@google.com> (raw)
In-Reply-To: <20260426062718.1238437-1-surenb@google.com>
When running tearing tests we need to ensure the pages we use include
VMAs that were mapped by the child process for this test. Currently we
always use the first two pages, checking VMAs at their boundaries and
this works, however once we add tests for /proc/pid/smaps, the first two
pages might not contain the VMAs that child modifies.
Locate the page that contains the first VMA mapped by the child and use
that and the next page for the test.
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
Reviewed-by: Liam R. Howlett <liam@infradead.org>
---
tools/testing/selftests/proc/proc-maps-race.c | 119 +++++++++++++++---
1 file changed, 100 insertions(+), 19 deletions(-)
diff --git a/tools/testing/selftests/proc/proc-maps-race.c b/tools/testing/selftests/proc/proc-maps-race.c
index a734553718da..5eb350c23da4 100644
--- a/tools/testing/selftests/proc/proc-maps-race.c
+++ b/tools/testing/selftests/proc/proc-maps-race.c
@@ -39,6 +39,13 @@
#include <sys/types.h>
#include <sys/wait.h>
+#define min(a, b) \
+ ({ \
+ typeof(a) _a = (a); \
+ typeof(b) _b = (b); \
+ _a < _b ? _a : _b; \
+ })
+
/* /proc/pid/maps parsing routines */
struct page_content {
char *data;
@@ -77,6 +84,7 @@ FIXTURE(proc_maps_race)
struct line_content first_line;
unsigned long duration_sec;
int shared_mem_size;
+ int skip_pages;
int page_size;
int vma_count;
bool verbose;
@@ -105,38 +113,102 @@ struct vma_modifier_info {
void *child_mapped_addr[];
};
-
-static bool read_two_pages(FIXTURE_DATA(proc_maps_race) *self)
+static bool read_page(FIXTURE_DATA(proc_maps_race) *self,
+ struct page_content *page)
{
ssize_t bytes_read;
- if (lseek(self->maps_fd, 0, SEEK_SET) < 0)
+ bytes_read = read(self->maps_fd, page->data, self->page_size);
+ if (bytes_read <= 0)
return false;
- bytes_read = read(self->maps_fd, self->page1.data, self->page_size);
- if (bytes_read <= 0)
+ /* Make sure data always ends with a newline character. */
+ if (page->data[bytes_read - 1] != '\n')
return false;
- self->page1.size = bytes_read;
+ page->size = bytes_read;
- bytes_read = read(self->maps_fd, self->page2.data, self->page_size);
- if (bytes_read <= 0)
+ return true;
+}
+
+static bool parse_vma_line(char *line_start, char *line_end,
+ unsigned long *start, unsigned long *end)
+{
+ bool found;
+
+ *line_end = '\0'; /* stop sscanf at the EOL */
+ found = (sscanf(line_start, "%lx-%lx", start, end) == 2);
+ *line_end = '\n';
+
+ return found;
+}
+
+static int locate_containing_page(FIXTURE_DATA(proc_maps_race) *self,
+ unsigned long addr, unsigned long size)
+{
+ unsigned long start, end;
+ int page = 0;
+
+ if (lseek(self->maps_fd, 0, SEEK_SET) < 0)
+ return -1;
+
+ while (true) {
+ char *curr_pos;
+ char *end_pos;
+
+ if (!read_page(self, &self->page1))
+ return -1;
+
+ curr_pos = self->page1.data;
+ end_pos = self->page1.data + self->page1.size;
+ while (curr_pos < end_pos) {
+ char *line_end;
+
+ line_end = strchr(curr_pos, '\n');
+ if (!line_end)
+ break;
+
+ if (parse_vma_line(curr_pos, line_end, &start, &end) &&
+ start == addr && end == addr + size)
+ return page;
+
+ curr_pos = line_end + 1;
+ }
+ page++;
+ }
+
+ return 0;
+}
+
+static bool read_two_pages(FIXTURE_DATA(proc_maps_race) *self)
+{
+ if (lseek(self->maps_fd, 0, SEEK_SET) < 0)
return false;
- self->page2.size = bytes_read;
+ for (int i = 0; i < self->skip_pages; i++)
+ if (!read_page(self, &self->page1))
+ return false;
- return true;
+ return read_page(self, &self->page1) && read_page(self, &self->page2);
}
-static void copy_first_line(struct page_content *page, char *first_line)
+static void copy_line(const char *line_start, const char *line_end,
+ char *buf, size_t buf_size)
{
- char *pos = strchr(page->data, '\n');
+ size_t len = min(line_end - line_start, buf_size - 1);
- strncpy(first_line, page->data, pos - page->data);
- first_line[pos - page->data] = '\0';
+ strncpy(buf, line_start, len);
+ buf[len] = '\0';
}
-static void copy_last_line(struct page_content *page, char *last_line)
+static void copy_first_line(struct page_content *page, char *first_line,
+ size_t line_size)
+{
+ copy_line(page->data, strchr(page->data, '\n'), first_line, line_size);
+}
+
+static void copy_last_line(struct page_content *page, char *last_line,
+ size_t line_size)
{
/* Get the last line in the first page */
const char *end = page->data + page->size - 1;
@@ -146,8 +218,8 @@ static void copy_last_line(struct page_content *page, char *last_line)
/* search previous newline */
while (pos[-1] != '\n')
pos--;
- strncpy(last_line, pos, end - pos);
- last_line[end - pos] = '\0';
+
+ copy_line(pos, end, last_line, line_size);
}
/* Read the last line of the first page and the first line of the second page */
@@ -158,8 +230,8 @@ static bool read_boundary_lines(FIXTURE_DATA(proc_maps_race) *self,
if (!read_two_pages(self))
return false;
- copy_last_line(&self->page1, last_line->text);
- copy_first_line(&self->page2, first_line->text);
+ copy_last_line(&self->page1, last_line->text, LINE_MAX_SIZE);
+ copy_first_line(&self->page2, first_line->text, LINE_MAX_SIZE);
return sscanf(last_line->text, "%lx-%lx", &last_line->start_addr,
&last_line->end_addr) == 2 &&
@@ -418,6 +490,8 @@ FIXTURE_SETUP(proc_maps_race)
struct vma_modifier_info *mod_info;
pthread_mutexattr_t mutex_attr;
pthread_condattr_t cond_attr;
+ unsigned long first_map_addr;
+ unsigned long last_map_addr;
unsigned long duration_sec;
char fname[32];
@@ -502,6 +576,13 @@ FIXTURE_SETUP(proc_maps_race)
self->page2.data = malloc(self->page_size);
ASSERT_NE(self->page2.data, NULL);
+ first_map_addr = (unsigned long)mod_info->child_mapped_addr[0];
+ last_map_addr = (unsigned long)mod_info->child_mapped_addr[mod_info->vma_count - 1];
+
+ self->skip_pages = locate_containing_page(self,
+ min(first_map_addr, last_map_addr),
+ self->page_size * 3);
+ ASSERT_NE(self->skip_pages, -1);
ASSERT_TRUE(read_boundary_lines(self, &self->last_line, &self->first_line));
/*
--
2.54.0.545.g6539524ca2-goog
next prev parent reply other threads:[~2026-04-26 6:27 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-26 6:27 [PATCH v2 0/3] use vma locks for proc/pid/{smaps|numa_maps} reads Suren Baghdasaryan
2026-04-26 6:27 ` [PATCH v2 1/3] fs/proc/task_mmu: read proc/pid/{smaps|numa_maps} under per-vma lock Suren Baghdasaryan
2026-04-26 6:27 ` Suren Baghdasaryan [this message]
2026-04-26 6:27 ` [PATCH v2 3/3] selftests/proc: add /proc/pid/smaps tearing tests Suren Baghdasaryan
2026-04-26 19:59 ` [PATCH v2 0/3] use vma locks for proc/pid/{smaps|numa_maps} reads Andrew Morton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260426062718.1238437-3-surenb@google.com \
--to=surenb@google.com \
--cc=akpm@linux-foundation.org \
--cc=david@redhat.com \
--cc=hsukrut3@gmail.com \
--cc=jannh@google.com \
--cc=liam@infradead.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=paulmck@kernel.org \
--cc=pfalcato@suse.de \
--cc=reddybalavignesh9979@gmail.com \
--cc=richard.weiyang@gmail.com \
--cc=shuah@kernel.org \
--cc=vbabka@kernel.org \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox