blob: 72345d07bc589cc16de51d98b38111b4f292b036 [file] [log] [blame]
/*
* 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>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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 = mmap(NULL, MEM_LENGTH, PROT_READ | PROT_WRITE, MAP_PRIVATE |
MAP_ANONYMOUS, 0, 0);
if (p == MAP_FAILED)
tst_brk(TBROK | TERRNO, "mmap");
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