1 /* 2 * Copyright (c) International Business Machines Corp., 2001 3 * Copyright (c) Linux Test Project, 2001-2017 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 */ 15 16 /* 17 * DESCRIPTION 18 * hugeshmat01 - test that shmat() works correctly 19 * 20 * ALGORITHM 21 * create a large shared memory resouce with read/write permissions 22 * loop if that option was specified 23 * call shmat() with the TEST() macro using three valid conditions 24 * check the return code 25 * if failure, issue a FAIL message. 26 * otherwise, 27 * if doing functionality testing 28 * check for the correct conditions after the call 29 * if correct, 30 * issue a PASS message 31 * otherwise 32 * issue a FAIL message 33 * call cleanup 34 * 35 * HISTORY 36 * 03/2001 - Written by Wayne Boyer 37 * 04/2004 - Updated by Robbie Williamson 38 */ 39 40 #include <limits.h> 41 #include "hugetlb.h" 42 43 #define CASE0 10 /* values to write into the shared */ 44 #define CASE1 20 /* memory location. */ 45 46 static size_t shm_size; 47 static int shm_id_1 = -1; 48 static void *addr; 49 50 static long hugepages = 128; 51 52 static struct tst_option options[] = { 53 {"s:", &nr_opt, "-s num Set the number of the been allocated hugepages"}, 54 {NULL, NULL, NULL} 55 }; 56 57 static struct tcase { 58 int *shmid; 59 void *addr; 60 int flags; 61 } tcases[] = { 62 /* a straight forward read/write attach */ 63 {&shm_id_1, 0, 0}, 64 /* 65 * an attach using non aligned memory 66 * -1 will be replaced with an unaligned addr 67 */ 68 {&shm_id_1, (void *)-1, SHM_RND}, 69 /* a read only attach */ 70 {&shm_id_1, 0, SHM_RDONLY} 71 }; 72 73 static void check_functionality(unsigned int i); 74 75 static void verify_hugeshmat(unsigned int i) 76 { 77 struct tcase *tc = &tcases[i]; 78 79 addr = shmat(*(tc->shmid), tc->addr, tc->flags); 80 if (addr == (void *)-1) { 81 tst_brk(TFAIL | TERRNO, "shmat"); 82 } else { 83 check_functionality(i); 84 } 85 86 /* 87 * addr in tcases[0] will be used to generate an unaligned 88 * address for tcases[1] 89 */ 90 if (i == 0 && addr != (void *)-1) 91 tc[1].addr = (void *)(((unsigned long)addr & 92 ~(SHMLBA - 1)) + SHMLBA - 1); 93 if (shmdt(addr) == -1) 94 tst_brk(TBROK | TERRNO, "shmdt"); 95 } 96 97 /* 98 * check_functionality - check various conditions to make sure they 99 * are correct. 100 */ 101 static void check_functionality(unsigned int i) 102 { 103 void *orig_add; 104 int *shared; 105 struct shmid_ds buf; 106 107 shared = (int *)addr; 108 109 /* stat the shared memory ID */ 110 if (shmctl(shm_id_1, IPC_STAT, &buf) == -1) 111 tst_brk(TBROK | TERRNO, "shmctl"); 112 113 /* check the number of attaches */ 114 if (buf.shm_nattch != 1) { 115 tst_res(TFAIL, "# of attaches is incorrect"); 116 return; 117 } 118 119 /* check the size of the segment */ 120 if (buf.shm_segsz != shm_size) { 121 tst_res(TFAIL, "segment size is incorrect"); 122 return; 123 } 124 125 /* check for specific conditions depending on the type of attach */ 126 switch (i) { 127 case 0: 128 /* 129 * Check the functionality of the first call by simply 130 * "writing" a value to the shared memory space. 131 * If this fails the program will get a SIGSEGV, dump 132 * core and exit. 133 */ 134 *shared = CASE0; 135 break; 136 case 1: 137 /* 138 * Check the functionality of the second call by writing 139 * a value to the shared memory space and then checking 140 * that the original address given was rounded down as 141 * specified in the man page. 142 */ 143 *shared = CASE1; 144 orig_add = addr + ((unsigned long)tcases[i].addr % SHMLBA); 145 if (orig_add != tcases[i].addr) { 146 tst_res(TFAIL, "shared memory address is not " 147 "correct"); 148 return; 149 } 150 break; 151 case 2: 152 /* 153 * This time the shared memory is read only. Read the value 154 * and check that it is equal to the value set in case #2, 155 * because shared memory is persistent. 156 */ 157 if (*shared != CASE1) { 158 tst_res(TFAIL, "shared memory value isn't correct"); 159 return; 160 } 161 break; 162 } 163 tst_res(TPASS, "conditions and functionality are correct"); 164 } 165 166 static void setup(void) 167 { 168 long hpage_size; 169 170 save_nr_hugepages(); 171 if (nr_opt) 172 hugepages = SAFE_STRTOL(nr_opt, 0, LONG_MAX); 173 174 set_sys_tune("nr_hugepages", hugepages, 1); 175 hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024; 176 177 shm_size = hpage_size * hugepages / 2; 178 update_shm_size(&shm_size); 179 shmkey = getipckey(); 180 shm_id_1 = shmget(shmkey++, shm_size, 181 SHM_HUGETLB | SHM_RW | IPC_CREAT | IPC_EXCL); 182 if (shm_id_1 == -1) 183 tst_brk(TBROK | TERRNO, "shmget"); 184 185 } 186 187 static void cleanup(void) 188 { 189 rm_shm(shm_id_1); 190 restore_nr_hugepages(); 191 } 192 193 static struct tst_test test = { 194 .needs_root = 1, 195 .needs_tmpdir = 1, 196 .options = options, 197 .tcnt = ARRAY_SIZE(tcases), 198 .test = verify_hugeshmat, 199 .setup = setup, 200 .cleanup = cleanup, 201 }; 202