-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
kselftest/arm64: Verify KSM page merge for MTE pages
Add a testcase to check that KSM should not merge pages containing same data with same/different MTE tag values. This testcase has one positive tests and passes if page merging happens according to the above rule. It also saves and restores any modified ksm sysfs entries. Signed-off-by: Amit Daniel Kachhap <amit.kachhap@arm.com> Tested-by: Catalin Marinas <catalin.marinas@arm.com> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Shuah Khan <shuah@kernel.org> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Will Deacon <will@kernel.org> Link: https://lore.kernel.org/r/20201002115630.24683-6-amit.kachhap@arm.com Signed-off-by: Will Deacon <will@kernel.org>
- Loading branch information
Amit Daniel Kachhap
authored and
Will Deacon
committed
Oct 5, 2020
1 parent
53ec81d
commit f981d8f
Showing
2 changed files
with
160 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ check_buffer_fill | |
check_tags_inclusion | ||
check_child_memory | ||
check_mmap_options | ||
check_ksm_options |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
// Copyright (C) 2020 ARM Limited | ||
|
||
#define _GNU_SOURCE | ||
|
||
#include <errno.h> | ||
#include <fcntl.h> | ||
#include <signal.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <ucontext.h> | ||
#include <sys/mman.h> | ||
|
||
#include "kselftest.h" | ||
#include "mte_common_util.h" | ||
#include "mte_def.h" | ||
|
||
#define TEST_UNIT 10 | ||
#define PATH_KSM "/sys/kernel/mm/ksm/" | ||
#define MAX_LOOP 4 | ||
|
||
static size_t page_sz; | ||
static unsigned long ksm_sysfs[5]; | ||
|
||
static unsigned long read_sysfs(char *str) | ||
{ | ||
FILE *f; | ||
unsigned long val = 0; | ||
|
||
f = fopen(str, "r"); | ||
if (!f) { | ||
ksft_print_msg("ERR: missing %s\n", str); | ||
return 0; | ||
} | ||
fscanf(f, "%lu", &val); | ||
fclose(f); | ||
return val; | ||
} | ||
|
||
static void write_sysfs(char *str, unsigned long val) | ||
{ | ||
FILE *f; | ||
|
||
f = fopen(str, "w"); | ||
if (!f) { | ||
ksft_print_msg("ERR: missing %s\n", str); | ||
return; | ||
} | ||
fprintf(f, "%lu", val); | ||
fclose(f); | ||
} | ||
|
||
static void mte_ksm_setup(void) | ||
{ | ||
ksm_sysfs[0] = read_sysfs(PATH_KSM "merge_across_nodes"); | ||
write_sysfs(PATH_KSM "merge_across_nodes", 1); | ||
ksm_sysfs[1] = read_sysfs(PATH_KSM "sleep_millisecs"); | ||
write_sysfs(PATH_KSM "sleep_millisecs", 0); | ||
ksm_sysfs[2] = read_sysfs(PATH_KSM "run"); | ||
write_sysfs(PATH_KSM "run", 1); | ||
ksm_sysfs[3] = read_sysfs(PATH_KSM "max_page_sharing"); | ||
write_sysfs(PATH_KSM "max_page_sharing", ksm_sysfs[3] + TEST_UNIT); | ||
ksm_sysfs[4] = read_sysfs(PATH_KSM "pages_to_scan"); | ||
write_sysfs(PATH_KSM "pages_to_scan", ksm_sysfs[4] + TEST_UNIT); | ||
} | ||
|
||
static void mte_ksm_restore(void) | ||
{ | ||
write_sysfs(PATH_KSM "merge_across_nodes", ksm_sysfs[0]); | ||
write_sysfs(PATH_KSM "sleep_millisecs", ksm_sysfs[1]); | ||
write_sysfs(PATH_KSM "run", ksm_sysfs[2]); | ||
write_sysfs(PATH_KSM "max_page_sharing", ksm_sysfs[3]); | ||
write_sysfs(PATH_KSM "pages_to_scan", ksm_sysfs[4]); | ||
} | ||
|
||
static void mte_ksm_scan(void) | ||
{ | ||
int cur_count = read_sysfs(PATH_KSM "full_scans"); | ||
int scan_count = cur_count + 1; | ||
int max_loop_count = MAX_LOOP; | ||
|
||
while ((cur_count < scan_count) && max_loop_count) { | ||
sleep(1); | ||
cur_count = read_sysfs(PATH_KSM "full_scans"); | ||
max_loop_count--; | ||
} | ||
#ifdef DEBUG | ||
ksft_print_msg("INFO: pages_shared=%lu pages_sharing=%lu\n", | ||
read_sysfs(PATH_KSM "pages_shared"), | ||
read_sysfs(PATH_KSM "pages_sharing")); | ||
#endif | ||
} | ||
|
||
static int check_madvise_options(int mem_type, int mode, int mapping) | ||
{ | ||
char *ptr; | ||
int err, ret; | ||
|
||
err = KSFT_FAIL; | ||
if (access(PATH_KSM, F_OK) == -1) { | ||
ksft_print_msg("ERR: Kernel KSM config not enabled\n"); | ||
return err; | ||
} | ||
|
||
mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG); | ||
ptr = mte_allocate_memory(TEST_UNIT * page_sz, mem_type, mapping, true); | ||
if (check_allocated_memory(ptr, TEST_UNIT * page_sz, mem_type, false) != KSFT_PASS) | ||
return KSFT_FAIL; | ||
|
||
/* Insert same data in all the pages */ | ||
memset(ptr, 'A', TEST_UNIT * page_sz); | ||
ret = madvise(ptr, TEST_UNIT * page_sz, MADV_MERGEABLE); | ||
if (ret) { | ||
ksft_print_msg("ERR: madvise failed to set MADV_UNMERGEABLE\n"); | ||
goto madvise_err; | ||
} | ||
mte_ksm_scan(); | ||
/* Tagged pages should not merge */ | ||
if ((read_sysfs(PATH_KSM "pages_shared") < 1) || | ||
(read_sysfs(PATH_KSM "pages_sharing") < (TEST_UNIT - 1))) | ||
err = KSFT_PASS; | ||
madvise_err: | ||
mte_free_memory(ptr, TEST_UNIT * page_sz, mem_type, true); | ||
return err; | ||
} | ||
|
||
int main(int argc, char *argv[]) | ||
{ | ||
int err; | ||
|
||
err = mte_default_setup(); | ||
if (err) | ||
return err; | ||
page_sz = getpagesize(); | ||
if (!page_sz) { | ||
ksft_print_msg("ERR: Unable to get page size\n"); | ||
return KSFT_FAIL; | ||
} | ||
/* Register signal handlers */ | ||
mte_register_signal(SIGBUS, mte_default_handler); | ||
mte_register_signal(SIGSEGV, mte_default_handler); | ||
/* Enable KSM */ | ||
mte_ksm_setup(); | ||
|
||
evaluate_test(check_madvise_options(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE), | ||
"Check KSM mte page merge for private mapping, sync mode and mmap memory\n"); | ||
evaluate_test(check_madvise_options(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE), | ||
"Check KSM mte page merge for private mapping, async mode and mmap memory\n"); | ||
evaluate_test(check_madvise_options(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED), | ||
"Check KSM mte page merge for shared mapping, sync mode and mmap memory\n"); | ||
evaluate_test(check_madvise_options(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED), | ||
"Check KSM mte page merge for shared mapping, async mode and mmap memory\n"); | ||
|
||
mte_ksm_restore(); | ||
mte_restore_setup(); | ||
ksft_print_cnts(); | ||
return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL; | ||
} |