Hi Jan,
On 10/18/2012 08:56 PM, Jan Stancek wrote:
> Use migrate_pages() syscall and check that
> shared/non-shared memory is migrated to desired node.
>
> Signed-off-by: Jan Stancek <[email protected]>
> ---
> runtest/syscalls | 1 +
> .../syscalls/migrate_pages/migrate_pages02.c | 363
> ++++++++++++++++++++
> 2 files changed, 364 insertions(+), 0 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/migrate_pages/migrate_pages02.c
> b/testcases/kernel/syscalls/migrate_pages/migrate_pages02.c
> new file mode 100644
> index 0000000..840aa2b
> --- /dev/null
> +++ b/testcases/kernel/syscalls/migrate_pages/migrate_pages02.c
> @@ -0,0 +1,363 @@
> +/*
> + * 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"
> +
> +#define NODE_MIN_FREEMEM 32*1024*1024
I think we can give some comments to explain why the minimum free memory
is 32M.
> +
> +char *TCID = "migrate_pages02";
> +int TST_TOTAL = 1;
> +
> +#if defined(__NR_migrate_pages) && HAVE_NUMA_H && HAVE_NUMAIF_H
> +static 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 int migrate_to_node(int pid, int node)
> +{
> + unsigned long nodemask_size, max_node;
> + unsigned long *old_nodes, *new_nodes;
> + int i;
> +
> + tst_resm(TPASS, "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 == -1)
> + tst_resm(TFAIL|TERRNO, "migrate_pages failed ");
> + 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);
get_mempolicy() syscall is defined as
int get_mempolicy(int *mode, unsigned long *nodemask,
unsigned long maxnode, unsigned long addr,
unsigned long flags);
and the 1st arg is the policy of memory, the 2nd arg is nodemask,
but in your codes, the 1st arg is '&node', I'm confusing how it can
implement to get the node id of address?
Thanks,
Zhouping
> + 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);
> + 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;
> + long long freep, maxA, maxB, node_size;
> +
> + 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");
> +
> + /* get 2 nodes with max free mem */
> + maxA = maxB = 0;
> + nodeA = nodeB = -1;
> + for (i=0; i<num_nodes; i++) {
> + node_size = numa_node_size64(nodes[i], &freep);
> + if (node_size < 0)
> + tst_brkm(TBROK|TERRNO, NULL, "numa_node_size64 failed");
> + if (freep > NODE_MIN_FREEMEM) {
> + if (freep > maxA) {
> + maxB = maxA;
> + nodeB = nodeA;
> + maxA = freep;
> + nodeA = nodes[i];
> + } else if (freep > maxB) {
> + maxB = freep;
> + nodeB = nodes[i];
> + }
> + }
> + }
> +
> + 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
------------------------------------------------------------------------------
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/ltp-list