Skip to content

Commit d23af27

Browse files
jakub50akpm00
authored andcommitted
mm: add merging after mremap resize
When mremap call results in expansion, it might be possible to merge the VMA with the next VMA which might become adjacent. This patch adds vma_merge call after the expansion is done to try and merge. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Jakub Matěna <[email protected]> Reviewed-by: Vlastimil Babka <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: "Kirill A . Shutemov" <[email protected]> Cc: Liam Howlett <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Mel Gorman <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Peter Zijlstra (Intel) <[email protected]> Cc: Rik van Riel <[email protected]> Cc: Steven Rostedt <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 04ab0bb commit d23af27

File tree

2 files changed

+63
-3
lines changed

2 files changed

+63
-3
lines changed

mm/mremap.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010

1111
#include <linux/mm.h>
12+
#include <linux/mm_inline.h>
1213
#include <linux/hugetlb.h>
1314
#include <linux/shm.h>
1415
#include <linux/ksm.h>
@@ -23,6 +24,7 @@
2324
#include <linux/mmu_notifier.h>
2425
#include <linux/uaccess.h>
2526
#include <linux/userfaultfd_k.h>
27+
#include <linux/mempolicy.h>
2628

2729
#include <asm/cacheflush.h>
2830
#include <asm/tlb.h>
@@ -1012,6 +1014,9 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
10121014
/* can we just expand the current mapping? */
10131015
if (vma_expandable(vma, new_len - old_len)) {
10141016
long pages = (new_len - old_len) >> PAGE_SHIFT;
1017+
unsigned long extension_start = addr + old_len;
1018+
unsigned long extension_end = addr + new_len;
1019+
pgoff_t extension_pgoff = vma->vm_pgoff + (old_len >> PAGE_SHIFT);
10151020

10161021
if (vma->vm_flags & VM_ACCOUNT) {
10171022
if (security_vm_enough_memory_mm(mm, pages)) {
@@ -1020,8 +1025,18 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
10201025
}
10211026
}
10221027

1023-
if (vma_adjust(vma, vma->vm_start, addr + new_len,
1024-
vma->vm_pgoff, NULL)) {
1028+
/*
1029+
* Function vma_merge() is called on the extension we are adding to
1030+
* the already existing vma, vma_merge() will merge this extension with
1031+
* the already existing vma (expand operation itself) and possibly also
1032+
* with the next vma if it becomes adjacent to the expanded vma and
1033+
* otherwise compatible.
1034+
*/
1035+
vma = vma_merge(mm, vma, extension_start, extension_end,
1036+
vma->vm_flags, vma->anon_vma, vma->vm_file,
1037+
extension_pgoff, vma_policy(vma),
1038+
vma->vm_userfaultfd_ctx, anon_vma_name(vma));
1039+
if (!vma) {
10251040
vm_unacct_memory(pages);
10261041
ret = -ENOMEM;
10271042
goto out;

tools/testing/selftests/vm/mremap_test.c

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,48 @@ static unsigned long long get_mmap_min_addr(void)
118118
return addr;
119119
}
120120

121+
/*
122+
* This test validates that merge is called when expanding a mapping.
123+
* Mapping containing three pages is created, middle page is unmapped
124+
* and then the mapping containing the first page is expanded so that
125+
* it fills the created hole. The two parts should merge creating
126+
* single mapping with three pages.
127+
*/
128+
static void mremap_expand_merge(unsigned long page_size)
129+
{
130+
char *test_name = "mremap expand merge";
131+
FILE *fp;
132+
char *line = NULL;
133+
size_t len = 0;
134+
bool success = false;
135+
136+
char *start = mmap(NULL, 3 * page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
137+
munmap(start + page_size, page_size);
138+
mremap(start, page_size, 2 * page_size, 0);
139+
140+
fp = fopen("/proc/self/maps", "r");
141+
if (fp == NULL) {
142+
ksft_test_result_fail("%s\n", test_name);
143+
return;
144+
}
145+
146+
while(getline(&line, &len, fp) != -1) {
147+
char *first = strtok(line,"- ");
148+
void *first_val = (void *) strtol(first, NULL, 16);
149+
char *second = strtok(NULL,"- ");
150+
void *second_val = (void *) strtol(second, NULL, 16);
151+
if (first_val == start && second_val == start + 3 * page_size) {
152+
success = true;
153+
break;
154+
}
155+
}
156+
if (success)
157+
ksft_test_result_pass("%s\n", test_name);
158+
else
159+
ksft_test_result_fail("%s\n", test_name);
160+
fclose(fp);
161+
}
162+
121163
/*
122164
* Returns the start address of the mapping on success, else returns
123165
* NULL on failure.
@@ -336,6 +378,7 @@ int main(int argc, char **argv)
336378
int i, run_perf_tests;
337379
unsigned int threshold_mb = VALIDATION_DEFAULT_THRESHOLD;
338380
unsigned int pattern_seed;
381+
int num_expand_tests = 1;
339382
struct test test_cases[MAX_TEST];
340383
struct test perf_test_cases[MAX_PERF_TEST];
341384
int page_size;
@@ -407,12 +450,14 @@ int main(int argc, char **argv)
407450
(threshold_mb * _1MB >= _1GB);
408451

409452
ksft_set_plan(ARRAY_SIZE(test_cases) + (run_perf_tests ?
410-
ARRAY_SIZE(perf_test_cases) : 0));
453+
ARRAY_SIZE(perf_test_cases) : 0) + num_expand_tests);
411454

412455
for (i = 0; i < ARRAY_SIZE(test_cases); i++)
413456
run_mremap_test_case(test_cases[i], &failures, threshold_mb,
414457
pattern_seed);
415458

459+
mremap_expand_merge(page_size);
460+
416461
if (run_perf_tests) {
417462
ksft_print_msg("\n%s\n",
418463
"mremap HAVE_MOVE_PMD/PUD optimization time comparison for 1GB region:");

0 commit comments

Comments
 (0)