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