Skip to content

Commit 6aacab3

Browse files
ljskernelakpm00
authored andcommitted
tools/testing/vma: separate VMA userland tests into separate files
So far the userland VMA tests have been established as a rough expression of what's been possible. Adapt it into a more usable form by separating out tests and shared helper functions. Since we test functions that are declared statically in mm/vma.c, we make use of the trick of #include'ing kernel C files directly. In order for the tests to continue to function, we must therefore also this way into the tests/ directory. We try to keep as much shared logic actually modularised into a separate compilation unit in shared.c, however the merge_existing() and attach_vma() helpers rely on statically declared mm/vma.c functions so these must be declared in main.c. Link: https://lkml.kernel.org/r/a0455ccfe4fdcd1c962c64f76304f612e5662a4e.1769097829.git.lorenzo.stoakes@oracle.com Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com> Cc: Baolin Wang <baolin.wang@linux.alibaba.com> Cc: Barry Song <baohua@kernel.org> Cc: David Hildenbrand <david@kernel.org> Cc: Dev Jain <dev.jain@arm.com> Cc: Jason Gunthorpe <jgg@nvidia.com> Cc: Suren Baghdasaryan <surenb@google.com> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Zi Yan <ziy@nvidia.com> Cc: Damien Le Moal <dlemoal@kernel.org> Cc: "Darrick J. Wong" <djwong@kernel.org> Cc: Jarkko Sakkinen <jarkko@kernel.org> Cc: Yury Norov <ynorov@nvidia.com> Cc: Chris Mason <clm@fb.com> Cc: Pedro Falcato <pfalcato@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 53f1d93 commit 6aacab3

8 files changed

Lines changed: 406 additions & 335 deletions

File tree

tools/testing/vma/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ default: vma
66

77
include ../shared/shared.mk
88

9-
OFILES = $(SHARED_OFILES) vma.o maple-shim.o
9+
OFILES = $(SHARED_OFILES) main.o shared.o maple-shim.o
1010
TARGETS = vma
1111

12-
vma.o: vma.c vma_internal.h ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h
12+
main.o: main.c shared.c shared.h vma_internal.h tests/merge.c tests/mmap.c tests/vma.c ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h
1313

1414
vma: $(OFILES)
1515
$(CC) $(CFLAGS) -o $@ $(OFILES) $(LDLIBS)

tools/testing/vma/main.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
3+
#include "shared.h"
4+
/*
5+
* Directly import the VMA implementation here. Our vma_internal.h wrapper
6+
* provides userland-equivalent functionality for everything vma.c uses.
7+
*/
8+
#include "../../../mm/vma_init.c"
9+
#include "../../../mm/vma_exec.c"
10+
#include "../../../mm/vma.c"
11+
12+
/* Tests are included directly so they can test static functions in mm/vma.c. */
13+
#include "tests/merge.c"
14+
#include "tests/mmap.c"
15+
#include "tests/vma.c"
16+
17+
/* Helper functions which utilise static kernel functions. */
18+
19+
struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg)
20+
{
21+
struct vm_area_struct *vma;
22+
23+
vma = vma_merge_existing_range(vmg);
24+
if (vma)
25+
vma_assert_attached(vma);
26+
return vma;
27+
}
28+
29+
int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma)
30+
{
31+
int res;
32+
33+
res = vma_link(mm, vma);
34+
if (!res)
35+
vma_assert_attached(vma);
36+
return res;
37+
}
38+
39+
/* Main test running which invokes tests/ *.c runners. */
40+
int main(void)
41+
{
42+
int num_tests = 0, num_fail = 0;
43+
44+
maple_tree_init();
45+
vma_state_init();
46+
47+
run_merge_tests(&num_tests, &num_fail);
48+
run_mmap_tests(&num_tests, &num_fail);
49+
run_vma_tests(&num_tests, &num_fail);
50+
51+
printf("%d tests run, %d passed, %d failed.\n",
52+
num_tests, num_tests - num_fail, num_fail);
53+
54+
return num_fail == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
55+
}

tools/testing/vma/shared.c

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
3+
#include "shared.h"
4+
5+
6+
bool fail_prealloc;
7+
unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
8+
unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
9+
unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
10+
11+
const struct vm_operations_struct vma_dummy_vm_ops;
12+
struct anon_vma dummy_anon_vma;
13+
struct task_struct __current;
14+
15+
struct vm_area_struct *alloc_vma(struct mm_struct *mm,
16+
unsigned long start, unsigned long end,
17+
pgoff_t pgoff, vm_flags_t vm_flags)
18+
{
19+
struct vm_area_struct *vma = vm_area_alloc(mm);
20+
21+
if (vma == NULL)
22+
return NULL;
23+
24+
vma->vm_start = start;
25+
vma->vm_end = end;
26+
vma->vm_pgoff = pgoff;
27+
vm_flags_reset(vma, vm_flags);
28+
vma_assert_detached(vma);
29+
30+
return vma;
31+
}
32+
33+
void detach_free_vma(struct vm_area_struct *vma)
34+
{
35+
vma_mark_detached(vma);
36+
vm_area_free(vma);
37+
}
38+
39+
struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
40+
unsigned long start, unsigned long end,
41+
pgoff_t pgoff, vm_flags_t vm_flags)
42+
{
43+
struct vm_area_struct *vma = alloc_vma(mm, start, end, pgoff, vm_flags);
44+
45+
if (vma == NULL)
46+
return NULL;
47+
48+
if (attach_vma(mm, vma)) {
49+
detach_free_vma(vma);
50+
return NULL;
51+
}
52+
53+
/*
54+
* Reset this counter which we use to track whether writes have
55+
* begun. Linking to the tree will have caused this to be incremented,
56+
* which means we will get a false positive otherwise.
57+
*/
58+
vma->vm_lock_seq = UINT_MAX;
59+
60+
return vma;
61+
}
62+
63+
void reset_dummy_anon_vma(void)
64+
{
65+
dummy_anon_vma.was_cloned = false;
66+
dummy_anon_vma.was_unlinked = false;
67+
}
68+
69+
int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi)
70+
{
71+
struct vm_area_struct *vma;
72+
int count = 0;
73+
74+
fail_prealloc = false;
75+
reset_dummy_anon_vma();
76+
77+
vma_iter_set(vmi, 0);
78+
for_each_vma(*vmi, vma) {
79+
detach_free_vma(vma);
80+
count++;
81+
}
82+
83+
mtree_destroy(&mm->mm_mt);
84+
mm->map_count = 0;
85+
return count;
86+
}
87+
88+
bool vma_write_started(struct vm_area_struct *vma)
89+
{
90+
int seq = vma->vm_lock_seq;
91+
92+
/* We reset after each check. */
93+
vma->vm_lock_seq = UINT_MAX;
94+
95+
/* The vma_start_write() stub simply increments this value. */
96+
return seq > -1;
97+
}
98+
99+
void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
100+
struct anon_vma_chain *avc, struct anon_vma *anon_vma)
101+
{
102+
vma->anon_vma = anon_vma;
103+
INIT_LIST_HEAD(&vma->anon_vma_chain);
104+
list_add(&avc->same_vma, &vma->anon_vma_chain);
105+
avc->anon_vma = vma->anon_vma;
106+
}
107+
108+
void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
109+
struct anon_vma_chain *avc)
110+
{
111+
__vma_set_dummy_anon_vma(vma, avc, &dummy_anon_vma);
112+
}
113+
114+
struct task_struct *get_current(void)
115+
{
116+
return &__current;
117+
}
118+
119+
unsigned long rlimit(unsigned int limit)
120+
{
121+
return (unsigned long)-1;
122+
}
123+
124+
void vma_set_range(struct vm_area_struct *vma,
125+
unsigned long start, unsigned long end,
126+
pgoff_t pgoff)
127+
{
128+
vma->vm_start = start;
129+
vma->vm_end = end;
130+
vma->vm_pgoff = pgoff;
131+
}

tools/testing/vma/shared.h

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
3+
#pragma once
4+
5+
#include <stdbool.h>
6+
#include <stdio.h>
7+
#include <stdlib.h>
8+
9+
#include "generated/bit-length.h"
10+
#include "maple-shared.h"
11+
#include "vma_internal.h"
12+
#include "../../../mm/vma.h"
13+
14+
/* Simple test runner. Assumes local num_[fail, tests] counters. */
15+
#define TEST(name) \
16+
do { \
17+
(*num_tests)++; \
18+
if (!test_##name()) { \
19+
(*num_fail)++; \
20+
fprintf(stderr, "Test " #name " FAILED\n"); \
21+
} \
22+
} while (0)
23+
24+
#define ASSERT_TRUE(_expr) \
25+
do { \
26+
if (!(_expr)) { \
27+
fprintf(stderr, \
28+
"Assert FAILED at %s:%d:%s(): %s is FALSE.\n", \
29+
__FILE__, __LINE__, __FUNCTION__, #_expr); \
30+
return false; \
31+
} \
32+
} while (0)
33+
34+
#define ASSERT_FALSE(_expr) ASSERT_TRUE(!(_expr))
35+
#define ASSERT_EQ(_val1, _val2) ASSERT_TRUE((_val1) == (_val2))
36+
#define ASSERT_NE(_val1, _val2) ASSERT_TRUE((_val1) != (_val2))
37+
38+
#define IS_SET(_val, _flags) ((_val & _flags) == _flags)
39+
40+
extern bool fail_prealloc;
41+
42+
/* Override vma_iter_prealloc() so we can choose to fail it. */
43+
#define vma_iter_prealloc(vmi, vma) \
44+
(fail_prealloc ? -ENOMEM : mas_preallocate(&(vmi)->mas, (vma), GFP_KERNEL))
45+
46+
#define CONFIG_DEFAULT_MMAP_MIN_ADDR 65536
47+
48+
extern unsigned long mmap_min_addr;
49+
extern unsigned long dac_mmap_min_addr;
50+
extern unsigned long stack_guard_gap;
51+
52+
extern const struct vm_operations_struct vma_dummy_vm_ops;
53+
extern struct anon_vma dummy_anon_vma;
54+
extern struct task_struct __current;
55+
56+
/*
57+
* Helper function which provides a wrapper around a merge existing VMA
58+
* operation.
59+
*
60+
* Declared in main.c as uses static VMA function.
61+
*/
62+
struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg);
63+
64+
/*
65+
* Helper function to allocate a VMA and link it to the tree.
66+
*
67+
* Declared in main.c as uses static VMA function.
68+
*/
69+
int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma);
70+
71+
/* Helper function providing a dummy vm_ops->close() method.*/
72+
static inline void dummy_close(struct vm_area_struct *)
73+
{
74+
}
75+
76+
/* Helper function to simply allocate a VMA. */
77+
struct vm_area_struct *alloc_vma(struct mm_struct *mm,
78+
unsigned long start, unsigned long end,
79+
pgoff_t pgoff, vm_flags_t vm_flags);
80+
81+
/* Helper function to detach and free a VMA. */
82+
void detach_free_vma(struct vm_area_struct *vma);
83+
84+
/* Helper function to allocate a VMA and link it to the tree. */
85+
struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
86+
unsigned long start, unsigned long end,
87+
pgoff_t pgoff, vm_flags_t vm_flags);
88+
89+
/*
90+
* Helper function to reset the dummy anon_vma to indicate it has not been
91+
* duplicated.
92+
*/
93+
void reset_dummy_anon_vma(void);
94+
95+
/*
96+
* Helper function to remove all VMAs and destroy the maple tree associated with
97+
* a virtual address space. Returns a count of VMAs in the tree.
98+
*/
99+
int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi);
100+
101+
/* Helper function to determine if VMA has had vma_start_write() performed. */
102+
bool vma_write_started(struct vm_area_struct *vma);
103+
104+
void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
105+
struct anon_vma_chain *avc, struct anon_vma *anon_vma);
106+
107+
/* Provide a simple dummy VMA/anon_vma dummy setup for testing. */
108+
void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
109+
struct anon_vma_chain *avc);
110+
111+
/* Helper function to specify a VMA's range. */
112+
void vma_set_range(struct vm_area_struct *vma,
113+
unsigned long start, unsigned long end,
114+
pgoff_t pgoff);

0 commit comments

Comments
 (0)