Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Apr 14-17, 2025
Register
Loading...
  1// SPDX-License-Identifier: GPL-2.0
  2// Copyright (C) 2020 ARM Limited
  3
  4#define _GNU_SOURCE
  5
  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	10
 20#define PATH_KSM	"/sys/kernel/mm/ksm/"
 21#define MAX_LOOP	4
 22
 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 DEBUG
 92	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#endif
 96}
 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}
1