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
35 static size_t shm_size;
36 static int shm_id_1 = -1;
37 struct shmid_ds buf;
38 static int *shared;
39 static int pass;
40 static sigjmp_buf env;
41
42 static void check_functionality(void);
43 static void sighandler(int sig);
44
hugeshmdt_test(void)45 static 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
check_functionality(void)66 static 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
sighandler(int sig)101 static 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
setup(void)113 void 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
cleanup(void)141 void cleanup(void)
142 {
143 rm_shm(shm_id_1);
144 }
145
146 static 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 .request_hugepages = 128,
156 };
157