From: Jan S. <jst...@re...> - 2012-10-18 12:56:41
|
errno tests for migrate_pages(2). Note, that older kernels (~2.6.18) are likely to panic during this test. Signed-off-by: Jan Stancek <jst...@re...> --- runtest/syscalls | 2 + testcases/kernel/syscalls/migrate_pages/Makefile | 32 +++ .../syscalls/migrate_pages/migrate_pages01.c | 280 ++++++++++++++++++++ .../syscalls/migrate_pages/migrate_pages_common.c | 62 +++++ .../syscalls/migrate_pages/migrate_pages_common.h | 33 +++ 5 files changed, 409 insertions(+), 0 deletions(-) create mode 100644 testcases/kernel/syscalls/migrate_pages/Makefile create mode 100644 testcases/kernel/syscalls/migrate_pages/migrate_pages01.c create mode 100644 testcases/kernel/syscalls/migrate_pages/migrate_pages_common.c create mode 100644 testcases/kernel/syscalls/migrate_pages/migrate_pages_common.h diff --git a/runtest/syscalls b/runtest/syscalls index 6973aaa..9daf234 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -517,6 +517,8 @@ memset01 memset01 memcmp01 memcmp01 memcpy01 memcpy01 +migrate_pages01 migrate_pages01 + mlockall01 mlockall01 mlockall02 mlockall02 mlockall03 mlockall03 diff --git a/testcases/kernel/syscalls/migrate_pages/Makefile b/testcases/kernel/syscalls/migrate_pages/Makefile new file mode 100644 index 0000000..7168cd6 --- /dev/null +++ b/testcases/kernel/syscalls/migrate_pages/Makefile @@ -0,0 +1,32 @@ +# +# Copyright (C) 2012 Linux Test Project, Inc. +# +# 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 will 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, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk + +MAKE_TARGETS := $(patsubst $(abs_srcdir)/%.c,%,$(wildcard $(abs_srcdir)/*[0-9].c)) +$(MAKE_TARGETS): %: %.o migrate_pages_common.o + +ifeq ($(NUMA_LIBS),) +CPPFLAGS += -Wno-unused +endif +CPPFLAGS += -I$(abs_srcdir)/../utils/ + +include $(top_srcdir)/testcases/kernel/include/lib.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/migrate_pages/migrate_pages01.c b/testcases/kernel/syscalls/migrate_pages/migrate_pages01.c new file mode 100644 index 0000000..53ced25 --- /dev/null +++ b/testcases/kernel/syscalls/migrate_pages/migrate_pages01.c @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2012 Linux Test Project, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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. + * + * Further, this software is distributed without any warranty that it + * is free of the rightful claim of any third person regarding + * infringement or the like. Any license provided herein, whether + * implied or otherwise, applies only to this software file. Patent + * licenses, if any, provided herein do not apply to combinations of + * this program with other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/* + * errno tests for migrate_pages() syscall + */ +#include <sys/types.h> +#include <sys/syscall.h> +#include <sys/wait.h> +#include <sys/mman.h> +#include <errno.h> +#if HAVE_NUMA_H +#include <numa.h> +#endif +#if HAVE_NUMAIF_H +#include <numaif.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <pwd.h> +#include "config.h" +#include "test.h" +#include "usctest.h" +#include "safe_macros.h" +#include "linux_syscall_numbers.h" +#include "numa_helper.h" +#include "migrate_pages_common.h" + +char *TCID = "migrate_pages01"; +int TST_TOTAL = 1; + +option_t options[] = { + { NULL, NULL, NULL } +}; + +#if defined(__NR_migrate_pages) && defined(HAVE_NUMA_H) +static unsigned long *sane_old_nodes; +static unsigned long *sane_new_nodes; +static int sane_nodemask_size; +static int sane_max_node; + +static void setup(void); +static void cleanup(void); + +static void test_sane_nodes(void) +{ + tst_resm(TINFO, "test_empty_mask"); + TEST(syscall(__NR_migrate_pages, 0, sane_max_node, + sane_old_nodes, sane_new_nodes)); + check_ret(0); +} + +static void test_invalid_pid(void) +{ + const char pid_max[] = "/proc/sys/kernel/pid_max"; + FILE *fp; + char buff[512]; + pid_t invalid_pid = -1; + + tst_resm(TINFO, "test_invalid_pid -1"); + TEST(syscall(__NR_migrate_pages, invalid_pid, sane_max_node, + sane_old_nodes, sane_new_nodes)); + check_ret(-1); + check_errno(ESRCH); + + tst_resm(TINFO, "test_invalid_pid pid_max+1"); + fp = fopen(pid_max, "r"); + if (fp == NULL) + tst_brkm(TBROK, cleanup, + "Could not open %s", pid_max); + if (!fgets(buff, sizeof(buff), fp)) + tst_brkm(TBROK, cleanup, + "Could not read %s", pid_max); + fclose(fp); + invalid_pid = atol(buff) + 1; + TEST(syscall(__NR_migrate_pages, invalid_pid, sane_max_node, + sane_old_nodes, sane_new_nodes)); + check_ret(-1); + check_errno(ESRCH); +} + +static void test_invalid_masksize(void) +{ + tst_resm(TINFO, "test_invalid_masksize"); + TEST(syscall(__NR_migrate_pages, 0, -1, sane_old_nodes, + sane_new_nodes)); + check_ret(-1); + check_errno(EINVAL); +} + +static void test_invalid_mem(void) +{ + unsigned long *p; + + tst_resm(TINFO, "test_invalid_mem -1"); + TEST(syscall(__NR_migrate_pages, 0, sane_max_node, -1, -1)); + check_ret(-1); + check_errno(EFAULT); + + tst_resm(TINFO, "test_invalid_mem invalid prot"); + p = mmap(NULL, getpagesize(), PROT_NONE, + MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); + if (p == MAP_FAILED) + tst_brkm(TBROK|TERRNO, cleanup, "mmap"); + TEST(syscall(__NR_migrate_pages, 0, sane_max_node, p, p)); + check_ret(-1); + check_errno(EFAULT); + + if (munmap(p, getpagesize()) < 0) + tst_brkm(TBROK|TERRNO, cleanup, "munmap"); + tst_resm(TINFO, "test_invalid_mem unmmaped"); + TEST(syscall(__NR_migrate_pages, 0, sane_max_node, p, p)); + check_ret(-1); + check_errno(EFAULT); +} + +static void test_invalid_nodes(void) +{ + int *nodes; + int num_nodes, ret, i; + int invalid_node = 0; + unsigned long *old_nodes, *new_nodes; + + tst_resm(TINFO, "test_invalid_nodes"); + ret = get_allowed_nodes_arr(NH_MEMS, &num_nodes, &nodes); + if (ret < 0) + tst_brkm(TBROK|TERRNO, cleanup, + "get_allowed_nodes_arr: %d", ret); + + /* get first node which is not in nodes */ + for (i = 0; i < num_nodes; i++, invalid_node++) + if (invalid_node != nodes[i]) + break; + if (invalid_node < sane_max_node) { + old_nodes = SAFE_MALLOC(NULL, sane_nodemask_size); + new_nodes = SAFE_MALLOC(NULL, sane_nodemask_size); + memcpy(old_nodes, sane_old_nodes, sane_nodemask_size); + memset(new_nodes, 0, sane_nodemask_size); + set_bit(new_nodes, invalid_node, 1); + + TEST(syscall(__NR_migrate_pages, 0, sane_max_node, + old_nodes, new_nodes)); + check_ret(-1); + check_errno(EINVAL); + free(old_nodes); + free(new_nodes); + } else { + tst_resm(TCONF, "All possible nodes are present"); + } + + free(nodes); +} + +static void test_invalid_perm(void) +{ + char nobody_uid[] = "nobody"; + struct passwd *ltpuser; + int status; + pid_t child_pid; + pid_t parent_pid; + int ret = 0; + + tst_resm(TINFO, "test_invalid_perm"); + parent_pid = getpid(); + fflush(stdout); + child_pid = fork(); + switch (child_pid) { + case -1: + tst_brkm(TBROK|TERRNO, cleanup, "fork"); + break; + case 0: + ltpuser = getpwnam(nobody_uid); + if (ltpuser == NULL) + tst_brkm(TBROK|TERRNO, NULL, + "getpwnam failed"); + if (setuid(ltpuser->pw_uid) == -1) + tst_brkm(TBROK|TERRNO, NULL, + "setuid(%u) failed", + ltpuser->pw_uid); + TEST(syscall(__NR_migrate_pages, parent_pid, + sane_max_node, sane_old_nodes, + sane_new_nodes)); + ret |= check_ret(-1); + ret |= check_errno(EPERM); + exit(ret); + default: + if (waitpid(child_pid, &status, 0) == -1) + tst_brkm(TBROK|TERRNO, cleanup, "waitpid"); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + tst_resm(TFAIL, "child returns %d", status); + } +} + +int main(int argc, char *argv[]) +{ + int lc; + char *msg; + + msg = parse_opts(argc, argv, options, NULL); + if (msg != NULL) + tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); + + setup(); + for (lc = 0; TEST_LOOPING(lc); lc++) { + Tst_count = 0; + test_sane_nodes(); + test_invalid_pid(); + test_invalid_masksize(); + test_invalid_mem(); + test_invalid_nodes(); + test_invalid_perm(); + } + cleanup(); + tst_exit(); +} + +static void setup(void) +{ + int node, ret; + + tst_require_root(NULL); + TEST(syscall(__NR_migrate_pages, 0, 0, NULL, NULL)); + + if (numa_available() == -1) + tst_brkm(TCONF, NULL, "NUMA not available"); + + ret = get_allowed_nodes(NH_MEMS, 1, &node); + if (ret < 0) + tst_brkm(TBROK|TERRNO, NULL, "get_allowed_nodes_arr: %d", ret); + + sane_max_node = get_max_node(); + sane_nodemask_size = sane_max_node/8+1; + sane_old_nodes = SAFE_MALLOC(NULL, sane_nodemask_size); + sane_new_nodes = SAFE_MALLOC(NULL, sane_nodemask_size); + memset(sane_old_nodes, 0, sane_nodemask_size); + memset(sane_new_nodes, 0, sane_nodemask_size); + + set_bit(sane_old_nodes, node, 1); + set_bit(sane_new_nodes, node, 1); + + TEST_PAUSE; +} + +static void cleanup(void) +{ + free(sane_old_nodes); + free(sane_new_nodes); + TEST_CLEANUP; +} + +#else /* __NR_migrate_pages */ +int main(void) +{ + tst_brkm(TCONF, NULL, "System doesn't support __NR_migrate_pages" + " or libnuma is not available"); +} +#endif diff --git a/testcases/kernel/syscalls/migrate_pages/migrate_pages_common.c b/testcases/kernel/syscalls/migrate_pages/migrate_pages_common.c new file mode 100644 index 0000000..00b512a --- /dev/null +++ b/testcases/kernel/syscalls/migrate_pages/migrate_pages_common.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2012 Linux Test Project, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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. + * + * Further, this software is distributed without any warranty that it + * is free of the rightful claim of any third person regarding + * infringement or the like. Any license provided herein, whether + * implied or otherwise, applies only to this software file. Patent + * licenses, if any, provided herein do not apply to combinations of + * this program with other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "test.h" +#include "usctest.h" +#include "migrate_pages_common.h" + +void set_bit(unsigned long *b, unsigned int n, unsigned int v) +{ + if (v) + b[n/bitsperlong] |= 1UL << (n % bitsperlong); + else + b[n/bitsperlong] &= ~(1UL << (n % bitsperlong)); +} + +int check_ret(long expected_ret) +{ + if (expected_ret == TEST_RETURN) { + tst_resm(TPASS, "expected ret success - " + "returned value = %ld", TEST_RETURN); + return 0; + } else + tst_resm(TFAIL, "unexpected failure - " + "returned value = %ld, expected: %ld", + TEST_RETURN, expected_ret); + return 1; +} + +int check_errno(long expected_errno) +{ + if (TEST_ERRNO == expected_errno) { + tst_resm(TPASS|TTERRNO, "expected failure"); + return 0; + } else if (TEST_ERRNO == 0) + tst_resm(TFAIL, "call succeeded unexpectedly"); + else + tst_resm(TFAIL|TTERRNO, "unexpected failure - " + "expected = %ld : %s, actual", + expected_errno, strerror(expected_errno)); + return 1; +} diff --git a/testcases/kernel/syscalls/migrate_pages/migrate_pages_common.h b/testcases/kernel/syscalls/migrate_pages/migrate_pages_common.h new file mode 100644 index 0000000..d821b07 --- /dev/null +++ b/testcases/kernel/syscalls/migrate_pages/migrate_pages_common.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2012 Linux Test Project, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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. + * + * Further, this software is distributed without any warranty that it + * is free of the rightful claim of any third person regarding + * infringement or the like. Any license provided herein, whether + * implied or otherwise, applies only to this software file. Patent + * licenses, if any, provided herein do not apply to combinations of + * this program with other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef MIGRATE_PAGES_COMMON_H +#define MIGRATE_PAGES_COMMON_H + +#define bitsperlong (8 * sizeof(unsigned long)) + +void set_bit(unsigned long *b, unsigned int n, unsigned int v); +int check_ret(long expected_ret); +int check_errno(long expected_errno); +#endif -- 1.7.1 |