167 lines · c
1// SPDX-License-Identifier: GPL-2.02// Copyright (C) 2020 ARM Limited3 4#define _GNU_SOURCE5 6#include <errno.h>7#include <fcntl.h>8#include <signal.h>9#include <stdio.h>10#include <stdlib.h>11#include <string.h>12#include <ucontext.h>13#include <sys/mman.h>14 15#include "kselftest.h"16#include "mte_common_util.h"17#include "mte_def.h"18 19#define TEST_UNIT 1020#define PATH_KSM "/sys/kernel/mm/ksm/"21#define MAX_LOOP 422 23static size_t page_sz;24static unsigned long ksm_sysfs[5];25 26static unsigned long read_sysfs(char *str)27{28 FILE *f;29 unsigned long val = 0;30 31 f = fopen(str, "r");32 if (!f) {33 ksft_print_msg("ERR: missing %s\n", str);34 return 0;35 }36 if (fscanf(f, "%lu", &val) != 1) {37 ksft_print_msg("ERR: parsing %s\n", str);38 val = 0;39 }40 fclose(f);41 return val;42}43 44static void write_sysfs(char *str, unsigned long val)45{46 FILE *f;47 48 f = fopen(str, "w");49 if (!f) {50 ksft_print_msg("ERR: missing %s\n", str);51 return;52 }53 fprintf(f, "%lu", val);54 fclose(f);55}56 57static void mte_ksm_setup(void)58{59 ksm_sysfs[0] = read_sysfs(PATH_KSM "merge_across_nodes");60 write_sysfs(PATH_KSM "merge_across_nodes", 1);61 ksm_sysfs[1] = read_sysfs(PATH_KSM "sleep_millisecs");62 write_sysfs(PATH_KSM "sleep_millisecs", 0);63 ksm_sysfs[2] = read_sysfs(PATH_KSM "run");64 write_sysfs(PATH_KSM "run", 1);65 ksm_sysfs[3] = read_sysfs(PATH_KSM "max_page_sharing");66 write_sysfs(PATH_KSM "max_page_sharing", ksm_sysfs[3] + TEST_UNIT);67 ksm_sysfs[4] = read_sysfs(PATH_KSM "pages_to_scan");68 write_sysfs(PATH_KSM "pages_to_scan", ksm_sysfs[4] + TEST_UNIT);69}70 71static void mte_ksm_restore(void)72{73 write_sysfs(PATH_KSM "merge_across_nodes", ksm_sysfs[0]);74 write_sysfs(PATH_KSM "sleep_millisecs", ksm_sysfs[1]);75 write_sysfs(PATH_KSM "run", ksm_sysfs[2]);76 write_sysfs(PATH_KSM "max_page_sharing", ksm_sysfs[3]);77 write_sysfs(PATH_KSM "pages_to_scan", ksm_sysfs[4]);78}79 80static void mte_ksm_scan(void)81{82 int cur_count = read_sysfs(PATH_KSM "full_scans");83 int scan_count = cur_count + 1;84 int max_loop_count = MAX_LOOP;85 86 while ((cur_count < scan_count) && max_loop_count) {87 sleep(1);88 cur_count = read_sysfs(PATH_KSM "full_scans");89 max_loop_count--;90 }91#ifdef DEBUG92 ksft_print_msg("INFO: pages_shared=%lu pages_sharing=%lu\n",93 read_sysfs(PATH_KSM "pages_shared"),94 read_sysfs(PATH_KSM "pages_sharing"));95#endif96}97 98static int check_madvise_options(int mem_type, int mode, int mapping)99{100 char *ptr;101 int err, ret;102 103 err = KSFT_FAIL;104 if (access(PATH_KSM, F_OK) == -1) {105 ksft_print_msg("ERR: Kernel KSM config not enabled\n");106 return err;107 }108 109 mte_switch_mode(mode, MTE_ALLOW_NON_ZERO_TAG);110 ptr = mte_allocate_memory(TEST_UNIT * page_sz, mem_type, mapping, true);111 if (check_allocated_memory(ptr, TEST_UNIT * page_sz, mem_type, false) != KSFT_PASS)112 return KSFT_FAIL;113 114 /* Insert same data in all the pages */115 memset(ptr, 'A', TEST_UNIT * page_sz);116 ret = madvise(ptr, TEST_UNIT * page_sz, MADV_MERGEABLE);117 if (ret) {118 ksft_print_msg("ERR: madvise failed to set MADV_UNMERGEABLE\n");119 goto madvise_err;120 }121 mte_ksm_scan();122 /* Tagged pages should not merge */123 if ((read_sysfs(PATH_KSM "pages_shared") < 1) ||124 (read_sysfs(PATH_KSM "pages_sharing") < (TEST_UNIT - 1)))125 err = KSFT_PASS;126madvise_err:127 mte_free_memory(ptr, TEST_UNIT * page_sz, mem_type, true);128 return err;129}130 131int main(int argc, char *argv[])132{133 int err;134 135 err = mte_default_setup();136 if (err)137 return err;138 page_sz = getpagesize();139 if (!page_sz) {140 ksft_print_msg("ERR: Unable to get page size\n");141 return KSFT_FAIL;142 }143 /* Register signal handlers */144 mte_register_signal(SIGBUS, mte_default_handler);145 mte_register_signal(SIGSEGV, mte_default_handler);146 147 /* Set test plan */148 ksft_set_plan(4);149 150 /* Enable KSM */151 mte_ksm_setup();152 153 evaluate_test(check_madvise_options(USE_MMAP, MTE_SYNC_ERR, MAP_PRIVATE),154 "Check KSM mte page merge for private mapping, sync mode and mmap memory\n");155 evaluate_test(check_madvise_options(USE_MMAP, MTE_ASYNC_ERR, MAP_PRIVATE),156 "Check KSM mte page merge for private mapping, async mode and mmap memory\n");157 evaluate_test(check_madvise_options(USE_MMAP, MTE_SYNC_ERR, MAP_SHARED),158 "Check KSM mte page merge for shared mapping, sync mode and mmap memory\n");159 evaluate_test(check_madvise_options(USE_MMAP, MTE_ASYNC_ERR, MAP_SHARED),160 "Check KSM mte page merge for shared mapping, async mode and mmap memory\n");161 162 mte_ksm_restore();163 mte_restore_setup();164 ksft_print_cnts();165 return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL;166}167