Skip to content

Commit d0cf3dd

Browse files
howlettakpm00
authored andcommitted
damon: convert __damon_va_three_regions to use the VMA iterator
This rather specialised walk can use the VMA iterator. If this proves to be too slow, we can write a custom routine to find the two largest gaps, but it will be somewhat complicated, so let's see if we need it first. Update the kunit test case to use the maple tree. This also fixes an issue with the kunit testcase not adding the last VMA to the list. Link: https://lkml.kernel.org/r/[email protected] Fixes: 17ccae8 (mm/damon: add kunit tests) Signed-off-by: Liam R. Howlett <[email protected]> Signed-off-by: Matthew Wilcox (Oracle) <[email protected]> Reviewed-by: SeongJae Park <[email protected]> Reviewed-by: David Hildenbrand <[email protected]> Tested-by: Yu Zhao <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: David Howells <[email protected]> Cc: Davidlohr Bueso <[email protected]> Cc: Sven Schnelle <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: Will Deacon <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent c9dbe82 commit d0cf3dd

File tree

2 files changed

+39
-50
lines changed

2 files changed

+39
-50
lines changed

mm/damon/vaddr-test.h

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,19 @@
1414

1515
#include <kunit/test.h>
1616

17-
static void __link_vmas(struct vm_area_struct *vmas, ssize_t nr_vmas)
17+
static void __link_vmas(struct maple_tree *mt, struct vm_area_struct *vmas,
18+
ssize_t nr_vmas)
1819
{
19-
int i, j;
20-
unsigned long largest_gap, gap;
20+
int i;
21+
MA_STATE(mas, mt, 0, 0);
2122

2223
if (!nr_vmas)
2324
return;
2425

25-
for (i = 0; i < nr_vmas - 1; i++) {
26-
vmas[i].vm_next = &vmas[i + 1];
27-
28-
vmas[i].vm_rb.rb_left = NULL;
29-
vmas[i].vm_rb.rb_right = &vmas[i + 1].vm_rb;
30-
31-
largest_gap = 0;
32-
for (j = i; j < nr_vmas; j++) {
33-
if (j == 0)
34-
continue;
35-
gap = vmas[j].vm_start - vmas[j - 1].vm_end;
36-
if (gap > largest_gap)
37-
largest_gap = gap;
38-
}
39-
vmas[i].rb_subtree_gap = largest_gap;
40-
}
41-
vmas[i].vm_next = NULL;
42-
vmas[i].vm_rb.rb_right = NULL;
43-
vmas[i].rb_subtree_gap = 0;
26+
mas_lock(&mas);
27+
for (i = 0; i < nr_vmas; i++)
28+
vma_mas_store(&vmas[i], &mas);
29+
mas_unlock(&mas);
4430
}
4531

4632
/*
@@ -72,6 +58,7 @@ static void __link_vmas(struct vm_area_struct *vmas, ssize_t nr_vmas)
7258
*/
7359
static void damon_test_three_regions_in_vmas(struct kunit *test)
7460
{
61+
static struct mm_struct mm;
7562
struct damon_addr_range regions[3] = {0,};
7663
/* 10-20-25, 200-210-220, 300-305, 307-330 */
7764
struct vm_area_struct vmas[] = {
@@ -83,9 +70,10 @@ static void damon_test_three_regions_in_vmas(struct kunit *test)
8370
(struct vm_area_struct) {.vm_start = 307, .vm_end = 330},
8471
};
8572

86-
__link_vmas(vmas, 6);
73+
mt_init_flags(&mm.mm_mt, MM_MT_FLAGS);
74+
__link_vmas(&mm.mm_mt, vmas, ARRAY_SIZE(vmas));
8775

88-
__damon_va_three_regions(&vmas[0], regions);
76+
__damon_va_three_regions(&mm, regions);
8977

9078
KUNIT_EXPECT_EQ(test, 10ul, regions[0].start);
9179
KUNIT_EXPECT_EQ(test, 25ul, regions[0].end);

mm/damon/vaddr.c

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -113,37 +113,38 @@ static unsigned long sz_range(struct damon_addr_range *r)
113113
*
114114
* Returns 0 if success, or negative error code otherwise.
115115
*/
116-
static int __damon_va_three_regions(struct vm_area_struct *vma,
116+
static int __damon_va_three_regions(struct mm_struct *mm,
117117
struct damon_addr_range regions[3])
118118
{
119-
struct damon_addr_range gap = {0}, first_gap = {0}, second_gap = {0};
120-
struct vm_area_struct *last_vma = NULL;
121-
unsigned long start = 0;
122-
struct rb_root rbroot;
123-
124-
/* Find two biggest gaps so that first_gap > second_gap > others */
125-
for (; vma; vma = vma->vm_next) {
126-
if (!last_vma) {
127-
start = vma->vm_start;
128-
goto next;
129-
}
119+
struct damon_addr_range first_gap = {0}, second_gap = {0};
120+
VMA_ITERATOR(vmi, mm, 0);
121+
struct vm_area_struct *vma, *prev = NULL;
122+
unsigned long start;
130123

131-
if (vma->rb_subtree_gap <= sz_range(&second_gap)) {
132-
rbroot.rb_node = &vma->vm_rb;
133-
vma = rb_entry(rb_last(&rbroot),
134-
struct vm_area_struct, vm_rb);
124+
/*
125+
* Find the two biggest gaps so that first_gap > second_gap > others.
126+
* If this is too slow, it can be optimised to examine the maple
127+
* tree gaps.
128+
*/
129+
for_each_vma(vmi, vma) {
130+
unsigned long gap;
131+
132+
if (!prev) {
133+
start = vma->vm_start;
135134
goto next;
136135
}
137-
138-
gap.start = last_vma->vm_end;
139-
gap.end = vma->vm_start;
140-
if (sz_range(&gap) > sz_range(&second_gap)) {
141-
swap(gap, second_gap);
142-
if (sz_range(&second_gap) > sz_range(&first_gap))
143-
swap(second_gap, first_gap);
136+
gap = vma->vm_start - prev->vm_end;
137+
138+
if (gap > sz_range(&first_gap)) {
139+
second_gap = first_gap;
140+
first_gap.start = prev->vm_end;
141+
first_gap.end = vma->vm_start;
142+
} else if (gap > sz_range(&second_gap)) {
143+
second_gap.start = prev->vm_end;
144+
second_gap.end = vma->vm_start;
144145
}
145146
next:
146-
last_vma = vma;
147+
prev = vma;
147148
}
148149

149150
if (!sz_range(&second_gap) || !sz_range(&first_gap))
@@ -159,7 +160,7 @@ static int __damon_va_three_regions(struct vm_area_struct *vma,
159160
regions[1].start = ALIGN(first_gap.end, DAMON_MIN_REGION);
160161
regions[1].end = ALIGN(second_gap.start, DAMON_MIN_REGION);
161162
regions[2].start = ALIGN(second_gap.end, DAMON_MIN_REGION);
162-
regions[2].end = ALIGN(last_vma->vm_end, DAMON_MIN_REGION);
163+
regions[2].end = ALIGN(prev->vm_end, DAMON_MIN_REGION);
163164

164165
return 0;
165166
}
@@ -180,7 +181,7 @@ static int damon_va_three_regions(struct damon_target *t,
180181
return -EINVAL;
181182

182183
mmap_read_lock(mm);
183-
rc = __damon_va_three_regions(mm->mmap, regions);
184+
rc = __damon_va_three_regions(mm, regions);
184185
mmap_read_unlock(mm);
185186

186187
mmput(mm);

0 commit comments

Comments
 (0)