1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz> 4 */ 5 6/* 7 * We are testing mbind() MPOL_MF_MOVE and MPOL_MF_MOVE_ALL. 8 * 9 * If one of these flags is passed along with the policy kernel attempts to 10 * move already faulted pages to match the requested policy. 11 */ 12 13#include <errno.h> 14#include "config.h" 15#ifdef HAVE_NUMA_H 16# include <numa.h> 17# include <numaif.h> 18# include "mbind.h" 19#endif 20#include "tst_test.h" 21#include "tst_numa.h" 22 23#ifdef HAVE_NUMA_V2 24 25static size_t page_size; 26static struct tst_nodemap *nodes; 27 28static void setup(void) 29{ 30 page_size = getpagesize(); 31 32 nodes = tst_get_nodemap(TST_NUMA_MEM, 2 * page_size / 1024); 33 if (nodes->cnt <= 1) 34 tst_brk(TCONF, "Test requires at least two NUMA memory nodes"); 35} 36 37static void cleanup(void) 38{ 39 tst_nodemap_free(nodes); 40} 41 42static void verify_policy(int mode, unsigned flag) 43{ 44 struct bitmask *bm = numa_allocate_nodemask(); 45 unsigned int i; 46 void *ptr; 47 unsigned long size = page_size; 48 unsigned int node = 0; 49 50 ptr = tst_numa_map(NULL, size); 51 tst_nodemap_reset_counters(nodes); 52 tst_numa_fault(ptr, size); 53 tst_nodemap_count_pages(nodes, ptr, size); 54 tst_nodemap_print_counters(nodes); 55 56 for (i = 0; i < nodes->cnt; i++) { 57 if (!nodes->counters[i]) { 58 node = nodes->map[i]; 59 tst_res(TINFO, "Attempting to move to node %i", node); 60 numa_bitmask_setbit(bm, node); 61 break; 62 } 63 } 64 65 TEST(mbind(ptr, size, mode, bm->maskp, bm->size + 1, flag)); 66 67 if (TST_RET) { 68 tst_res(TFAIL | TTERRNO, 69 "mbind(%s, %s) node %u", 70 tst_mempolicy_mode_name(mode), mbind_flag_name(flag), node); 71 goto exit; 72 } else { 73 tst_res(TPASS, "mbind(%s, %s) node %u succeded", 74 tst_mempolicy_mode_name(mode), mbind_flag_name(flag), node); 75 } 76 77 tst_nodemap_reset_counters(nodes); 78 tst_nodemap_count_pages(nodes, ptr, size); 79 80 for (i = 0; i < nodes->cnt; i++) { 81 if (nodes->map[i] == node) { 82 if (nodes->counters[i] == 1) { 83 tst_res(TPASS, "Node %u allocated %u", node, 1); 84 } else { 85 tst_res(TFAIL, "Node %u allocated %u, expected %u", 86 node, nodes->counters[i], 0); 87 } 88 continue; 89 } 90 91 if (nodes->counters[i]) { 92 tst_res(TFAIL, "Node %u allocated %u, expected 0", 93 i, nodes->counters[i]); 94 } 95 } 96 97exit: 98 tst_numa_unmap(ptr, size); 99 numa_free_nodemask(bm); 100} 101 102static const int modes[] = { 103 MPOL_PREFERRED, 104 MPOL_BIND, 105 MPOL_INTERLEAVE, 106}; 107 108static void verify_mbind(unsigned int n) 109{ 110 verify_policy(modes[n], MPOL_MF_MOVE); 111 verify_policy(modes[n], MPOL_MF_MOVE_ALL); 112} 113 114static struct tst_test test = { 115 .setup = setup, 116 .cleanup = cleanup, 117 .test = verify_mbind, 118 .tcnt = ARRAY_SIZE(modes), 119 .needs_root = 1, 120}; 121 122#else 123 124TST_TEST_TCONF(NUMA_ERROR_MSG); 125 126#endif /* HAVE_NUMA_H */ 127