Skip to content

Commit ed8ea81

Browse files
walken-googletorvalds
authored andcommitted
mm: add CONFIG_DEBUG_VM_RB build option
Add a CONFIG_DEBUG_VM_RB build option for the previously existing DEBUG_MM_RB code. Now that Andi Kleen modified it to avoid using recursive algorithms, we can expose it a bit more. Also extend this code to validate_mm() after stack expansion, and to check that the vma's start and last pgoffs have not changed since the nodes were inserted on the anon vma interval tree (as it is important that the nodes be reindexed after each such update). Signed-off-by: Michel Lespinasse <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: Rik van Riel <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Daniel Santos <[email protected]> Cc: Hugh Dickins <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 86c2ad1 commit ed8ea81

File tree

5 files changed

+64
-11
lines changed

5 files changed

+64
-11
lines changed

include/linux/mm.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,6 +1386,9 @@ struct anon_vma_chain *anon_vma_interval_tree_iter_first(
13861386
struct rb_root *root, unsigned long start, unsigned long last);
13871387
struct anon_vma_chain *anon_vma_interval_tree_iter_next(
13881388
struct anon_vma_chain *node, unsigned long start, unsigned long last);
1389+
#ifdef CONFIG_DEBUG_VM_RB
1390+
void anon_vma_interval_tree_verify(struct anon_vma_chain *node);
1391+
#endif
13891392

13901393
#define anon_vma_interval_tree_foreach(avc, root, start, last) \
13911394
for (avc = anon_vma_interval_tree_iter_first(root, start, last); \

include/linux/rmap.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ struct anon_vma_chain {
6666
struct list_head same_vma; /* locked by mmap_sem & page_table_lock */
6767
struct rb_node rb; /* locked by anon_vma->mutex */
6868
unsigned long rb_subtree_last;
69+
#ifdef CONFIG_DEBUG_VM_RB
70+
unsigned long cached_vma_start, cached_vma_last;
71+
#endif
6972
};
7073

7174
#ifdef CONFIG_MMU

lib/Kconfig.debug

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,15 @@ config DEBUG_VM
798798

799799
If unsure, say N.
800800

801+
config DEBUG_VM_RB
802+
bool "Debug VM red-black trees"
803+
depends on DEBUG_VM
804+
help
805+
Enable this to turn on more extended checks in the virtual-memory
806+
system that may impact performance.
807+
808+
If unsure, say N.
809+
801810
config DEBUG_VIRTUAL
802811
bool "Debug VM translations"
803812
depends on DEBUG_KERNEL && X86

mm/interval_tree.c

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,43 @@ static inline unsigned long avc_last_pgoff(struct anon_vma_chain *avc)
7070
}
7171

7272
INTERVAL_TREE_DEFINE(struct anon_vma_chain, rb, unsigned long, rb_subtree_last,
73-
avc_start_pgoff, avc_last_pgoff,, anon_vma_interval_tree)
73+
avc_start_pgoff, avc_last_pgoff,
74+
static inline, __anon_vma_interval_tree)
75+
76+
void anon_vma_interval_tree_insert(struct anon_vma_chain *node,
77+
struct rb_root *root)
78+
{
79+
#ifdef CONFIG_DEBUG_VM_RB
80+
node->cached_vma_start = avc_start_pgoff(node);
81+
node->cached_vma_last = avc_last_pgoff(node);
82+
#endif
83+
__anon_vma_interval_tree_insert(node, root);
84+
}
85+
86+
void anon_vma_interval_tree_remove(struct anon_vma_chain *node,
87+
struct rb_root *root)
88+
{
89+
__anon_vma_interval_tree_remove(node, root);
90+
}
91+
92+
struct anon_vma_chain *
93+
anon_vma_interval_tree_iter_first(struct rb_root *root,
94+
unsigned long first, unsigned long last)
95+
{
96+
return __anon_vma_interval_tree_iter_first(root, first, last);
97+
}
98+
99+
struct anon_vma_chain *
100+
anon_vma_interval_tree_iter_next(struct anon_vma_chain *node,
101+
unsigned long first, unsigned long last)
102+
{
103+
return __anon_vma_interval_tree_iter_next(node, first, last);
104+
}
105+
106+
#ifdef CONFIG_DEBUG_VM_RB
107+
void anon_vma_interval_tree_verify(struct anon_vma_chain *node)
108+
{
109+
WARN_ON_ONCE(node->cached_vma_start != avc_start_pgoff(node));
110+
WARN_ON_ONCE(node->cached_vma_last != avc_last_pgoff(node));
111+
}
112+
#endif

mm/mmap.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,6 @@ static void unmap_region(struct mm_struct *mm,
5151
struct vm_area_struct *vma, struct vm_area_struct *prev,
5252
unsigned long start, unsigned long end);
5353

54-
/*
55-
* WARNING: the debugging will use recursive algorithms so never enable this
56-
* unless you know what you are doing.
57-
*/
58-
#undef DEBUG_MM_RB
59-
6054
/* description of effects of mapping type and prot in current implementation.
6155
* this is due to the limited x86 page protection hardware. The expected
6256
* behavior is in parens:
@@ -303,7 +297,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
303297
return retval;
304298
}
305299

306-
#ifdef DEBUG_MM_RB
300+
#ifdef CONFIG_DEBUG_VM_RB
307301
static int browse_rb(struct rb_root *root)
308302
{
309303
int i = 0, j;
@@ -337,9 +331,12 @@ void validate_mm(struct mm_struct *mm)
337331
{
338332
int bug = 0;
339333
int i = 0;
340-
struct vm_area_struct *tmp = mm->mmap;
341-
while (tmp) {
342-
tmp = tmp->vm_next;
334+
struct vm_area_struct *vma = mm->mmap;
335+
while (vma) {
336+
struct anon_vma_chain *avc;
337+
list_for_each_entry(avc, &vma->anon_vma_chain, same_vma)
338+
anon_vma_interval_tree_verify(avc);
339+
vma = vma->vm_next;
343340
i++;
344341
}
345342
if (i != mm->map_count)
@@ -1790,6 +1787,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
17901787
}
17911788
vma_unlock_anon_vma(vma);
17921789
khugepaged_enter_vma_merge(vma);
1790+
validate_mm(vma->vm_mm);
17931791
return error;
17941792
}
17951793
#endif /* CONFIG_STACK_GROWSUP || CONFIG_IA64 */
@@ -1843,6 +1841,7 @@ int expand_downwards(struct vm_area_struct *vma,
18431841
}
18441842
vma_unlock_anon_vma(vma);
18451843
khugepaged_enter_vma_merge(vma);
1844+
validate_mm(vma->vm_mm);
18461845
return error;
18471846
}
18481847

0 commit comments

Comments
 (0)