From: Suren Baghdasaryan <surenb@google.com>
To: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: akpm@linux-foundation.org, Liam.Howlett@oracle.com,
david@redhat.com, vbabka@suse.cz, peterx@redhat.com,
jannh@google.com, hannes@cmpxchg.org, mhocko@kernel.org,
paulmck@kernel.org, shuah@kernel.org, adobriyan@gmail.com,
brauner@kernel.org, josef@toxicpanda.com, yebin10@huawei.com,
linux@weissschuh.net, willy@infradead.org, osalvador@suse.de,
andrii@kernel.org, ryan.roberts@arm.com,
christophe.leroy@csgroup.eu, tjmercier@google.com,
kaleshsingh@google.com, aha310510@gmail.com,
linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
linux-mm@kvack.org, linux-kselftest@vger.kernel.org,
SeongJae Park <sj@kernel.org>
Subject: Re: [PATCH v4 1/3] selftests/proc: test PROCMAP_QUERY ioctl while vma is concurrently modified
Date: Wed, 13 Aug 2025 16:21:47 +0000 [thread overview]
Message-ID: <CAJuCfpH+Mg7P--sP7LmhhUgGSU0AwmoJLYGyvft5fPC0Mz1P6w@mail.gmail.com> (raw)
In-Reply-To: <7d3b4b0c-f905-4622-95a8-e4d076dc71d4@lucifer.local>
On Wed, Aug 13, 2025 at 1:39 PM Lorenzo Stoakes
<lorenzo.stoakes@oracle.com> wrote:
>
> On Fri, Aug 08, 2025 at 08:28:47AM -0700, Suren Baghdasaryan wrote:
> > Extend /proc/pid/maps tearing tests to verify PROCMAP_QUERY ioctl operation
> > correctness while the vma is being concurrently modified.
> >
>
> General comment, but I really feel like this stuff is mm-specific. Yes it uses
> proc, but it's using it to check for mm functionality.
>
> I mean I'd love for these to be in the mm self tests but I get obviously why
> they're in the proc ones...
>
> > Signed-off-by: Suren Baghdasaryan <surenb@google.com>
> > Tested-by: SeongJae Park <sj@kernel.org>
> > Acked-by: SeongJae Park <sj@kernel.org>
>
> The tests themselves look good, had a good look through. But I've given you
> some nice ASCII diagrams to sprinkle liberally around :)
Thanks for the commentary, Lorenzo, it is great! I think I'll post
them as a follow-up patch since they do not change the functionality
of the test.
>
> Anyway for tests themselves:
>
> Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Thanks!
>
> > ---
> > tools/testing/selftests/proc/proc-maps-race.c | 65 +++++++++++++++++++
> > 1 file changed, 65 insertions(+)
> >
> > diff --git a/tools/testing/selftests/proc/proc-maps-race.c b/tools/testing/selftests/proc/proc-maps-race.c
> > index 94bba4553130..a546475db550 100644
> > --- a/tools/testing/selftests/proc/proc-maps-race.c
> > +++ b/tools/testing/selftests/proc/proc-maps-race.c
> > @@ -32,6 +32,8 @@
> > #include <stdlib.h>
> > #include <string.h>
> > #include <unistd.h>
> > +#include <linux/fs.h>
> > +#include <sys/ioctl.h>
> > #include <sys/mman.h>
> > #include <sys/stat.h>
> > #include <sys/types.h>
> > @@ -317,6 +319,25 @@ static bool capture_mod_pattern(FIXTURE_DATA(proc_maps_race) *self,
> > strcmp(restored_first_line->text, self->first_line.text) == 0;
> > }
> >
> > +static bool query_addr_at(int maps_fd, void *addr,
> > + unsigned long *vma_start, unsigned long *vma_end)
> > +{
> > + struct procmap_query q;
> > +
> > + memset(&q, 0, sizeof(q));
> > + q.size = sizeof(q);
> > + /* Find the VMA at the split address */
> > + q.query_addr = (unsigned long long)addr;
> > + q.query_flags = 0;
> > + if (ioctl(maps_fd, PROCMAP_QUERY, &q))
> > + return false;
> > +
> > + *vma_start = q.vma_start;
> > + *vma_end = q.vma_end;
> > +
> > + return true;
> > +}
> > +
> > static inline bool split_vma(FIXTURE_DATA(proc_maps_race) *self)
> > {
> > return mmap(self->mod_info->addr, self->page_size, self->mod_info->prot | PROT_EXEC,
> > @@ -559,6 +580,8 @@ TEST_F(proc_maps_race, test_maps_tearing_from_split)
> > do {
> > bool last_line_changed;
> > bool first_line_changed;
> > + unsigned long vma_start;
> > + unsigned long vma_end;
> >
> > ASSERT_TRUE(read_boundary_lines(self, &new_last_line, &new_first_line));
> >
> > @@ -595,6 +618,19 @@ TEST_F(proc_maps_race, test_maps_tearing_from_split)
> > first_line_changed = strcmp(new_first_line.text, self->first_line.text) != 0;
> > ASSERT_EQ(last_line_changed, first_line_changed);
> >
> > + /* Check if PROCMAP_QUERY ioclt() finds the right VMA */
>
> Typo ioclt -> ioctl.
>
> I think a little misleading, we're just testing whether we find a VMA at
> mod_info->addr + self->page_size.
>
>
> > + ASSERT_TRUE(query_addr_at(self->maps_fd, mod_info->addr + self->page_size,
> > + &vma_start, &vma_end));
> > + /*
> > + * The vma at the split address can be either the same as
> > + * original one (if read before the split) or the same as the
> > + * first line in the second page (if read after the split).
> > + */
> > + ASSERT_TRUE((vma_start == self->last_line.start_addr &&
> > + vma_end == self->last_line.end_addr) ||
> > + (vma_start == split_first_line.start_addr &&
> > + vma_end == split_first_line.end_addr));
> > +
>
> So I'd make things clearer here with a comment like:
>
> We are mmap()'ing a distinct VMA over the start of a 3 page
> mapping, which will cause the first page to be unmapped, and we can
> observe two states:
>
> read
> |
> v
> |---------|------------------|
> | | |
> | A | B | or:
> | | |
> |---------|------------------|
>
> |
> v
> |----------------------------|
> | |
> | A |
> | |
> |----------------------------|
>
> If we see entries in /proc/$pid/maps it'll be:
>
> 7fa86aa15000-7fa86aa16000 rw-p 00000000 00:00 0 (A)
> 7fa86aa16000-7fa86aa18000 rw-p 00000000 00:00 0 (B)
>
> Or:
>
> 7fa86aa15000-7fa86aa18000 rw-p 00000000 00:00 0 (A)
>
> So we assert that the reported range is equivalent to one of these.
>
> Obviously you can mix this in where you feel it makes sense.
>
> > clock_gettime(CLOCK_MONOTONIC_COARSE, &end_ts);
> > end_test_iteration(&end_ts, self->verbose);
> > } while (end_ts.tv_sec - start_ts.tv_sec < self->duration_sec);
> > @@ -636,6 +672,9 @@ TEST_F(proc_maps_race, test_maps_tearing_from_resize)
> > clock_gettime(CLOCK_MONOTONIC_COARSE, &start_ts);
> > start_test_loop(&start_ts, self->verbose);
> > do {
> > + unsigned long vma_start;
> > + unsigned long vma_end;
> > +
> > ASSERT_TRUE(read_boundary_lines(self, &new_last_line, &new_first_line));
> >
> > /* Check if we read vmas after shrinking it */
> > @@ -662,6 +701,16 @@ TEST_F(proc_maps_race, test_maps_tearing_from_resize)
> > "Expand result invalid", self));
> > }
> >
> > + /* Check if PROCMAP_QUERY ioclt() finds the right VMA */
> > + ASSERT_TRUE(query_addr_at(self->maps_fd, mod_info->addr, &vma_start, &vma_end));
>
> Same comments as above.
>
> > + /*
> > + * The vma should stay at the same address and have either the
> > + * original size of 3 pages or 1 page if read after shrinking.
> > + */
> > + ASSERT_TRUE(vma_start == self->last_line.start_addr &&
> > + (vma_end - vma_start == self->page_size * 3 ||
> > + vma_end - vma_start == self->page_size));
>
>
> So I'd make things clearer here with a comment like:
>
> We are shrinking and expanding a VMA from 1 page to 3 pages:
>
> read
> |
> v
> |---------|
> | |
> | A |
> | |
> |---------|
>
> |
> v
> |----------------------------|
> | |
> | A |
> | |
> |----------------------------|
>
> If we see entries in /proc/$pid/maps it'll be:
>
> 7fa86aa15000-7fa86aa16000 rw-p 00000000 00:00 0 (A)
>
> Or:
>
> 7fa86aa15000-7fa86aa18000 rw-p 00000000 00:00 0 (A)
>
> So we assert that the reported range is equivalent to one of these.
>
>
> > +
> > clock_gettime(CLOCK_MONOTONIC_COARSE, &end_ts);
> > end_test_iteration(&end_ts, self->verbose);
> > } while (end_ts.tv_sec - start_ts.tv_sec < self->duration_sec);
> > @@ -703,6 +752,9 @@ TEST_F(proc_maps_race, test_maps_tearing_from_remap)
> > clock_gettime(CLOCK_MONOTONIC_COARSE, &start_ts);
> > start_test_loop(&start_ts, self->verbose);
> > do {
> > + unsigned long vma_start;
> > + unsigned long vma_end;
> > +
> > ASSERT_TRUE(read_boundary_lines(self, &new_last_line, &new_first_line));
> >
> > /* Check if we read vmas after remapping it */
> > @@ -729,6 +781,19 @@ TEST_F(proc_maps_race, test_maps_tearing_from_remap)
> > "Remap restore result invalid", self));
> > }
> >
> > + /* Check if PROCMAP_QUERY ioclt() finds the right VMA */
> > + ASSERT_TRUE(query_addr_at(self->maps_fd, mod_info->addr + self->page_size,
> > + &vma_start, &vma_end));
>
> Same comments as above.
>
>
> > + /*
> > + * The vma should either stay at the same address and have the
> > + * original size of 3 pages or we should find the remapped vma
> > + * at the remap destination address with size of 1 page.
> > + */
> > + ASSERT_TRUE((vma_start == self->last_line.start_addr &&
> > + vma_end - vma_start == self->page_size * 3) ||
> > + (vma_start == self->last_line.start_addr + self->page_size &&
> > + vma_end - vma_start == self->page_size));
> > +
>
> Again be good to have more explanation here, similar comments to abov.
>
> We are mremap()'ing the last page of the next VMA (B) into the
> midle of the current one (A) (using MREMAP_DONTUNMAP leaving the
> last page of the original VMA zapped but in place:
>
> read
> |
> v R/W R/O
> |----------------------------| |------------------.---------|
> | | | . |
> | A | | B . |
> | | | . |
> |----------------------------| |------------------.---------|
>
> This will unmap the middle of A, splitting it in two, before
> placing a copy of B there (Which has different prot bits than A):
>
> |
> v R/W R/O R/W R/O
> |---------|---------|--------| |----------------------------|
> | | | | | |
> | A1 | B2 | A2 | | B |
> | | | | | |
> |---------|---------|--------| |----------------------------|
>
> But then we 'patch' B2 back to R/W prot bits, causing B2 to get
> merged:
>
> |
> v R/W R/O
> |----------------------------| |----------------------------|
> | | | |
> | A | | B |
> | | | |
> |----------------------------| |----------------------------|
>
> If we see entries in /proc/$pid/maps it'll be:
>
> 7fa86aa15000-7fa86aa18000 rw-p 00000000 00:00 0 (A)
> 7fa86aa19000-7fa86aa20000 r--p 00000000 00:00 0 (B)
>
> Or:
>
> 7fa86aa15000-7fa86aa16000 rw-p 00000000 00:00 0 (A1)
> 7fa86aa16000-7fa86aa17000 r--p 00000000 00:00 0 (B2)
> 7fa86aa17000-7fa86aa18000 rw-p 00000000 00:00 0 (A3)
> 7fa86aa19000-7fa86aa20000 r--p 00000000 00:00 0 (B)
>
> We are always examining the first line, so we simply assert that
> this remains in place and we observe 1 page or 3 pages.
>
> > clock_gettime(CLOCK_MONOTONIC_COARSE, &end_ts);
> > end_test_iteration(&end_ts, self->verbose);
> > } while (end_ts.tv_sec - start_ts.tv_sec < self->duration_sec);
> > --
> > 2.50.1.703.g449372360f-goog
> >
next prev parent reply other threads:[~2025-08-13 16:22 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-08 15:28 [PATCH v4 0/3] execute PROCMAP_QUERY ioctl under per-vma lock Suren Baghdasaryan
2025-08-08 15:28 ` [PATCH v4 1/3] selftests/proc: test PROCMAP_QUERY ioctl while vma is concurrently modified Suren Baghdasaryan
2025-08-13 13:38 ` Lorenzo Stoakes
2025-08-13 16:21 ` Suren Baghdasaryan [this message]
2025-08-13 18:53 ` Lorenzo Stoakes
2025-08-08 15:28 ` [PATCH v4 2/3] fs/proc/task_mmu: factor out proc_maps_private fields used by PROCMAP_QUERY Suren Baghdasaryan
2025-08-13 13:44 ` Lorenzo Stoakes
2025-08-08 15:28 ` [PATCH v4 3/3] fs/proc/task_mmu: execute PROCMAP_QUERY ioctl under per-vma locks Suren Baghdasaryan
2025-08-08 17:46 ` Vlastimil Babka
2025-08-11 23:14 ` Andrii Nakryiko
2025-08-13 13:50 ` Lorenzo Stoakes
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=CAJuCfpH+Mg7P--sP7LmhhUgGSU0AwmoJLYGyvft5fPC0Mz1P6w@mail.gmail.com \
--to=surenb@google.com \
--cc=Liam.Howlett@oracle.com \
--cc=adobriyan@gmail.com \
--cc=aha310510@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=andrii@kernel.org \
--cc=brauner@kernel.org \
--cc=christophe.leroy@csgroup.eu \
--cc=david@redhat.com \
--cc=hannes@cmpxchg.org \
--cc=jannh@google.com \
--cc=josef@toxicpanda.com \
--cc=kaleshsingh@google.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux@weissschuh.net \
--cc=lorenzo.stoakes@oracle.com \
--cc=mhocko@kernel.org \
--cc=osalvador@suse.de \
--cc=paulmck@kernel.org \
--cc=peterx@redhat.com \
--cc=ryan.roberts@arm.com \
--cc=shuah@kernel.org \
--cc=sj@kernel.org \
--cc=tjmercier@google.com \
--cc=vbabka@suse.cz \
--cc=willy@infradead.org \
--cc=yebin10@huawei.com \
/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;
as well as URLs for NNTP newsgroup(s).