| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- // 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;
- }
- if (fscanf(f, "%lu", &val) != 1) {
- ksft_print_msg("ERR: parsing %s\n", str);
- val = 0;
- }
- 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);
- /* Set test plan */
- ksft_set_plan(4);
- /* 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;
- }
|