On 26/04/24 12:02AM, Suren Baghdasaryan wrote:
> 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 <[email protected]>

Reviewed-by: Liam R. Howlett <[email protected]>

> ---
>  tools/testing/selftests/proc/proc-maps-race.c | 78 ++++++++++++++++---
>  1 file changed, 68 insertions(+), 10 deletions(-)
> 
> diff --git a/tools/testing/selftests/proc/proc-maps-race.c 
> b/tools/testing/selftests/proc/proc-maps-race.c
> index a734553718da..c5031b0593b7 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; \
> +     })
> +

Another implementation of min in the selftests.  I guess it's somewhat
unavoidable.

>  /* /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,27 +113,68 @@ 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 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) {
> +                     if (sscanf(curr_pos, "%lx-%lx", &start, &end) == 2 &&
> +                         start == addr && end == addr + size)
> +                             return page;
> +
> +                     curr_pos = strchr(curr_pos, '\n');
> +                     if (!curr_pos)
> +                             break;
> +                     curr_pos++;
> +             }
> +             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)
> @@ -418,6 +467,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 +553,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
> 

Reply via email to