* [LTP] [PATCH v3 2/3] new syscall test: migrate_pages01
2012-10-26 13:31 [LTP] [PATCH v3 0/3] new syscall tests for migrate_pages Jan Stancek
2012-10-26 13:31 ` [LTP] [PATCH v3 1/3] numa_helper: export get_max_node() Jan Stancek
@ 2012-10-26 13:31 ` Jan Stancek
2012-11-02 2:00 ` Wanlong Gao
2012-10-26 13:31 ` [LTP] [PATCH v3 3/3] new syscall test: migrate_pages02 Jan Stancek
2 siblings, 1 reply; 8+ messages in thread
From: Jan Stancek @ 2012-10-26 13:31 UTC (permalink / raw)
To: ltp-list
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 <jstancek@redhat.com>
---
runtest/syscalls | 2 +
testcases/kernel/syscalls/.gitignore | 1 +
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 +++
6 files changed, 410 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/.gitignore b/testcases/kernel/syscalls/.gitignore
index 7df28c2..e883617 100644
--- a/testcases/kernel/syscalls/.gitignore
+++ b/testcases/kernel/syscalls/.gitignore
@@ -472,6 +472,7 @@
/memcpy/memcpy01
/memmap/mem03
/memset/memset01
+/migrate_pages/migrate_pages01
/mincore/mincore01
/mincore/mincore02
/mkdir/mkdir01
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..a96d75d
--- /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
------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_sfd2d_oct
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list
^ permalink raw reply related [flat|nested] 8+ messages in thread* [LTP] [PATCH v3 3/3] new syscall test: migrate_pages02
2012-10-26 13:31 [LTP] [PATCH v3 0/3] new syscall tests for migrate_pages Jan Stancek
2012-10-26 13:31 ` [LTP] [PATCH v3 1/3] numa_helper: export get_max_node() Jan Stancek
2012-10-26 13:31 ` [LTP] [PATCH v3 2/3] new syscall test: migrate_pages01 Jan Stancek
@ 2012-10-26 13:31 ` Jan Stancek
2012-11-02 2:02 ` Wanlong Gao
2 siblings, 1 reply; 8+ messages in thread
From: Jan Stancek @ 2012-10-26 13:31 UTC (permalink / raw)
To: ltp-list
Use migrate_pages() syscall and check that
shared/non-shared memory is migrated to desired node.
Signed-off-by: Jan Stancek <jstancek@redhat.com>
---
runtest/syscalls | 1 +
testcases/kernel/syscalls/.gitignore | 1 +
.../syscalls/migrate_pages/migrate_pages01.c | 2 +-
.../syscalls/migrate_pages/migrate_pages02.c | 419 ++++++++++++++++++++
4 files changed, 422 insertions(+), 1 deletions(-)
create mode 100644 testcases/kernel/syscalls/migrate_pages/migrate_pages02.c
diff --git a/runtest/syscalls b/runtest/syscalls
index 9daf234..78f3bd3 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -518,6 +518,7 @@ memcmp01 memcmp01
memcpy01 memcpy01
migrate_pages01 migrate_pages01
+migrate_pages02 migrate_pages02
mlockall01 mlockall01
mlockall02 mlockall02
diff --git a/testcases/kernel/syscalls/.gitignore b/testcases/kernel/syscalls/.gitignore
index e883617..a146eee 100644
--- a/testcases/kernel/syscalls/.gitignore
+++ b/testcases/kernel/syscalls/.gitignore
@@ -473,6 +473,7 @@
/memmap/mem03
/memset/memset01
/migrate_pages/migrate_pages01
+/migrate_pages/migrate_pages02
/mincore/mincore01
/mincore/mincore02
/mkdir/mkdir01
diff --git a/testcases/kernel/syscalls/migrate_pages/migrate_pages01.c b/testcases/kernel/syscalls/migrate_pages/migrate_pages01.c
index 53ced25..1c52b62 100644
--- a/testcases/kernel/syscalls/migrate_pages/migrate_pages01.c
+++ b/testcases/kernel/syscalls/migrate_pages/migrate_pages01.c
@@ -56,7 +56,7 @@ option_t options[] = {
{ NULL, NULL, NULL }
};
-#if defined(__NR_migrate_pages) && defined(HAVE_NUMA_H)
+#if defined(__NR_migrate_pages) && HAVE_NUMA_H && HAVE_NUMAIF_H
static unsigned long *sane_old_nodes;
static unsigned long *sane_new_nodes;
static int sane_nodemask_size;
diff --git a/testcases/kernel/syscalls/migrate_pages/migrate_pages02.c b/testcases/kernel/syscalls/migrate_pages/migrate_pages02.c
new file mode 100644
index 0000000..b1c294a
--- /dev/null
+++ b/testcases/kernel/syscalls/migrate_pages/migrate_pages02.c
@@ -0,0 +1,419 @@
+/*
+ * 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.
+ */
+
+/*
+ * use migrate_pages() and check that address is on correct node
+ * 1. process A can migrate its non-shared mem with CAP_SYS_NICE
+ * 2. process A can migrate its non-shared mem without CAP_SYS_NICE
+ * 3. process A can migrate shared mem only with CAP_SYS_NICE
+ * 4. process A can migrate non-shared mem in process B with same effective uid
+ * 5. process A can migrate non-shared mem in process B with CAP_SYS_NICE
+ */
+#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 <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"
+
+/*
+ * This is an estimated minimum of free mem required to migrate this
+ * process to another node as migrate_pages will fail if there is not
+ * enough free space on node. While running this test on x86_64
+ * it used ~2048 pages (total VM, not just RSS). Considering ia64 as
+ * architecture with largest (non-huge) page size (16k), this limit
+ * is set to 2048*16k == 32M.
+ */
+#define NODE_MIN_FREEMEM (32*1024*1024)
+
+char *TCID = "migrate_pages02";
+int TST_TOTAL = 1;
+
+#if defined(__NR_migrate_pages) && HAVE_NUMA_H && HAVE_NUMAIF_H
+static const char nobody_uid[] = "nobody";
+static struct passwd *ltpuser;
+static int *nodes, nodeA, nodeB;
+static int num_nodes;
+
+static void setup(void);
+static void cleanup(void);
+
+option_t options[] = {
+ { NULL, NULL, NULL }
+};
+
+static void print_mem_stats(pid_t pid, int node)
+{
+ char s[64];
+ long long node_size, freep;
+
+ if (pid == 0)
+ pid = getpid();
+
+ tst_resm(TINFO, "mem_stats pid: %d, node: %d", pid, node);
+
+ /* dump pid's VM info */
+ sprintf(s, "cat /proc/%d/status", pid);
+ system(s);
+ sprintf(s, "cat /proc/%d/numa_maps", pid);
+ system(s);
+
+ /* dump node free mem */
+ node_size = numa_node_size64(node, &freep);
+ tst_resm(TINFO, "Node id: %d, size: %lld, free: %lld",
+ node, node_size, freep);
+}
+
+static int migrate_to_node(pid_t pid, int node)
+{
+ unsigned long nodemask_size, max_node;
+ unsigned long *old_nodes, *new_nodes;
+ int i;
+
+ tst_resm(TINFO, "pid(%d) migrate pid %d to node -> %d",
+ getpid(), pid, node);
+ max_node = get_max_node();
+ nodemask_size = max_node/8+1;
+ old_nodes = SAFE_MALLOC(NULL, nodemask_size);
+ new_nodes = SAFE_MALLOC(NULL, nodemask_size);
+
+ memset(old_nodes, 0, nodemask_size);
+ memset(new_nodes, 0, nodemask_size);
+ for (i = 0; i < num_nodes; i++)
+ set_bit(old_nodes, nodes[i], 1);
+ set_bit(new_nodes, node, 1);
+
+ TEST(syscall(__NR_migrate_pages, pid, max_node, old_nodes, new_nodes));
+ if (TEST_RETURN != 0) {
+ if (TEST_RETURN < 0)
+ tst_resm(TFAIL|TERRNO, "migrate_pages failed "
+ "ret: %ld, ", TEST_RETURN);
+ else
+ tst_resm(TWARN, "migrate_pages could not migrate all "
+ "pages, not migrated: %ld", TEST_RETURN);
+ print_mem_stats(pid, node);
+ }
+ free(old_nodes);
+ free(new_nodes);
+ return TEST_RETURN;
+}
+
+static int addr_on_node(void *addr)
+{
+ int node;
+ int ret;
+
+ ret = syscall(__NR_get_mempolicy, &node, NULL, (unsigned long)0,
+ (unsigned long) addr, MPOL_F_NODE | MPOL_F_ADDR);
+ if (ret == -1) {
+ tst_resm(TBROK | TERRNO, "error getting memory policy "
+ "for page %p", addr);
+ }
+ return node;
+}
+
+static int check_addr_on_node(void *addr, int exp_node)
+{
+ int node;
+
+ node = addr_on_node(addr);
+ if (node == exp_node) {
+ tst_resm(TPASS, "pid(%d) addr %p is on expected node: %d",
+ getpid(), addr, exp_node);
+ return 0;
+ } else {
+ tst_resm(TFAIL, "pid(%d) addr %p not on expected node: %d "
+ ", expected %d", getpid(), addr, node,
+ exp_node);
+ print_mem_stats(0, exp_node);
+ return 1;
+ }
+}
+
+static void test_migrate_current_process(int node1, int node2,
+ int cap_sys_nice)
+{
+ char *testp, *testp2;
+ int ret, status;
+ pid_t child;
+
+ /* parent can migrate its non-shared memory */
+ tst_resm(TINFO, "current_process, cap_sys_nice: %d", cap_sys_nice);
+ testp = SAFE_MALLOC(NULL, getpagesize());
+ testp[0] = 0;
+ tst_resm(TINFO, "private anonymous: %p", testp);
+ migrate_to_node(0, node2);
+ check_addr_on_node(testp, node2);
+ migrate_to_node(0, node1);
+ check_addr_on_node(testp, node1);
+ free(testp);
+
+ /* parent can migrate shared memory with CAP_SYS_NICE */
+ testp2 = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_SHARED, 0, 0);
+ if (testp2 == MAP_FAILED)
+ tst_brkm(TBROK|TERRNO, cleanup, "mmap failed");
+ testp2[0] = 1;
+ tst_resm(TINFO, "shared anonymous: %p", testp2);
+ migrate_to_node(0, node2);
+ check_addr_on_node(testp2, node2);
+
+ /* shared mem is on node2, try to migrate in child to node1 */
+ fflush(stdout);
+ child = fork();
+ switch (child) {
+ case -1:
+ tst_brkm(TBROK|TERRNO, cleanup, "fork");
+ break;
+ case 0:
+ tst_resm(TINFO, "child shared anonymous, cap_sys_nice: %d",
+ cap_sys_nice);
+ testp = SAFE_MALLOC(NULL, getpagesize());
+ testp[0] = 1;
+ testp2[0] = 1;
+ if (!cap_sys_nice)
+ if (seteuid(ltpuser->pw_uid) == -1)
+ tst_brkm(TBROK|TERRNO, NULL, "seteuid failed");
+
+ migrate_to_node(0, node1);
+ /* child can migrate non-shared memory */
+ ret = check_addr_on_node(testp, node1);
+
+ free(testp);
+ munmap(testp2, getpagesize());
+ exit(ret);
+ default:
+ if (waitpid(child, &status, 0) == -1)
+ tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ tst_resm(TFAIL, "child returns %d", status);
+ if (cap_sys_nice)
+ /* child can migrate shared memory only
+ * with CAP_SYS_NICE */
+ check_addr_on_node(testp2, node1);
+ else
+ check_addr_on_node(testp2, node2);
+ munmap(testp2, getpagesize());
+ }
+}
+
+static void test_migrate_other_process(int node1, int node2,
+ int cap_sys_nice)
+{
+ char *testp;
+ int status, ret, tmp;
+ pid_t child;
+ int child_ready[2];
+ int pages_migrated[2];
+
+ /* setup pipes to synchronize child/parent */
+ if (pipe(child_ready) == -1)
+ tst_resm(TBROK | TERRNO, "pipe #1 failed");
+ if (pipe(pages_migrated) == -1)
+ tst_resm(TBROK | TERRNO, "pipe #2 failed");
+
+ tst_resm(TINFO, "other_process, cap_sys_nice: %d", cap_sys_nice);
+
+ fflush(stdout);
+ child = fork();
+ switch (child) {
+ case -1:
+ tst_brkm(TBROK|TERRNO, cleanup, "fork");
+ break;
+ case 0:
+ close(child_ready[0]);
+ close(pages_migrated[1]);
+
+ testp = SAFE_MALLOC(NULL, getpagesize());
+ testp[0] = 0;
+
+ /* make sure we are on node1 */
+ migrate_to_node(0, node1);
+ check_addr_on_node(testp, node1);
+
+ if (seteuid(ltpuser->pw_uid) == -1)
+ tst_brkm(TBROK|TERRNO, NULL, "seteuid failed");
+
+ /* signal parent it's OK to migrate child and wait */
+ if (write(child_ready[1], &tmp, 1) != 1)
+ tst_brkm(TBROK|TERRNO, NULL, "write #1 failed");
+ if (read(pages_migrated[0], &tmp, 1) != 1)
+ tst_brkm(TBROK|TERRNO, NULL, "read #1 failed");
+
+ /* parent can migrate child process with same euid */
+ /* parent can migrate child process with CAP_SYS_NICE */
+ ret = check_addr_on_node(testp, node2);
+
+ free(testp);
+ close(child_ready[1]);
+ close(pages_migrated[0]);
+ exit(ret);
+ default:
+ close(child_ready[1]);
+ close(pages_migrated[0]);
+
+ if (!cap_sys_nice)
+ if (seteuid(ltpuser->pw_uid) == -1)
+ tst_brkm(TBROK|TERRNO, NULL, "seteuid failed");
+
+ /* wait until child is ready on node1, then migrate and
+ * signal to check current node */
+ if (read(child_ready[0], &tmp, 1) != 1)
+ tst_brkm(TBROK|TERRNO, NULL, "read #2 failed");
+ migrate_to_node(child, node2);
+ if (write(pages_migrated[1], &tmp, 1) != 1)
+ tst_brkm(TBROK|TERRNO, NULL, "write #2 failed");
+
+ if (waitpid(child, &status, 0) == -1)
+ tst_brkm(TBROK|TERRNO, cleanup, "waitpid");
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ tst_resm(TFAIL, "child returns %d", status);
+ close(child_ready[0]);
+ close(pages_migrated[1]);
+
+ /* reset euid, so this testcase can be used in loop */
+ if (!cap_sys_nice)
+ if (seteuid(0) == -1)
+ tst_brkm(TBROK|TERRNO, NULL, "seteuid failed");
+ }
+}
+
+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_migrate_current_process(nodeA, nodeB, 1);
+ test_migrate_current_process(nodeA, nodeB, 0);
+ test_migrate_other_process(nodeA, nodeB, 1);
+ test_migrate_other_process(nodeA, nodeB, 0);
+ }
+ cleanup();
+ tst_exit();
+}
+
+static void setup(void)
+{
+ int ret, i, j;
+ int pagesize = getpagesize();
+ void *p;
+
+ 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_arr(NH_MEMS, &num_nodes, &nodes);
+ if (ret < 0)
+ tst_brkm(TBROK|TERRNO, NULL, "get_allowed_nodes(): %d", ret);
+
+ if (num_nodes < 2)
+ tst_brkm(TCONF, NULL, "at least 2 allowed NUMA nodes"
+ " are required");
+ else if (tst_kvercmp(2, 6, 18) < 0)
+ tst_brkm(TCONF, NULL, "2.6.18 or greater kernel required");
+
+ /*
+ * find 2 nodes, which can hold NODE_MIN_FREEMEM bytes
+ * The reason is that:
+ * 1. migrate_pages() is expected to succeed
+ * 2. this test avoids hitting:
+ * Bug 870326 - migrate_pages() reports success, but pages are
+ * not moved to desired node
+ * https://bugzilla.redhat.com/show_bug.cgi?id=870326
+ */
+ nodeA = nodeB = -1;
+ for (i = 0; i < num_nodes; i++) {
+ p = numa_alloc_onnode(NODE_MIN_FREEMEM, nodes[i]);
+ if (p == NULL)
+ break;
+ memset(p, 0xff, NODE_MIN_FREEMEM);
+
+ j = 0;
+ while (j < NODE_MIN_FREEMEM) {
+ if (addr_on_node(p+j) != nodes[i])
+ break;
+ j += pagesize;
+ }
+ numa_free(p, NODE_MIN_FREEMEM);
+
+ if (j >= NODE_MIN_FREEMEM) {
+ if (nodeA == -1)
+ nodeA = nodes[i];
+ else if (nodeB == -1)
+ nodeB = nodes[i];
+ else
+ break;
+ }
+ }
+
+ if (nodeA == -1 || nodeB == -1)
+ tst_brkm(TCONF, NULL, "at least 2 NUMA nodes with "
+ "free mem > %d are needed", NODE_MIN_FREEMEM);
+ tst_resm(TINFO, "Using nodes: %d %d", nodeA, nodeB);
+
+ ltpuser = getpwnam(nobody_uid);
+ if (ltpuser == NULL)
+ tst_brkm(TBROK|TERRNO, NULL, "getpwnam failed");
+
+ TEST_PAUSE;
+}
+
+static void cleanup(void)
+{
+ free(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
--
1.7.1
------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_sfd2d_oct
_______________________________________________
Ltp-list mailing list
Ltp-list@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ltp-list
^ permalink raw reply related [flat|nested] 8+ messages in thread