mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 15:41:52 +02:00
tools/testing/vma: add VMA sticky userland tests
Modify existing merge new/existing userland VMA tests to assert that sticky VMA flags behave as expected. We do so by generating every possible permutation of VMAs being manipulated being sticky/not sticky and asserting that VMA flags with this property retain are retained upon merge. Link: https://lkml.kernel.org/r/5e2c7244485867befd052f8afc8188be6a4be670.1763460113.git.lorenzo.stoakes@oracle.com Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Cc: Andrei Vagin <avagin@gmail.com> Cc: Baolin Wang <baolin.wang@linux.alibaba.com> Cc: Barry Song <baohua@kernel.org> Cc: David Hildenbrand (Red Hat) <david@kernel.org> Cc: Dev Jain <dev.jain@arm.com> Cc: Jann Horn <jannh@google.com> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Lance Yang <lance.yang@linux.dev> Cc: Liam Howlett <liam.howlett@oracle.com> Cc: "Masami Hiramatsu (Google)" <mhiramat@kernel.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Michal Hocko <mhocko@suse.com> Cc: Mike Rapoport <rppt@kernel.org> Cc: Nico Pache <npache@redhat.com> Cc: Pedro Falcato <pfalcato@suse.de> Cc: Ryan Roberts <ryan.roberts@arm.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Suren Baghdasaryan <surenb@google.com> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Zi Yan <ziy@nvidia.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
49e14dabed
commit
29bef05e6d
|
|
@ -48,6 +48,8 @@ static struct anon_vma dummy_anon_vma;
|
|||
#define ASSERT_EQ(_val1, _val2) ASSERT_TRUE((_val1) == (_val2))
|
||||
#define ASSERT_NE(_val1, _val2) ASSERT_TRUE((_val1) != (_val2))
|
||||
|
||||
#define IS_SET(_val, _flags) ((_val & _flags) == _flags)
|
||||
|
||||
static struct task_struct __current;
|
||||
|
||||
struct task_struct *get_current(void)
|
||||
|
|
@ -442,7 +444,7 @@ static bool test_simple_shrink(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool test_merge_new(void)
|
||||
static bool __test_merge_new(bool is_sticky, bool a_is_sticky, bool b_is_sticky, bool c_is_sticky)
|
||||
{
|
||||
vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
|
||||
struct mm_struct mm = {};
|
||||
|
|
@ -470,23 +472,32 @@ static bool test_merge_new(void)
|
|||
struct vm_area_struct *vma, *vma_a, *vma_b, *vma_c, *vma_d;
|
||||
bool merged;
|
||||
|
||||
if (is_sticky)
|
||||
vm_flags |= VM_STICKY;
|
||||
|
||||
/*
|
||||
* 0123456789abc
|
||||
* AA B CC
|
||||
*/
|
||||
vma_a = alloc_and_link_vma(&mm, 0, 0x2000, 0, vm_flags);
|
||||
ASSERT_NE(vma_a, NULL);
|
||||
if (a_is_sticky)
|
||||
vm_flags_set(vma_a, VM_STICKY);
|
||||
/* We give each VMA a single avc so we can test anon_vma duplication. */
|
||||
INIT_LIST_HEAD(&vma_a->anon_vma_chain);
|
||||
list_add(&dummy_anon_vma_chain_a.same_vma, &vma_a->anon_vma_chain);
|
||||
|
||||
vma_b = alloc_and_link_vma(&mm, 0x3000, 0x4000, 3, vm_flags);
|
||||
ASSERT_NE(vma_b, NULL);
|
||||
if (b_is_sticky)
|
||||
vm_flags_set(vma_b, VM_STICKY);
|
||||
INIT_LIST_HEAD(&vma_b->anon_vma_chain);
|
||||
list_add(&dummy_anon_vma_chain_b.same_vma, &vma_b->anon_vma_chain);
|
||||
|
||||
vma_c = alloc_and_link_vma(&mm, 0xb000, 0xc000, 0xb, vm_flags);
|
||||
ASSERT_NE(vma_c, NULL);
|
||||
if (c_is_sticky)
|
||||
vm_flags_set(vma_c, VM_STICKY);
|
||||
INIT_LIST_HEAD(&vma_c->anon_vma_chain);
|
||||
list_add(&dummy_anon_vma_chain_c.same_vma, &vma_c->anon_vma_chain);
|
||||
|
||||
|
|
@ -521,6 +532,8 @@ static bool test_merge_new(void)
|
|||
ASSERT_EQ(vma->anon_vma, &dummy_anon_vma);
|
||||
ASSERT_TRUE(vma_write_started(vma));
|
||||
ASSERT_EQ(mm.map_count, 3);
|
||||
if (is_sticky || a_is_sticky || b_is_sticky)
|
||||
ASSERT_TRUE(IS_SET(vma->vm_flags, VM_STICKY));
|
||||
|
||||
/*
|
||||
* Merge to PREVIOUS VMA.
|
||||
|
|
@ -538,6 +551,8 @@ static bool test_merge_new(void)
|
|||
ASSERT_EQ(vma->anon_vma, &dummy_anon_vma);
|
||||
ASSERT_TRUE(vma_write_started(vma));
|
||||
ASSERT_EQ(mm.map_count, 3);
|
||||
if (is_sticky || a_is_sticky)
|
||||
ASSERT_TRUE(IS_SET(vma->vm_flags, VM_STICKY));
|
||||
|
||||
/*
|
||||
* Merge to NEXT VMA.
|
||||
|
|
@ -557,6 +572,8 @@ static bool test_merge_new(void)
|
|||
ASSERT_EQ(vma->anon_vma, &dummy_anon_vma);
|
||||
ASSERT_TRUE(vma_write_started(vma));
|
||||
ASSERT_EQ(mm.map_count, 3);
|
||||
if (is_sticky) /* D uses is_sticky. */
|
||||
ASSERT_TRUE(IS_SET(vma->vm_flags, VM_STICKY));
|
||||
|
||||
/*
|
||||
* Merge BOTH sides.
|
||||
|
|
@ -575,6 +592,8 @@ static bool test_merge_new(void)
|
|||
ASSERT_EQ(vma->anon_vma, &dummy_anon_vma);
|
||||
ASSERT_TRUE(vma_write_started(vma));
|
||||
ASSERT_EQ(mm.map_count, 2);
|
||||
if (is_sticky || a_is_sticky)
|
||||
ASSERT_TRUE(IS_SET(vma->vm_flags, VM_STICKY));
|
||||
|
||||
/*
|
||||
* Merge to NEXT VMA.
|
||||
|
|
@ -593,6 +612,8 @@ static bool test_merge_new(void)
|
|||
ASSERT_EQ(vma->anon_vma, &dummy_anon_vma);
|
||||
ASSERT_TRUE(vma_write_started(vma));
|
||||
ASSERT_EQ(mm.map_count, 2);
|
||||
if (is_sticky || c_is_sticky)
|
||||
ASSERT_TRUE(IS_SET(vma->vm_flags, VM_STICKY));
|
||||
|
||||
/*
|
||||
* Merge BOTH sides.
|
||||
|
|
@ -610,6 +631,8 @@ static bool test_merge_new(void)
|
|||
ASSERT_EQ(vma->anon_vma, &dummy_anon_vma);
|
||||
ASSERT_TRUE(vma_write_started(vma));
|
||||
ASSERT_EQ(mm.map_count, 1);
|
||||
if (is_sticky || a_is_sticky || c_is_sticky)
|
||||
ASSERT_TRUE(IS_SET(vma->vm_flags, VM_STICKY));
|
||||
|
||||
/*
|
||||
* Final state.
|
||||
|
|
@ -638,6 +661,20 @@ static bool test_merge_new(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool test_merge_new(void)
|
||||
{
|
||||
int i, j, k, l;
|
||||
|
||||
/* Generate every possible permutation of sticky flags. */
|
||||
for (i = 0; i < 2; i++)
|
||||
for (j = 0; j < 2; j++)
|
||||
for (k = 0; k < 2; k++)
|
||||
for (l = 0; l < 2; l++)
|
||||
ASSERT_TRUE(__test_merge_new(i, j, k, l));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test_vma_merge_special_flags(void)
|
||||
{
|
||||
vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
|
||||
|
|
@ -974,9 +1011,11 @@ static bool test_vma_merge_new_with_close(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool test_merge_existing(void)
|
||||
static bool __test_merge_existing(bool prev_is_sticky, bool middle_is_sticky, bool next_is_sticky)
|
||||
{
|
||||
vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
|
||||
vm_flags_t prev_flags = vm_flags;
|
||||
vm_flags_t next_flags = vm_flags;
|
||||
struct mm_struct mm = {};
|
||||
VMA_ITERATOR(vmi, &mm, 0);
|
||||
struct vm_area_struct *vma, *vma_prev, *vma_next;
|
||||
|
|
@ -989,6 +1028,13 @@ static bool test_merge_existing(void)
|
|||
};
|
||||
struct anon_vma_chain avc = {};
|
||||
|
||||
if (prev_is_sticky)
|
||||
prev_flags |= VM_STICKY;
|
||||
if (middle_is_sticky)
|
||||
vm_flags |= VM_STICKY;
|
||||
if (next_is_sticky)
|
||||
next_flags |= VM_STICKY;
|
||||
|
||||
/*
|
||||
* Merge right case - partial span.
|
||||
*
|
||||
|
|
@ -1001,7 +1047,7 @@ static bool test_merge_existing(void)
|
|||
*/
|
||||
vma = alloc_and_link_vma(&mm, 0x2000, 0x6000, 2, vm_flags);
|
||||
vma->vm_ops = &vm_ops; /* This should have no impact. */
|
||||
vma_next = alloc_and_link_vma(&mm, 0x6000, 0x9000, 6, vm_flags);
|
||||
vma_next = alloc_and_link_vma(&mm, 0x6000, 0x9000, 6, next_flags);
|
||||
vma_next->vm_ops = &vm_ops; /* This should have no impact. */
|
||||
vmg_set_range_anon_vma(&vmg, 0x3000, 0x6000, 3, vm_flags, &dummy_anon_vma);
|
||||
vmg.middle = vma;
|
||||
|
|
@ -1019,6 +1065,8 @@ static bool test_merge_existing(void)
|
|||
ASSERT_TRUE(vma_write_started(vma));
|
||||
ASSERT_TRUE(vma_write_started(vma_next));
|
||||
ASSERT_EQ(mm.map_count, 2);
|
||||
if (middle_is_sticky || next_is_sticky)
|
||||
ASSERT_TRUE(IS_SET(vma_next->vm_flags, VM_STICKY));
|
||||
|
||||
/* Clear down and reset. */
|
||||
ASSERT_EQ(cleanup_mm(&mm, &vmi), 2);
|
||||
|
|
@ -1034,7 +1082,7 @@ static bool test_merge_existing(void)
|
|||
* NNNNNNN
|
||||
*/
|
||||
vma = alloc_and_link_vma(&mm, 0x2000, 0x6000, 2, vm_flags);
|
||||
vma_next = alloc_and_link_vma(&mm, 0x6000, 0x9000, 6, vm_flags);
|
||||
vma_next = alloc_and_link_vma(&mm, 0x6000, 0x9000, 6, next_flags);
|
||||
vma_next->vm_ops = &vm_ops; /* This should have no impact. */
|
||||
vmg_set_range_anon_vma(&vmg, 0x2000, 0x6000, 2, vm_flags, &dummy_anon_vma);
|
||||
vmg.middle = vma;
|
||||
|
|
@ -1047,6 +1095,8 @@ static bool test_merge_existing(void)
|
|||
ASSERT_EQ(vma_next->anon_vma, &dummy_anon_vma);
|
||||
ASSERT_TRUE(vma_write_started(vma_next));
|
||||
ASSERT_EQ(mm.map_count, 1);
|
||||
if (middle_is_sticky || next_is_sticky)
|
||||
ASSERT_TRUE(IS_SET(vma_next->vm_flags, VM_STICKY));
|
||||
|
||||
/* Clear down and reset. We should have deleted vma. */
|
||||
ASSERT_EQ(cleanup_mm(&mm, &vmi), 1);
|
||||
|
|
@ -1061,7 +1111,7 @@ static bool test_merge_existing(void)
|
|||
* 0123456789
|
||||
* PPPPPPV
|
||||
*/
|
||||
vma_prev = alloc_and_link_vma(&mm, 0, 0x3000, 0, vm_flags);
|
||||
vma_prev = alloc_and_link_vma(&mm, 0, 0x3000, 0, prev_flags);
|
||||
vma_prev->vm_ops = &vm_ops; /* This should have no impact. */
|
||||
vma = alloc_and_link_vma(&mm, 0x3000, 0x7000, 3, vm_flags);
|
||||
vma->vm_ops = &vm_ops; /* This should have no impact. */
|
||||
|
|
@ -1081,6 +1131,8 @@ static bool test_merge_existing(void)
|
|||
ASSERT_TRUE(vma_write_started(vma_prev));
|
||||
ASSERT_TRUE(vma_write_started(vma));
|
||||
ASSERT_EQ(mm.map_count, 2);
|
||||
if (prev_is_sticky || middle_is_sticky)
|
||||
ASSERT_TRUE(IS_SET(vma_prev->vm_flags, VM_STICKY));
|
||||
|
||||
/* Clear down and reset. */
|
||||
ASSERT_EQ(cleanup_mm(&mm, &vmi), 2);
|
||||
|
|
@ -1095,7 +1147,7 @@ static bool test_merge_existing(void)
|
|||
* 0123456789
|
||||
* PPPPPPP
|
||||
*/
|
||||
vma_prev = alloc_and_link_vma(&mm, 0, 0x3000, 0, vm_flags);
|
||||
vma_prev = alloc_and_link_vma(&mm, 0, 0x3000, 0, prev_flags);
|
||||
vma_prev->vm_ops = &vm_ops; /* This should have no impact. */
|
||||
vma = alloc_and_link_vma(&mm, 0x3000, 0x7000, 3, vm_flags);
|
||||
vmg_set_range_anon_vma(&vmg, 0x3000, 0x7000, 3, vm_flags, &dummy_anon_vma);
|
||||
|
|
@ -1110,6 +1162,8 @@ static bool test_merge_existing(void)
|
|||
ASSERT_EQ(vma_prev->anon_vma, &dummy_anon_vma);
|
||||
ASSERT_TRUE(vma_write_started(vma_prev));
|
||||
ASSERT_EQ(mm.map_count, 1);
|
||||
if (prev_is_sticky || middle_is_sticky)
|
||||
ASSERT_TRUE(IS_SET(vma_prev->vm_flags, VM_STICKY));
|
||||
|
||||
/* Clear down and reset. We should have deleted vma. */
|
||||
ASSERT_EQ(cleanup_mm(&mm, &vmi), 1);
|
||||
|
|
@ -1124,10 +1178,10 @@ static bool test_merge_existing(void)
|
|||
* 0123456789
|
||||
* PPPPPPPPPP
|
||||
*/
|
||||
vma_prev = alloc_and_link_vma(&mm, 0, 0x3000, 0, vm_flags);
|
||||
vma_prev = alloc_and_link_vma(&mm, 0, 0x3000, 0, prev_flags);
|
||||
vma_prev->vm_ops = &vm_ops; /* This should have no impact. */
|
||||
vma = alloc_and_link_vma(&mm, 0x3000, 0x7000, 3, vm_flags);
|
||||
vma_next = alloc_and_link_vma(&mm, 0x7000, 0x9000, 7, vm_flags);
|
||||
vma_next = alloc_and_link_vma(&mm, 0x7000, 0x9000, 7, next_flags);
|
||||
vmg_set_range_anon_vma(&vmg, 0x3000, 0x7000, 3, vm_flags, &dummy_anon_vma);
|
||||
vmg.prev = vma_prev;
|
||||
vmg.middle = vma;
|
||||
|
|
@ -1140,6 +1194,8 @@ static bool test_merge_existing(void)
|
|||
ASSERT_EQ(vma_prev->anon_vma, &dummy_anon_vma);
|
||||
ASSERT_TRUE(vma_write_started(vma_prev));
|
||||
ASSERT_EQ(mm.map_count, 1);
|
||||
if (prev_is_sticky || middle_is_sticky || next_is_sticky)
|
||||
ASSERT_TRUE(IS_SET(vma_prev->vm_flags, VM_STICKY));
|
||||
|
||||
/* Clear down and reset. We should have deleted prev and next. */
|
||||
ASSERT_EQ(cleanup_mm(&mm, &vmi), 1);
|
||||
|
|
@ -1159,9 +1215,9 @@ static bool test_merge_existing(void)
|
|||
* PPPVVVVVNNN
|
||||
*/
|
||||
|
||||
vma_prev = alloc_and_link_vma(&mm, 0, 0x3000, 0, vm_flags);
|
||||
vma_prev = alloc_and_link_vma(&mm, 0, 0x3000, 0, prev_flags);
|
||||
vma = alloc_and_link_vma(&mm, 0x3000, 0x8000, 3, vm_flags);
|
||||
vma_next = alloc_and_link_vma(&mm, 0x8000, 0xa000, 8, vm_flags);
|
||||
vma_next = alloc_and_link_vma(&mm, 0x8000, 0xa000, 8, next_flags);
|
||||
|
||||
vmg_set_range(&vmg, 0x4000, 0x5000, 4, vm_flags);
|
||||
vmg.prev = vma;
|
||||
|
|
@ -1204,6 +1260,19 @@ static bool test_merge_existing(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool test_merge_existing(void)
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
/* Generate every possible permutation of sticky flags. */
|
||||
for (i = 0; i < 2; i++)
|
||||
for (j = 0; j < 2; j++)
|
||||
for (k = 0; k < 2; k++)
|
||||
ASSERT_TRUE(__test_merge_existing(i, j, k));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test_anon_vma_non_mergeable(void)
|
||||
{
|
||||
vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user