228 lines
4.7 KiB
C
228 lines
4.7 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (c) Crackerjack Project., 2007-2008, Hitachi, Ltd
|
|
* Copyright (c) 2017 Petr Vorel <pvorel@suse.cz>
|
|
*
|
|
* Authors:
|
|
* Takahiro Yasui <takahiro.yasui.mp@hitachi.com>,
|
|
* Yumiko Sugita <yumiko.sugita.yf@hitachi.com>,
|
|
* Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp>
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#if HAVE_NUMA_H
|
|
#include <numa.h>
|
|
#endif
|
|
|
|
#include "config.h"
|
|
#include "numa_helper.h"
|
|
#include "tst_test.h"
|
|
|
|
#ifdef HAVE_NUMA_V2
|
|
|
|
#define MEM_LENGTH (4 * 1024 * 1024)
|
|
|
|
#define UNKNOWN_POLICY -1
|
|
|
|
#define POLICY_DESC(x) .policy = x, .desc = #x
|
|
#define POLICY_DESC_TEXT(x, y) .policy = x, .desc = #x" ("y")"
|
|
|
|
static struct bitmask *nodemask, *getnodemask, *empty_nodemask;
|
|
|
|
static void test_default(unsigned int i, char *p);
|
|
static void test_none(unsigned int i, char *p);
|
|
static void test_invalid_nodemask(unsigned int i, char *p);
|
|
|
|
struct test_case {
|
|
int policy;
|
|
const char *desc;
|
|
unsigned flags;
|
|
int ret;
|
|
int err;
|
|
void (*test)(unsigned int, char *);
|
|
struct bitmask **exp_nodemask;
|
|
};
|
|
|
|
static struct test_case tcase[] = {
|
|
{
|
|
POLICY_DESC(MPOL_DEFAULT),
|
|
.ret = 0,
|
|
.err = 0,
|
|
.test = test_none,
|
|
.exp_nodemask = &empty_nodemask,
|
|
},
|
|
{
|
|
POLICY_DESC_TEXT(MPOL_DEFAULT, "target exists"),
|
|
.ret = -1,
|
|
.err = EINVAL,
|
|
.test = test_default,
|
|
},
|
|
{
|
|
POLICY_DESC_TEXT(MPOL_BIND, "no target"),
|
|
.ret = -1,
|
|
.err = EINVAL,
|
|
.test = test_none,
|
|
},
|
|
{
|
|
POLICY_DESC(MPOL_BIND),
|
|
.ret = 0,
|
|
.err = 0,
|
|
.test = test_default,
|
|
.exp_nodemask = &nodemask,
|
|
},
|
|
{
|
|
POLICY_DESC_TEXT(MPOL_INTERLEAVE, "no target"),
|
|
.ret = -1,
|
|
.err = EINVAL,
|
|
.test = test_none,
|
|
},
|
|
{
|
|
POLICY_DESC(MPOL_INTERLEAVE),
|
|
.ret = 0,
|
|
.err = 0,
|
|
.test = test_default,
|
|
.exp_nodemask = &nodemask,
|
|
},
|
|
{
|
|
POLICY_DESC_TEXT(MPOL_PREFERRED, "no target"),
|
|
.ret = 0,
|
|
.err = 0,
|
|
.test = test_none,
|
|
},
|
|
{
|
|
POLICY_DESC(MPOL_PREFERRED),
|
|
.ret = 0,
|
|
.err = 0,
|
|
.test = test_default,
|
|
.exp_nodemask = &nodemask,
|
|
},
|
|
{
|
|
POLICY_DESC(UNKNOWN_POLICY),
|
|
.ret = -1,
|
|
.err = EINVAL,
|
|
.test = test_none,
|
|
},
|
|
{
|
|
POLICY_DESC_TEXT(MPOL_DEFAULT, "invalid flags"),
|
|
.flags = -1,
|
|
.ret = -1,
|
|
.err = EINVAL,
|
|
.test = test_none,
|
|
},
|
|
{
|
|
POLICY_DESC_TEXT(MPOL_PREFERRED, "invalid nodemask"),
|
|
.ret = -1,
|
|
.err = EFAULT,
|
|
.test = test_invalid_nodemask,
|
|
},
|
|
};
|
|
|
|
static void test_default(unsigned int i, char *p)
|
|
{
|
|
struct test_case *tc = &tcase[i];
|
|
|
|
TEST(mbind(p, MEM_LENGTH, tc->policy, nodemask->maskp,
|
|
nodemask->size, tc->flags));
|
|
}
|
|
|
|
static void test_none(unsigned int i, char *p)
|
|
{
|
|
struct test_case *tc = &tcase[i];
|
|
|
|
TEST(mbind(p, MEM_LENGTH, tc->policy, NULL, 0, tc->flags));
|
|
}
|
|
|
|
static void test_invalid_nodemask(unsigned int i, char *p)
|
|
{
|
|
struct test_case *tc = &tcase[i];
|
|
|
|
/* use invalid nodemask (64 MiB after heap) */
|
|
TEST(mbind(p, MEM_LENGTH, tc->policy, sbrk(0) + 64*1024*1024,
|
|
NUMA_NUM_NODES, tc->flags));
|
|
}
|
|
|
|
static void setup(void)
|
|
{
|
|
if (!is_numa(NULL, NH_MEMS, 1))
|
|
tst_brk(TCONF, "requires NUMA with at least 1 node");
|
|
empty_nodemask = numa_allocate_nodemask();
|
|
}
|
|
|
|
static void setup_node(void)
|
|
{
|
|
int test_node = -1;
|
|
|
|
if (get_allowed_nodes(NH_MEMS, 1, &test_node) < 0)
|
|
tst_brk(TBROK | TERRNO, "get_allowed_nodes failed");
|
|
|
|
nodemask = numa_allocate_nodemask();
|
|
getnodemask = numa_allocate_nodemask();
|
|
numa_bitmask_setbit(nodemask, test_node);
|
|
}
|
|
|
|
static void do_test(unsigned int i)
|
|
{
|
|
struct test_case *tc = &tcase[i];
|
|
int policy, fail = 0;
|
|
char *p = NULL;
|
|
|
|
tst_res(TINFO, "case %s", tc->desc);
|
|
|
|
setup_node();
|
|
|
|
p = SAFE_MMAP(NULL, MEM_LENGTH, PROT_READ | PROT_WRITE, MAP_PRIVATE |
|
|
MAP_ANONYMOUS, 0, 0);
|
|
|
|
tc->test(i, p);
|
|
|
|
if (TST_RET >= 0) {
|
|
/* Check policy of the allocated memory */
|
|
TEST(get_mempolicy(&policy, getnodemask->maskp,
|
|
getnodemask->size, p, MPOL_F_ADDR));
|
|
if (TST_RET < 0) {
|
|
tst_res(TFAIL | TTERRNO, "get_mempolicy failed");
|
|
return;
|
|
}
|
|
if (tc->policy != policy) {
|
|
tst_res(TFAIL, "Wrong policy: %d, expected: %d",
|
|
tc->policy, policy);
|
|
fail = 1;
|
|
}
|
|
if (tc->exp_nodemask) {
|
|
struct bitmask *exp_mask = *(tc->exp_nodemask);
|
|
|
|
if (!numa_bitmask_equal(exp_mask, getnodemask)) {
|
|
tst_res(TFAIL, "masks are not equal");
|
|
tst_res_hexd(TINFO, exp_mask->maskp,
|
|
exp_mask->size / 8, "exp_mask: ");
|
|
tst_res_hexd(TINFO, getnodemask->maskp,
|
|
getnodemask->size / 8, "returned: ");
|
|
fail = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (TST_RET != tc->ret) {
|
|
tst_res(TFAIL, "wrong return code: %ld, expected: %d",
|
|
TST_RET, tc->ret);
|
|
fail = 1;
|
|
}
|
|
if (TST_RET == -1 && TST_ERR != tc->err) {
|
|
tst_res(TFAIL | TTERRNO, "expected errno: %s, got",
|
|
tst_strerrno(tc->err));
|
|
fail = 1;
|
|
}
|
|
if (!fail)
|
|
tst_res(TPASS, "Test passed");
|
|
}
|
|
|
|
static struct tst_test test = {
|
|
.tcnt = ARRAY_SIZE(tcase),
|
|
.test = do_test,
|
|
.setup = setup,
|
|
};
|
|
|
|
#else
|
|
TST_TEST_TCONF(NUMA_ERROR_MSG);
|
|
#endif
|