Skip to content

Commit f615cc9

Browse files
ljskernelakpm00
authored andcommitted
tools/testing/vma: add VMA userland tests for VMA flag functions
Now we have the capability to test the new helpers for the bitmap VMA flags in userland, do so. We also update the Makefile such that both VMA (and while we're here) mm_struct flag sizes can be customised on build. We default to 128-bit to enable testing of flags above word size even on 64-bit systems. We add userland tests to ensure that we do not regress VMA flag behaviour with the introduction when using bitmap VMA flags, nor accidentally introduce unexpected results due to for instance higher bit values not being correctly cleared/set. As part of this change, make __mk_vma_flags() a custom function so we can handle specifying invalid VMA bits. This is purposeful so we can have the VMA tests work at lower and higher number of VMA flags without having to duplicate code too much. Link: https://lkml.kernel.org/r/7fe6afe9c8c61e4d3cfc9a2d50a5d24da8528e68.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 a1f0dac commit f615cc9

5 files changed

Lines changed: 322 additions & 12 deletions

File tree

tools/testing/vma/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ include ../shared/shared.mk
99
OFILES = $(SHARED_OFILES) main.o shared.o maple-shim.o
1010
TARGETS = vma
1111

12+
# These can be varied to test different sizes.
13+
CFLAGS += -DNUM_VMA_FLAG_BITS=128 -DNUM_MM_FLAG_BITS=128
14+
1215
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 include/custom.h include/dup.h include/stubs.h
1316

1417
vma: $(OFILES)

tools/testing/vma/include/custom.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,19 @@ static inline void vma_lock_init(struct vm_area_struct *vma, bool reset_refcnt)
101101
if (reset_refcnt)
102102
refcount_set(&vma->vm_refcnt, 0);
103103
}
104+
105+
static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
106+
{
107+
vma_flags_t flags;
108+
int i;
109+
110+
/*
111+
* For testing purposes: allow invalid bit specification so we can
112+
* easily test.
113+
*/
114+
vma_flags_clear_all(&flags);
115+
for (i = 0; i < count; i++)
116+
if (bits[i] < NUM_VMA_FLAG_BITS)
117+
vma_flag_set(&flags, bits[i]);
118+
return flags;
119+
}

tools/testing/vma/include/dup.h

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -838,16 +838,7 @@ static inline void vm_flags_clear(struct vm_area_struct *vma,
838838
vma_flags_clear_word(&vma->flags, flags);
839839
}
840840

841-
static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
842-
{
843-
vma_flags_t flags;
844-
int i;
845-
846-
vma_flags_clear_all(&flags);
847-
for (i = 0; i < count; i++)
848-
vma_flag_set(&flags, bits[i]);
849-
return flags;
850-
}
841+
static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits);
851842

852843
#define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
853844
(const vma_flag_t []){__VA_ARGS__})

tools/testing/vma/tests/vma.c

Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,25 @@
11
// SPDX-License-Identifier: GPL-2.0-or-later
22

3+
static bool compare_legacy_flags(vm_flags_t legacy_flags, vma_flags_t flags)
4+
{
5+
const unsigned long legacy_val = legacy_flags;
6+
/* The lower word should contain the precise same value. */
7+
const unsigned long flags_lower = flags.__vma_flags[0];
8+
#if NUM_VMA_FLAGS > BITS_PER_LONG
9+
int i;
10+
11+
/* All bits in higher flag values should be zero. */
12+
for (i = 1; i < NUM_VMA_FLAGS / BITS_PER_LONG; i++) {
13+
if (flags.__vma_flags[i] != 0)
14+
return false;
15+
}
16+
#endif
17+
18+
static_assert(sizeof(legacy_flags) == sizeof(unsigned long));
19+
20+
return legacy_val == flags_lower;
21+
}
22+
323
static bool test_copy_vma(void)
424
{
525
vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
@@ -33,7 +53,287 @@ static bool test_copy_vma(void)
3353
return true;
3454
}
3555

56+
static bool test_vma_flags_unchanged(void)
57+
{
58+
vma_flags_t flags = EMPTY_VMA_FLAGS;
59+
vm_flags_t legacy_flags = 0;
60+
int bit;
61+
struct vm_area_struct vma;
62+
struct vm_area_desc desc;
63+
64+
65+
vma.flags = EMPTY_VMA_FLAGS;
66+
desc.vma_flags = EMPTY_VMA_FLAGS;
67+
68+
for (bit = 0; bit < BITS_PER_LONG; bit++) {
69+
vma_flags_t mask = mk_vma_flags(bit);
70+
71+
legacy_flags |= (1UL << bit);
72+
73+
/* Individual flags. */
74+
vma_flags_set(&flags, bit);
75+
ASSERT_TRUE(compare_legacy_flags(legacy_flags, flags));
76+
77+
/* Via mask. */
78+
vma_flags_set_mask(&flags, mask);
79+
ASSERT_TRUE(compare_legacy_flags(legacy_flags, flags));
80+
81+
/* Same for VMA. */
82+
vma_set_flags(&vma, bit);
83+
ASSERT_TRUE(compare_legacy_flags(legacy_flags, vma.flags));
84+
vma_set_flags_mask(&vma, mask);
85+
ASSERT_TRUE(compare_legacy_flags(legacy_flags, vma.flags));
86+
87+
/* Same for VMA descriptor. */
88+
vma_desc_set_flags(&desc, bit);
89+
ASSERT_TRUE(compare_legacy_flags(legacy_flags, desc.vma_flags));
90+
vma_desc_set_flags_mask(&desc, mask);
91+
ASSERT_TRUE(compare_legacy_flags(legacy_flags, desc.vma_flags));
92+
}
93+
94+
return true;
95+
}
96+
97+
static bool test_vma_flags_cleared(void)
98+
{
99+
const vma_flags_t empty = EMPTY_VMA_FLAGS;
100+
vma_flags_t flags;
101+
int i;
102+
103+
/* Set all bits high. */
104+
memset(&flags, 1, sizeof(flags));
105+
/* Try to clear. */
106+
vma_flags_clear_all(&flags);
107+
/* Equal to EMPTY_VMA_FLAGS? */
108+
ASSERT_EQ(memcmp(&empty, &flags, sizeof(flags)), 0);
109+
/* Make sure every unsigned long entry in bitmap array zero. */
110+
for (i = 0; i < sizeof(flags) / BITS_PER_LONG; i++) {
111+
const unsigned long val = flags.__vma_flags[i];
112+
113+
ASSERT_EQ(val, 0);
114+
}
115+
116+
return true;
117+
}
118+
119+
/*
120+
* Assert that VMA flag functions that operate at the system word level function
121+
* correctly.
122+
*/
123+
static bool test_vma_flags_word(void)
124+
{
125+
vma_flags_t flags = EMPTY_VMA_FLAGS;
126+
const vma_flags_t comparison =
127+
mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT, 64, 65);
128+
129+
/* Set some custom high flags. */
130+
vma_flags_set(&flags, 64, 65);
131+
/* Now overwrite the first word. */
132+
vma_flags_overwrite_word(&flags, VM_READ | VM_WRITE);
133+
/* Ensure they are equal. */
134+
ASSERT_EQ(memcmp(&flags, &comparison, sizeof(flags)), 0);
135+
136+
flags = EMPTY_VMA_FLAGS;
137+
vma_flags_set(&flags, 64, 65);
138+
139+
/* Do the same with the _once() equivalent. */
140+
vma_flags_overwrite_word_once(&flags, VM_READ | VM_WRITE);
141+
ASSERT_EQ(memcmp(&flags, &comparison, sizeof(flags)), 0);
142+
143+
flags = EMPTY_VMA_FLAGS;
144+
vma_flags_set(&flags, 64, 65);
145+
146+
/* Make sure we can set a word without disturbing other bits. */
147+
vma_flags_set(&flags, VMA_WRITE_BIT);
148+
vma_flags_set_word(&flags, VM_READ);
149+
ASSERT_EQ(memcmp(&flags, &comparison, sizeof(flags)), 0);
150+
151+
flags = EMPTY_VMA_FLAGS;
152+
vma_flags_set(&flags, 64, 65);
153+
154+
/* Make sure we can clear a word without disturbing other bits. */
155+
vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
156+
vma_flags_clear_word(&flags, VM_EXEC);
157+
ASSERT_EQ(memcmp(&flags, &comparison, sizeof(flags)), 0);
158+
159+
return true;
160+
}
161+
162+
/* Ensure that vma_flags_test() and friends works correctly. */
163+
static bool test_vma_flags_test(void)
164+
{
165+
const vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT,
166+
VMA_EXEC_BIT, 64, 65);
167+
struct vm_area_struct vma;
168+
struct vm_area_desc desc;
169+
170+
vma.flags = flags;
171+
desc.vma_flags = flags;
172+
173+
#define do_test(...) \
174+
ASSERT_TRUE(vma_flags_test(&flags, __VA_ARGS__)); \
175+
ASSERT_TRUE(vma_desc_test_flags(&desc, __VA_ARGS__))
176+
177+
#define do_test_all_true(...) \
178+
ASSERT_TRUE(vma_flags_test_all(&flags, __VA_ARGS__)); \
179+
ASSERT_TRUE(vma_test_all_flags(&vma, __VA_ARGS__))
180+
181+
#define do_test_all_false(...) \
182+
ASSERT_FALSE(vma_flags_test_all(&flags, __VA_ARGS__)); \
183+
ASSERT_FALSE(vma_test_all_flags(&vma, __VA_ARGS__))
184+
185+
/*
186+
* Testing for some flags that are present, some that are not - should
187+
* pass. ANY flags matching should work.
188+
*/
189+
do_test(VMA_READ_BIT, VMA_MAYREAD_BIT, VMA_SEQ_READ_BIT);
190+
/* However, the ...test_all() variant should NOT pass. */
191+
do_test_all_false(VMA_READ_BIT, VMA_MAYREAD_BIT, VMA_SEQ_READ_BIT);
192+
/* But should pass for flags present. */
193+
do_test_all_true(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT, 64, 65);
194+
/* Also subsets... */
195+
do_test_all_true(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT, 64);
196+
do_test_all_true(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
197+
do_test_all_true(VMA_READ_BIT, VMA_WRITE_BIT);
198+
do_test_all_true(VMA_READ_BIT);
199+
/*
200+
* Check _mask variant. We don't need to test extensively as macro
201+
* helper is the equivalent.
202+
*/
203+
ASSERT_TRUE(vma_flags_test_mask(&flags, flags));
204+
ASSERT_TRUE(vma_flags_test_all_mask(&flags, flags));
205+
206+
/* Single bits. */
207+
do_test(VMA_READ_BIT);
208+
do_test(VMA_WRITE_BIT);
209+
do_test(VMA_EXEC_BIT);
210+
#if NUM_VMA_FLAG_BITS > 64
211+
do_test(64);
212+
do_test(65);
213+
#endif
214+
215+
/* Two bits. */
216+
do_test(VMA_READ_BIT, VMA_WRITE_BIT);
217+
do_test(VMA_READ_BIT, VMA_EXEC_BIT);
218+
do_test(VMA_WRITE_BIT, VMA_EXEC_BIT);
219+
/* Ordering shouldn't matter. */
220+
do_test(VMA_WRITE_BIT, VMA_READ_BIT);
221+
do_test(VMA_EXEC_BIT, VMA_READ_BIT);
222+
do_test(VMA_EXEC_BIT, VMA_WRITE_BIT);
223+
#if NUM_VMA_FLAG_BITS > 64
224+
do_test(VMA_READ_BIT, 64);
225+
do_test(VMA_WRITE_BIT, 64);
226+
do_test(64, VMA_READ_BIT);
227+
do_test(64, VMA_WRITE_BIT);
228+
do_test(VMA_READ_BIT, 65);
229+
do_test(VMA_WRITE_BIT, 65);
230+
do_test(65, VMA_READ_BIT);
231+
do_test(65, VMA_WRITE_BIT);
232+
#endif
233+
/* Three bits. */
234+
do_test(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
235+
#if NUM_VMA_FLAG_BITS > 64
236+
/* No need to consider every single permutation. */
237+
do_test(VMA_READ_BIT, VMA_WRITE_BIT, 64);
238+
do_test(VMA_READ_BIT, VMA_WRITE_BIT, 65);
239+
240+
/* Four bits. */
241+
do_test(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT, 64);
242+
do_test(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT, 65);
243+
244+
/* Five bits. */
245+
do_test(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT, 64, 65);
246+
#endif
247+
248+
#undef do_test
249+
#undef do_test_all_true
250+
#undef do_test_all_false
251+
252+
return true;
253+
}
254+
255+
/* Ensure that vma_flags_clear() and friends works correctly. */
256+
static bool test_vma_flags_clear(void)
257+
{
258+
vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT,
259+
VMA_EXEC_BIT, 64, 65);
260+
vma_flags_t mask = mk_vma_flags(VMA_EXEC_BIT, 64);
261+
struct vm_area_struct vma;
262+
struct vm_area_desc desc;
263+
264+
vma.flags = flags;
265+
desc.vma_flags = flags;
266+
267+
/* Cursory check of _mask() variant, as the helper macros imply. */
268+
vma_flags_clear_mask(&flags, mask);
269+
vma_flags_clear_mask(&vma.flags, mask);
270+
vma_desc_clear_flags_mask(&desc, mask);
271+
ASSERT_FALSE(vma_flags_test(&flags, VMA_EXEC_BIT, 64));
272+
ASSERT_FALSE(vma_flags_test(&vma.flags, VMA_EXEC_BIT, 64));
273+
ASSERT_FALSE(vma_desc_test_flags(&desc, VMA_EXEC_BIT, 64));
274+
/* Reset. */
275+
vma_flags_set(&flags, VMA_EXEC_BIT, 64);
276+
vma_set_flags(&vma, VMA_EXEC_BIT, 64);
277+
vma_desc_set_flags(&desc, VMA_EXEC_BIT, 64);
278+
279+
/*
280+
* Clear the flags and assert clear worked, then reset flags back to
281+
* include specified flags.
282+
*/
283+
#define do_test_and_reset(...) \
284+
vma_flags_clear(&flags, __VA_ARGS__); \
285+
vma_flags_clear(&vma.flags, __VA_ARGS__); \
286+
vma_desc_clear_flags(&desc, __VA_ARGS__); \
287+
ASSERT_FALSE(vma_flags_test(&flags, __VA_ARGS__)); \
288+
ASSERT_FALSE(vma_flags_test(&vma.flags, __VA_ARGS__)); \
289+
ASSERT_FALSE(vma_desc_test_flags(&desc, __VA_ARGS__)); \
290+
vma_flags_set(&flags, __VA_ARGS__); \
291+
vma_set_flags(&vma, __VA_ARGS__); \
292+
vma_desc_set_flags(&desc, __VA_ARGS__)
293+
294+
/* Single flags. */
295+
do_test_and_reset(VMA_READ_BIT);
296+
do_test_and_reset(VMA_WRITE_BIT);
297+
do_test_and_reset(VMA_EXEC_BIT);
298+
do_test_and_reset(64);
299+
do_test_and_reset(65);
300+
301+
/* Two flags, in different orders. */
302+
do_test_and_reset(VMA_READ_BIT, VMA_WRITE_BIT);
303+
do_test_and_reset(VMA_READ_BIT, VMA_EXEC_BIT);
304+
do_test_and_reset(VMA_READ_BIT, 64);
305+
do_test_and_reset(VMA_READ_BIT, 65);
306+
do_test_and_reset(VMA_WRITE_BIT, VMA_READ_BIT);
307+
do_test_and_reset(VMA_WRITE_BIT, VMA_EXEC_BIT);
308+
do_test_and_reset(VMA_WRITE_BIT, 64);
309+
do_test_and_reset(VMA_WRITE_BIT, 65);
310+
do_test_and_reset(VMA_EXEC_BIT, VMA_READ_BIT);
311+
do_test_and_reset(VMA_EXEC_BIT, VMA_WRITE_BIT);
312+
do_test_and_reset(VMA_EXEC_BIT, 64);
313+
do_test_and_reset(VMA_EXEC_BIT, 65);
314+
do_test_and_reset(64, VMA_READ_BIT);
315+
do_test_and_reset(64, VMA_WRITE_BIT);
316+
do_test_and_reset(64, VMA_EXEC_BIT);
317+
do_test_and_reset(64, 65);
318+
do_test_and_reset(65, VMA_READ_BIT);
319+
do_test_and_reset(65, VMA_WRITE_BIT);
320+
do_test_and_reset(65, VMA_EXEC_BIT);
321+
do_test_and_reset(65, 64);
322+
323+
/* Three flags. */
324+
325+
#undef do_test_some_missing
326+
#undef do_test_and_reset
327+
328+
return true;
329+
}
330+
36331
static void run_vma_tests(int *num_tests, int *num_fail)
37332
{
38333
TEST(copy_vma);
334+
TEST(vma_flags_unchanged);
335+
TEST(vma_flags_cleared);
336+
TEST(vma_flags_word);
337+
TEST(vma_flags_test);
338+
TEST(vma_flags_clear);
39339
}

tools/testing/vma/vma_internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@
3636
* ahead of all other headers.
3737
*/
3838
#define __private
39-
#define NUM_MM_FLAG_BITS (64)
39+
/* NUM_MM_FLAG_BITS defined by test code. */
4040
typedef struct {
4141
__private DECLARE_BITMAP(__mm_flags, NUM_MM_FLAG_BITS);
4242
} mm_flags_t;
43-
#define NUM_VMA_FLAG_BITS BITS_PER_LONG
43+
/* NUM_VMA_FLAG_BITS defined by test code. */
4444
typedef struct {
4545
DECLARE_BITMAP(__vma_flags, NUM_VMA_FLAG_BITS);
4646
} __private vma_flags_t;

0 commit comments

Comments
 (0)