1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2017 FUJITSU LIMITED. All rights reserved. 4 * Author(s): Xiao Yang <yangx.jy@cn.fujitsu.com> 5 * Jie Fei <feij.fnst@cn.fujitsu.com> 6 */ 7 8/* 9 * Description: 10 * This is a regression test for ksm page migration which is miscalculated. 11 * 12 * The kernel bug has been fixed by: 13 * 14 * commit 4b0ece6fa0167b22c004ff69e137dc94ee2e469e 15 * Author: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> 16 * Date: Fri Mar 31 15:11:44 2017 -0700 17 * 18 * mm: migrate: fix remove_migration_pte() for ksm pages 19 */ 20 21#include <errno.h> 22#include <unistd.h> 23#include <stdlib.h> 24#include <pwd.h> 25 26#include "tst_test.h" 27#include "lapi/syscalls.h" 28#include "lapi/mmap.h" 29#include "ksm_helper.h" 30#include "numa_helper.h" 31#include "migrate_pages_common.h" 32 33#ifdef HAVE_NUMA_V2 34#define N_PAGES 20 35#define N_LOOPS 600 36#define TEST_NODES 2 37 38static int orig_ksm_run = -1; 39static unsigned int page_size; 40static void *test_pages[N_PAGES]; 41static int num_nodes, max_node; 42static int *nodes; 43static unsigned long *new_nodes[2]; 44static const char nobody_uid[] = "nobody"; 45static struct passwd *ltpuser; 46 47static void setup(void) 48{ 49 int n; 50 unsigned long nodemask_size; 51 52 if (access(PATH_KSM, F_OK)) 53 tst_brk(TCONF, "KSM configuration was not enabled"); 54 55 if (get_allowed_nodes_arr(NH_MEMS, &num_nodes, &nodes) < 0) 56 tst_brk(TBROK | TERRNO, "get_allowed_nodes() failed"); 57 58 if (num_nodes < TEST_NODES) { 59 tst_brk(TCONF, "requires NUMA with at least %d node", 60 TEST_NODES); 61 } 62 63 ltpuser = SAFE_GETPWNAM(nobody_uid); 64 65 max_node = LTP_ALIGN(get_max_node(), sizeof(unsigned long) * 8); 66 nodemask_size = max_node / 8; 67 new_nodes[0] = SAFE_MALLOC(nodemask_size); 68 new_nodes[1] = SAFE_MALLOC(nodemask_size); 69 memset(new_nodes[0], 0, nodemask_size); 70 memset(new_nodes[1], 0, nodemask_size); 71 set_bit(new_nodes[0], nodes[0], 1); 72 set_bit(new_nodes[1], nodes[1], 1); 73 74 page_size = getpagesize(); 75 76 for (n = 0; n < N_PAGES; n++) { 77 test_pages[n] = SAFE_MMAP(NULL, page_size, PROT_READ | PROT_WRITE | PROT_EXEC, 78 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 79 if (madvise(test_pages[n], page_size, MADV_MERGEABLE)) { 80 if (errno == EINVAL) { 81 tst_brk(TCONF | TERRNO, "madvise() didn't " 82 "support MADV_MERGEABLE"); 83 } 84 85 tst_brk(TBROK | TERRNO, 86 "madvise(MADV_MERGEABLE) failed"); 87 } 88 89 if (mbind(test_pages[n], page_size, MPOL_BIND, new_nodes[0], 90 max_node, 0)) 91 tst_brk(TBROK | TERRNO, "mbind(MPOL_BIND) failed"); 92 93 memset(test_pages[n], 0, page_size); 94 } 95 96 SAFE_FILE_SCANF(PATH_KSM "run", "%d", &orig_ksm_run); 97 SAFE_FILE_PRINTF(PATH_KSM "run", "%d", 1); 98 wait_ksmd_full_scan(); 99} 100 101static void cleanup(void) 102{ 103 int n; 104 105 for (n = 0; n < N_PAGES; n++) { 106 if (test_pages[n]) 107 SAFE_MUNMAP(test_pages[n], page_size); 108 } 109 110 free(new_nodes[0]); 111 free(new_nodes[1]); 112 113 if (orig_ksm_run != -1) 114 SAFE_FILE_PRINTF(PATH_KSM "run", "%d", orig_ksm_run); 115} 116 117static void migrate_test(void) 118{ 119 int loop, i, ret; 120 121 SAFE_SETEUID(ltpuser->pw_uid); 122 for (loop = 0; loop < N_LOOPS; loop++) { 123 i = loop % 2; 124 ret = tst_syscall(__NR_migrate_pages, 0, max_node, 125 new_nodes[i], new_nodes[i ? 0 : 1]); 126 if (ret < 0) { 127 tst_res(TFAIL | TERRNO, "migrate_pages() failed"); 128 return; 129 } 130 131 if (!tst_remaining_runtime()) { 132 tst_res(TINFO, "Out of runtime, exiting..."); 133 break; 134 } 135 } 136 SAFE_SETEUID(0); 137 138 tst_res(TPASS, "migrate_pages() passed"); 139} 140 141static struct tst_test test = { 142 .max_runtime = 300, 143 .needs_root = 1, 144 .setup = setup, 145 .cleanup = cleanup, 146 .test_all = migrate_test, 147 .tags = (const struct tst_tag[]) { 148 {"linux-git", "4b0ece6fa016"}, 149 {} 150 } 151}; 152 153#else 154 TST_TEST_TCONF("require libnuma >= 2 and it's development packages"); 155#endif 156