151 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
| // SPDX-License-Identifier: GPL-2.0-or-later
 | |
| /*
 | |
|  * Copyright (c) 2017 FUJITSU LIMITED. All rights reserved.
 | |
|  * Author(s): Xiao Yang <yangx.jy@cn.fujitsu.com>
 | |
|  *            Jie Fei <feij.fnst@cn.fujitsu.com>
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Description:
 | |
|  * This is a regression test for ksm page migration which is miscalculated.
 | |
|  *
 | |
|  * The kernel bug has been fixed by:
 | |
|  *
 | |
|  * commit 4b0ece6fa0167b22c004ff69e137dc94ee2e469e
 | |
|  * Author: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
 | |
|  * Date:   Fri Mar 31 15:11:44 2017 -0700
 | |
|  *
 | |
|  *     mm: migrate: fix remove_migration_pte() for ksm pages
 | |
|  */
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <unistd.h>
 | |
| #include <stdlib.h>
 | |
| #include <pwd.h>
 | |
| 
 | |
| #include "tst_test.h"
 | |
| #include "lapi/syscalls.h"
 | |
| #include "lapi/mmap.h"
 | |
| #include "ksm_helper.h"
 | |
| #include "numa_helper.h"
 | |
| #include "migrate_pages_common.h"
 | |
| 
 | |
| #ifdef HAVE_NUMA_V2
 | |
| #define N_PAGES 20
 | |
| #define N_LOOPS 600
 | |
| #define TEST_NODES 2
 | |
| 
 | |
| static int orig_ksm_run = -1;
 | |
| static unsigned int page_size;
 | |
| static void *test_pages[N_PAGES];
 | |
| static int num_nodes, max_node;
 | |
| static int *nodes;
 | |
| static unsigned long *new_nodes[2];
 | |
| static const char nobody_uid[] = "nobody";
 | |
| static struct passwd *ltpuser;
 | |
| 
 | |
| static void setup(void)
 | |
| {
 | |
| 	int n;
 | |
| 	unsigned long nodemask_size;
 | |
| 
 | |
| 	if (access(PATH_KSM, F_OK))
 | |
| 		tst_brk(TCONF, "KSM configuration was not enabled");
 | |
| 
 | |
| 	if (get_allowed_nodes_arr(NH_MEMS, &num_nodes, &nodes) < 0)
 | |
| 		tst_brk(TBROK | TERRNO, "get_allowed_nodes() failed");
 | |
| 
 | |
| 	if (num_nodes < TEST_NODES) {
 | |
| 		tst_brk(TCONF, "requires NUMA with at least %d node",
 | |
| 			TEST_NODES);
 | |
| 	}
 | |
| 
 | |
| 	ltpuser = SAFE_GETPWNAM(nobody_uid);
 | |
| 
 | |
| 	max_node = LTP_ALIGN(get_max_node(), sizeof(unsigned long) * 8);
 | |
| 	nodemask_size = max_node / 8;
 | |
| 	new_nodes[0] = SAFE_MALLOC(nodemask_size);
 | |
| 	new_nodes[1] = SAFE_MALLOC(nodemask_size);
 | |
| 	memset(new_nodes[0], 0, nodemask_size);
 | |
| 	memset(new_nodes[1], 0, nodemask_size);
 | |
| 	set_bit(new_nodes[0], nodes[0], 1);
 | |
| 	set_bit(new_nodes[1], nodes[1], 1);
 | |
| 
 | |
| 	page_size = getpagesize();
 | |
| 
 | |
| 	for (n = 0; n < N_PAGES; n++) {
 | |
| 		test_pages[n] = SAFE_MMAP(NULL, page_size, PROT_READ | PROT_WRITE | PROT_EXEC,
 | |
| 					  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 | |
| 		if (madvise(test_pages[n], page_size, MADV_MERGEABLE)) {
 | |
| 			if (errno == EINVAL) {
 | |
| 				tst_brk(TCONF | TERRNO, "madvise() didn't "
 | |
| 					"support MADV_MERGEABLE");
 | |
| 			}
 | |
| 
 | |
| 			tst_brk(TBROK | TERRNO,
 | |
| 				"madvise(MADV_MERGEABLE) failed");
 | |
| 		}
 | |
| 
 | |
| 		if (mbind(test_pages[n], page_size, MPOL_BIND, new_nodes[0],
 | |
| 			  max_node, 0))
 | |
| 			tst_brk(TBROK | TERRNO, "mbind(MPOL_BIND) failed");
 | |
| 
 | |
| 		memset(test_pages[n], 0, page_size);
 | |
| 	}
 | |
| 
 | |
| 	SAFE_FILE_SCANF(PATH_KSM "run", "%d", &orig_ksm_run);
 | |
| 	SAFE_FILE_PRINTF(PATH_KSM "run", "%d", 1);
 | |
| 	wait_ksmd_full_scan();
 | |
| }
 | |
| 
 | |
| static void cleanup(void)
 | |
| {
 | |
| 	int n;
 | |
| 
 | |
| 	for (n = 0; n < N_PAGES; n++) {
 | |
| 		if (test_pages[n])
 | |
| 			SAFE_MUNMAP(test_pages[n], page_size);
 | |
| 	}
 | |
| 
 | |
| 	free(new_nodes[0]);
 | |
| 	free(new_nodes[1]);
 | |
| 
 | |
| 	if (orig_ksm_run != -1)
 | |
| 		SAFE_FILE_PRINTF(PATH_KSM "run", "%d", orig_ksm_run);
 | |
| }
 | |
| 
 | |
| static void migrate_test(void)
 | |
| {
 | |
| 	int loop, i, ret;
 | |
| 
 | |
| 	SAFE_SETEUID(ltpuser->pw_uid);
 | |
| 	for (loop = 0; loop < N_LOOPS; loop++) {
 | |
| 		i = loop % 2;
 | |
| 		ret = tst_syscall(__NR_migrate_pages, 0, max_node,
 | |
| 				   new_nodes[i], new_nodes[i ? 0 : 1]);
 | |
| 		if (ret < 0) {
 | |
| 			tst_res(TFAIL | TERRNO, "migrate_pages() failed");
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| 	SAFE_SETEUID(0);
 | |
| 
 | |
| 	tst_res(TPASS, "migrate_pages() passed");
 | |
| }
 | |
| 
 | |
| static struct tst_test test = {
 | |
| 	.min_kver = "2.6.32",
 | |
| 	.needs_root = 1,
 | |
| 	.setup = setup,
 | |
| 	.cleanup = cleanup,
 | |
| 	.test_all = migrate_test,
 | |
| 	.tags = (const struct tst_tag[]) {
 | |
| 		{"linux-git", "4b0ece6fa016"},
 | |
| 		{}
 | |
| 	}
 | |
| };
 | |
| 
 | |
| #else
 | |
| 	TST_TEST_TCONF("require libnuma >= 2 and it's development packages");
 | |
| #endif
 |