1 /* 2 * Copyright (c) 2008 Vijay Kumar B. <vijaykumar (at) bravegnu.org> 3 * 4 * Based on testcases/kernel/syscalls/waitpid/waitpid01.c 5 * Original copyright message: 6 * 7 * Copyright (c) International Business Machines Corp., 2001 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 17 * the GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24 /* 25 * NAME 26 * move_pages03.c 27 * 28 * DESCRIPTION 29 * Test movement of pages mapped by a process. 30 * 31 * ALGORITHM 32 * 1. Start the test case program as root. 33 * 2. Allocate a shared memory in NUMA node A. 34 * 3. Fork another process. 35 * 4. Use move_pages() to move the pages to NUMA node B, with the 36 * MPOL_MF_MOVE_ALL. 37 * 5. Check if all pages are in node B. 38 * 39 * USAGE: <for command-line> 40 * move_pages03 [-c n] [-i n] [-I x] [-P x] [-t] 41 * where, -c n : Run n copies concurrently. 42 * -i n : Execute test n times. 43 * -I x : Execute test for x seconds. 44 * -P x : Pause for x seconds between iterations. 45 * -t : Turn on syscall timing. 46 * 47 * History 48 * 05/2008 Vijay Kumar 49 * Initial Version. 50 * 51 * Restrictions 52 * None 53 */ 54 55 #include <sys/types.h> 56 #include <sys/wait.h> 57 #include <unistd.h> 58 #include <signal.h> 59 #include <semaphore.h> 60 #include <errno.h> 61 #include "test.h" 62 #include "move_pages_support.h" 63 64 #define TEST_PAGES 2 65 #define TEST_NODES 2 66 67 enum { 68 SEM_CHILD_SETUP, 69 SEM_PARENT_TEST, 70 71 MAX_SEMS 72 }; 73 74 void setup(void); 75 void cleanup(void); 76 77 char *TCID = "move_pages03"; 78 int TST_TOTAL = 1; 79 80 /* 81 * child() - touches shared pages, and waits for signal from parent. 82 * @pages: shared pages allocated in parent 83 * @sem: semaphore to sync with parent 84 */ 85 void child(void **pages, sem_t * sem) 86 { 87 int i; 88 89 for (i = 0; i < TEST_PAGES; i++) { 90 char *page; 91 92 page = pages[i]; 93 page[0] = 0xAA; 94 } 95 96 /* Setup complete. Ask parent to continue. */ 97 if (sem_post(&sem[SEM_CHILD_SETUP]) == -1) 98 tst_resm(TWARN | TERRNO, "error post semaphore"); 99 100 /* Wait for testcase in parent to complete. */ 101 if (sem_wait(&sem[SEM_PARENT_TEST]) == -1) 102 tst_resm(TWARN | TERRNO, "error wait semaphore"); 103 104 exit(0); 105 } 106 107 int main(int argc, char **argv) 108 { 109 110 tst_parse_opts(argc, argv, NULL, NULL); 111 112 setup(); 113 114 #if HAVE_NUMA_MOVE_PAGES 115 unsigned int i; 116 int lc; 117 unsigned int from_node; 118 unsigned int to_node; 119 int ret; 120 121 ret = get_allowed_nodes(NH_MEMS, 2, &from_node, &to_node); 122 if (ret < 0) 123 tst_brkm(TBROK | TERRNO, cleanup, "get_allowed_nodes: %d", ret); 124 125 /* check for looping state if -i option is given */ 126 for (lc = 0; TEST_LOOPING(lc); lc++) { 127 void *pages[TEST_PAGES] = { 0 }; 128 int nodes[TEST_PAGES]; 129 int status[TEST_PAGES]; 130 pid_t cpid; 131 sem_t *sem; 132 133 /* reset tst_count in case we are looping */ 134 tst_count = 0; 135 136 ret = alloc_shared_pages_on_node(pages, TEST_PAGES, from_node); 137 if (ret == -1) 138 continue; 139 140 for (i = 0; i < TEST_PAGES; i++) { 141 nodes[i] = to_node; 142 } 143 144 sem = alloc_sem(MAX_SEMS); 145 if (sem == NULL) { 146 goto err_free_pages; 147 } 148 149 /* 150 * Fork a child process so that the shared pages are 151 * now really shared between two processes. 152 */ 153 cpid = fork(); 154 if (cpid == -1) { 155 tst_resm(TBROK | TERRNO, "forking child failed"); 156 goto err_free_sem; 157 } else if (cpid == 0) { 158 child(pages, sem); 159 } 160 161 /* Wait for child to setup and signal. */ 162 if (sem_wait(&sem[SEM_CHILD_SETUP]) == -1) 163 tst_resm(TWARN | TERRNO, "error wait semaphore"); 164 165 ret = numa_move_pages(0, TEST_PAGES, pages, nodes, 166 status, MPOL_MF_MOVE_ALL); 167 if (ret != 0) { 168 tst_resm(TFAIL|TERRNO, "move_pages failed"); 169 goto err_kill_child; 170 } 171 172 verify_pages_on_node(pages, status, TEST_PAGES, to_node); 173 174 err_kill_child: 175 /* Test done. Ask child to terminate. */ 176 if (sem_post(&sem[SEM_PARENT_TEST]) == -1) 177 tst_resm(TWARN | TERRNO, "error post semaphore"); 178 /* Read the status, no zombies! */ 179 wait(NULL); 180 err_free_sem: 181 free_sem(sem, MAX_SEMS); 182 err_free_pages: 183 free_shared_pages(pages, TEST_PAGES); 184 } 185 #else 186 tst_resm(TCONF, "move_pages support not found."); 187 #endif 188 189 cleanup(); 190 191 tst_exit(); 192 } 193 194 /* 195 * setup() - performs all ONE TIME setup for this test 196 */ 197 void setup(void) 198 { 199 200 tst_sig(FORK, DEF_HANDLER, cleanup); 201 202 check_config(TEST_NODES); 203 204 /* Pause if that option was specified 205 * TEST_PAUSE contains the code to fork the test with the -c option. 206 */ 207 TEST_PAUSE; 208 } 209 210 /* 211 * cleanup() - performs all ONE TIME cleanup for this test at completion 212 */ 213 void cleanup(void) 214 { 215 216 } 217