1/* 2 * Copyright (c) International Business Machines Corp., 2004 3 * Copyright (c) Linux Test Project, 2004-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 * hugeshmdt01 - check that largr shared memory is detached correctly 19 * 20 * ALGORITHM 21 * create a large shared memory resource 22 * attach it to the current process and give it a value 23 * call shmdt() using the TEST macro 24 * check the return code 25 * if failure, issue a FAIL message. 26 * otherwise, 27 * if doing functionality testing 28 * attempt to write a value to the large shared memory address 29 * this should generate a SIGSEGV which will be caught in 30 * the signal handler 31 * if correct, 32 * issue a PASS message 33 * otherwise 34 * issue a FAIL message 35 * call cleanup 36 * 37 * HISTORY 38 * 03/2001 - Written by Wayne Boyer 39 * 04/2004 - Updated by Robbie Williamson 40 */ 41 42#include <setjmp.h> 43#include <limits.h> 44#include "hugetlb.h" 45#include "hugetlb.h" 46 47static size_t shm_size; 48static int shm_id_1 = -1; 49struct shmid_ds buf; 50static int *shared; 51static int pass; 52static sigjmp_buf env; 53 54static long hugepages = 128; 55static struct tst_option options[] = { 56 {"s:", &nr_opt, "-s num Set the number of the been allocated hugepages"}, 57 {NULL, NULL, NULL} 58}; 59 60static void check_functionality(void); 61static void sighandler(int sig); 62 63static void hugeshmdt_test(void) 64{ 65 struct sigaction sa; 66 67 sa.sa_handler = sighandler; 68 sigaction(SIGSEGV, &sa, NULL); 69 70 if (shmdt(shared) == -1) 71 tst_res(TFAIL | TERRNO, "shmdt"); 72 else 73 check_functionality(); 74 75 /* reattach the shared memory segment in case we are looping */ 76 shared = shmat(shm_id_1, 0, 0); 77 if (shared == (void *)-1) 78 tst_brk(TBROK | TERRNO, "shmat #2: reattach"); 79 80 /* also reset pass */ 81 pass = 0; 82} 83 84static void check_functionality(void) 85{ 86 /* stat the shared memory segment */ 87 if (shmctl(shm_id_1, IPC_STAT, &buf) == -1) 88 tst_brk(TBROK | TERRNO, "shmctl"); 89 90 if (buf.shm_nattch != 0) { 91 tst_res(TFAIL, "# of attaches is incorrect"); 92 return; 93 } 94 95 /* 96 * Try writing to the shared memory. This should generate a 97 * SIGSEGV which will be caught below. 98 * 99 * This is wrapped by the sigsetjmp() call that will take care of 100 * restoring the program's context in an elegant way in conjunction 101 * with the call to siglongjmp() in the signal handler. 102 * 103 * An attempt to do the assignment without using the sigsetjmp() 104 * and siglongjmp() calls will result in an infinite loop. Program 105 * control is returned to the assignment statement after the execution 106 * of the signal handler and another SIGSEGV will be generated. 107 */ 108 109 if (sigsetjmp(env, 1) == 0) 110 *shared = 2; 111 112 if (pass) 113 tst_res(TPASS, "huge shared memory detached correctly"); 114 else 115 tst_res(TFAIL, "huge shared memory was not detached " 116 "correctly"); 117} 118 119static void sighandler(int sig) 120{ 121 /* if we have received a SIGSEGV, we are almost done */ 122 if (sig == SIGSEGV) { 123 /* set the global variable and jump back */ 124 pass = 1; 125 siglongjmp(env, 1); 126 } else { 127 tst_brk(TBROK, "unexpected signal received: %d", sig); 128 } 129} 130 131void setup(void) 132{ 133 long hpage_size; 134 135 save_nr_hugepages(); 136 if (nr_opt) 137 hugepages = SAFE_STRTOL(nr_opt, 0, LONG_MAX); 138 139 set_sys_tune("nr_hugepages", hugepages, 1); 140 hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024; 141 142 shm_size = hpage_size * hugepages / 2; 143 update_shm_size(&shm_size); 144 shmkey = getipckey(); 145 146 /* create a shared memory resource with read and write permissions */ 147 shm_id_1 = shmget(shmkey, shm_size, 148 SHM_HUGETLB | SHM_RW | IPC_CREAT | IPC_EXCL); 149 if (shm_id_1 == -1) 150 tst_brk(TBROK | TERRNO, "shmget"); 151 152 /* attach the shared memory segment */ 153 shared = shmat(shm_id_1, 0, 0); 154 if (shared == (void *)-1) 155 tst_brk(TBROK | TERRNO, "shmat #1"); 156 157 /* give a value to the shared memory integer */ 158 *shared = 4; 159} 160 161void cleanup(void) 162{ 163 rm_shm(shm_id_1); 164 restore_nr_hugepages(); 165} 166 167static struct tst_test test = { 168 .needs_root = 1, 169 .options = options, 170 .setup = setup, 171 .cleanup = cleanup, 172 .test_all = hugeshmdt_test, 173}; 174