Home | History | Annotate | Download | only in mbind
      1 /*
      2  * Copyright (c) Crackerjack Project., 2007-2008, Hitachi, Ltd
      3  * Copyright (c) 2017 Petr Vorel <pvorel (at) suse.cz>
      4  *
      5  * Authors:
      6  * Takahiro Yasui <takahiro.yasui.mp (at) hitachi.com>,
      7  * Yumiko Sugita <yumiko.sugita.yf (at) hitachi.com>,
      8  * Satoshi Fujiwara <sa-fuji (at) sdl.hitachi.co.jp>
      9  *
     10  * This program is free software; you can redistribute it and/or
     11  * modify it under the terms of the GNU General Public License as
     12  * published by the Free Software Foundation; either version 2 of
     13  * the License, or (at your option) any later version.
     14  *
     15  * This program is distributed in the hope that it would be useful,
     16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18  * GNU General Public License for more details.
     19  *
     20  * You should have received a copy of the GNU General Public License
     21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
     22  */
     23 
     24 #include <errno.h>
     25 #if HAVE_NUMA_H
     26 #include <numa.h>
     27 #endif
     28 
     29 #include "config.h"
     30 #include "numa_helper.h"
     31 #include "tst_test.h"
     32 
     33 #ifdef HAVE_NUMA_V2
     34 
     35 #define MEM_LENGTH (4 * 1024 * 1024)
     36 
     37 #define UNKNOWN_POLICY -1
     38 
     39 #define POLICY_DESC(x) .policy = x, .desc = #x
     40 #define POLICY_DESC_TEXT(x, y) .policy = x, .desc = #x" ("y")"
     41 
     42 static struct bitmask *nodemask, *getnodemask, *empty_nodemask;
     43 
     44 static void test_default(unsigned int i, char *p);
     45 static void test_none(unsigned int i, char *p);
     46 static void test_invalid_nodemask(unsigned int i, char *p);
     47 
     48 struct test_case {
     49 	int policy;
     50 	const char *desc;
     51 	unsigned flags;
     52 	int ret;
     53 	int err;
     54 	void (*test)(unsigned int, char *);
     55 	struct bitmask **exp_nodemask;
     56 };
     57 
     58 static struct test_case tcase[] = {
     59 	{
     60 		POLICY_DESC(MPOL_DEFAULT),
     61 		.ret = 0,
     62 		.err = 0,
     63 		.test = test_none,
     64 		.exp_nodemask = &empty_nodemask,
     65 	},
     66 	{
     67 		POLICY_DESC_TEXT(MPOL_DEFAULT, "target exists"),
     68 		.ret = -1,
     69 		.err = EINVAL,
     70 		.test = test_default,
     71 	},
     72 	{
     73 		POLICY_DESC_TEXT(MPOL_BIND, "no target"),
     74 		.ret = -1,
     75 		.err = EINVAL,
     76 		.test = test_none,
     77 	},
     78 	{
     79 		POLICY_DESC(MPOL_BIND),
     80 		.ret = 0,
     81 		.err = 0,
     82 		.test = test_default,
     83 		.exp_nodemask = &nodemask,
     84 	},
     85 	{
     86 		POLICY_DESC_TEXT(MPOL_INTERLEAVE, "no target"),
     87 		.ret = -1,
     88 		.err = EINVAL,
     89 		.test = test_none,
     90 	},
     91 	{
     92 		POLICY_DESC(MPOL_INTERLEAVE),
     93 		.ret = 0,
     94 		.err = 0,
     95 		.test = test_default,
     96 		.exp_nodemask = &nodemask,
     97 	},
     98 	{
     99 		POLICY_DESC_TEXT(MPOL_PREFERRED, "no target"),
    100 		.ret = 0,
    101 		.err = 0,
    102 		.test = test_none,
    103 	},
    104 	{
    105 		POLICY_DESC(MPOL_PREFERRED),
    106 		.ret = 0,
    107 		.err = 0,
    108 		.test = test_default,
    109 		.exp_nodemask = &nodemask,
    110 	},
    111 	{
    112 		POLICY_DESC(UNKNOWN_POLICY),
    113 		.ret = -1,
    114 		.err = EINVAL,
    115 		.test = test_none,
    116 	},
    117 	{
    118 		POLICY_DESC_TEXT(MPOL_DEFAULT, "invalid flags"),
    119 		.flags = -1,
    120 		.ret = -1,
    121 		.err = EINVAL,
    122 		.test = test_none,
    123 	},
    124 	{
    125 		POLICY_DESC_TEXT(MPOL_PREFERRED, "invalid nodemask"),
    126 		.ret = -1,
    127 		.err = EFAULT,
    128 		.test = test_invalid_nodemask,
    129 	},
    130 };
    131 
    132 static void test_default(unsigned int i, char *p)
    133 {
    134 	struct test_case *tc = &tcase[i];
    135 
    136 	TEST(mbind(p, MEM_LENGTH, tc->policy, nodemask->maskp,
    137 		   nodemask->size, tc->flags));
    138 }
    139 
    140 static void test_none(unsigned int i, char *p)
    141 {
    142 	struct test_case *tc = &tcase[i];
    143 
    144 	TEST(mbind(p, MEM_LENGTH, tc->policy, NULL, 0, tc->flags));
    145 }
    146 
    147 static void test_invalid_nodemask(unsigned int i, char *p)
    148 {
    149 	struct test_case *tc = &tcase[i];
    150 
    151 	/* use invalid nodemask (64 MiB after heap) */
    152 	TEST(mbind(p, MEM_LENGTH, tc->policy, sbrk(0) + 64*1024*1024,
    153 		   NUMA_NUM_NODES, tc->flags));
    154 }
    155 
    156 static void setup(void)
    157 {
    158 	if (!is_numa(NULL, NH_MEMS, 1))
    159 		tst_brk(TCONF, "requires NUMA with at least 1 node");
    160 	empty_nodemask = numa_allocate_nodemask();
    161 }
    162 
    163 static void setup_node(void)
    164 {
    165 	int test_node = -1;
    166 
    167 	if (get_allowed_nodes(NH_MEMS, 1, &test_node) < 0)
    168 		tst_brk(TBROK | TERRNO, "get_allowed_nodes failed");
    169 
    170 	nodemask = numa_allocate_nodemask();
    171 	getnodemask = numa_allocate_nodemask();
    172 	numa_bitmask_setbit(nodemask, test_node);
    173 }
    174 
    175 static void do_test(unsigned int i)
    176 {
    177 	struct test_case *tc = &tcase[i];
    178 	int policy, fail = 0;
    179 	char *p = NULL;
    180 
    181 	tst_res(TINFO, "case %s", tc->desc);
    182 
    183 	setup_node();
    184 
    185 	p = mmap(NULL, MEM_LENGTH, PROT_READ | PROT_WRITE, MAP_PRIVATE |
    186 			 MAP_ANONYMOUS, 0, 0);
    187 	if (p == MAP_FAILED)
    188 		tst_brk(TBROK | TERRNO, "mmap");
    189 
    190 	tc->test(i, p);
    191 
    192 	if (TEST_RETURN >= 0) {
    193 		/* Check policy of the allocated memory */
    194 		TEST(get_mempolicy(&policy, getnodemask->maskp,
    195 				   getnodemask->size, p, MPOL_F_ADDR));
    196 		if (TEST_RETURN < 0) {
    197 			tst_res(TFAIL | TTERRNO, "get_mempolicy failed");
    198 			return;
    199 		}
    200 		if (tc->policy != policy) {
    201 			tst_res(TFAIL, "Wrong policy: %d, expected: %d",
    202 				tc->policy, policy);
    203 			fail = 1;
    204 		}
    205 		if (tc->exp_nodemask) {
    206 			struct bitmask *exp_mask = *(tc->exp_nodemask);
    207 
    208 			if (!numa_bitmask_equal(exp_mask, getnodemask)) {
    209 				tst_res(TFAIL, "masks are not equal");
    210 				tst_res_hexd(TINFO, exp_mask->maskp,
    211 					exp_mask->size / 8, "exp_mask: ");
    212 				tst_res_hexd(TINFO, getnodemask->maskp,
    213 					getnodemask->size / 8, "returned: ");
    214 				fail = 1;
    215 			}
    216 		}
    217 	}
    218 
    219 	if (TEST_RETURN != tc->ret) {
    220 		tst_res(TFAIL, "wrong return code: %ld, expected: %d",
    221 			TEST_RETURN, tc->ret);
    222 		fail = 1;
    223 	}
    224 	if (TEST_RETURN == -1 && TEST_ERRNO != tc->err) {
    225 		tst_res(TFAIL | TTERRNO, "expected errno: %s, got",
    226 			tst_strerrno(tc->err));
    227 		fail = 1;
    228 	}
    229 	if (!fail)
    230 		tst_res(TPASS, "Test passed");
    231 }
    232 
    233 static struct tst_test test = {
    234 	.tcnt = ARRAY_SIZE(tcase),
    235 	.test = do_test,
    236 	.setup = setup,
    237 };
    238 
    239 #else
    240 TST_TEST_TCONF("test requires libnuma >= 2 and it's development packages");
    241 #endif
    242