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_pages11.c 27 * 28 * DESCRIPTION 29 * Failure when trying move shared pages. 30 * 31 * ALGORITHM 32 * 1. Allocate a shared memory in NUMA node A. 33 * 2. Fork another process. 34 * 3. Use move_pages() to move the pages to NUMA node B, with the 35 * MPOL_MF_MOVE_ALL. 36 * 4. Check if errno is set to EPERM. 37 * 38 * USAGE: <for command-line> 39 * move_pages11 [-c n] [-i n] [-I x] [-P x] [-t] 40 * where, -c n : Run n copies concurrently. 41 * -i n : Execute test n times. 42 * -I x : Execute test for x seconds. 43 * -P x : Pause for x seconds between iterations. 44 * -t : Turn on syscall timing. 45 * 46 * History 47 * 05/2008 Vijay Kumar 48 * Initial Version. 49 * 50 * Restrictions 51 * None 52 */ 53 54 #include <sys/types.h> 55 #include <sys/wait.h> 56 #include <unistd.h> 57 #include <signal.h> 58 #include <semaphore.h> 59 #include <errno.h> 60 #include <pwd.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_pages11"; 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, "error post semaphore: %s", strerror(errno)); 99 100 /* Wait for testcase in parent to complete. */ 101 if (sem_wait(&sem[SEM_PARENT_TEST]) == -1) 102 tst_resm(TWARN, "error wait semaphore: %s", strerror(errno)); 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, "forking child failed: %s", 156 strerror(errno)); 157 goto err_free_sem; 158 } else if (cpid == 0) { 159 child(pages, sem); 160 } 161 162 /* Wait for child to setup and signal. */ 163 if (sem_wait(&sem[SEM_CHILD_SETUP]) == -1) 164 tst_resm(TWARN, "error wait semaphore: %s", 165 strerror(errno)); 166 167 ret = numa_move_pages(0, TEST_PAGES, pages, nodes, 168 status, MPOL_MF_MOVE_ALL); 169 if (ret == -1 && errno == EPERM) 170 tst_resm(TPASS, "move_pages failed with " 171 "EPERM as expected"); 172 else 173 tst_resm(TFAIL|TERRNO, "move_pages did not fail " 174 "with EPERM ret: %d", ret); 175 176 /* Test done. Ask child to terminate. */ 177 if (sem_post(&sem[SEM_PARENT_TEST]) == -1) 178 tst_resm(TWARN, "error post semaphore: %s", 179 strerror(errno)); 180 /* Read the status, no zombies! */ 181 wait(NULL); 182 err_free_sem: 183 free_sem(sem, MAX_SEMS); 184 err_free_pages: 185 free_shared_pages(pages, TEST_PAGES); 186 } 187 #else 188 tst_resm(TCONF, "move_pages support not found."); 189 #endif 190 191 cleanup(); 192 193 tst_exit(); 194 } 195 196 /* 197 * setup() - performs all ONE TIME setup for this test 198 */ 199 void setup(void) 200 { 201 struct passwd *ltpuser; 202 203 tst_require_root(); 204 205 tst_sig(FORK, DEF_HANDLER, cleanup); 206 207 check_config(TEST_NODES); 208 209 if ((ltpuser = getpwnam("nobody")) == NULL) { 210 tst_brkm(TBROK, NULL, "'nobody' user not present"); 211 } 212 213 if (seteuid(ltpuser->pw_uid) == -1) { 214 tst_brkm(TBROK, NULL, "setting uid to %d failed", 215 ltpuser->pw_uid); 216 } 217 218 /* Pause if that option was specified 219 * TEST_PAUSE contains the code to fork the test with the -c option. 220 */ 221 TEST_PAUSE; 222 } 223 224 /* 225 * cleanup() - performs all ONE TIME cleanup for this test at completion 226 */ 227 void cleanup(void) 228 { 229 230 } 231