• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 struct tst_option options[] = {
43 	{"s:", &nr_opt, "-s num   Set the number of the been allocated hugepages"},
44 	{NULL, NULL, NULL}
45 };
46 
47 static void check_functionality(void);
48 static void sighandler(int sig);
49 
hugeshmdt_test(void)50 static void hugeshmdt_test(void)
51 {
52 	struct sigaction sa;
53 
54 	sa.sa_handler = sighandler;
55 	sigaction(SIGSEGV, &sa, NULL);
56 
57 	if (shmdt(shared) == -1)
58 		tst_res(TFAIL | TERRNO, "shmdt");
59 	else
60 		check_functionality();
61 
62 	/* reattach the shared memory segment in case we are looping */
63 	shared = shmat(shm_id_1, 0, 0);
64 	if (shared == (void *)-1)
65 		tst_brk(TBROK | TERRNO, "shmat #2: reattach");
66 
67 	/* also reset pass */
68 	pass = 0;
69 }
70 
check_functionality(void)71 static void check_functionality(void)
72 {
73 	/* stat the shared memory segment */
74 	if (shmctl(shm_id_1, IPC_STAT, &buf) == -1)
75 		tst_brk(TBROK | TERRNO, "shmctl");
76 
77 	if (buf.shm_nattch != 0) {
78 		tst_res(TFAIL, "# of attaches is incorrect");
79 		return;
80 	}
81 
82 	/*
83 	 * Try writing to the shared memory.  This should generate a
84 	 * SIGSEGV which will be caught below.
85 	 *
86 	 * This is wrapped by the sigsetjmp() call that will take care of
87 	 * restoring the program's context in an elegant way in conjunction
88 	 * with the call to siglongjmp() in the signal handler.
89 	 *
90 	 * An attempt to do the assignment without using the sigsetjmp()
91 	 * and siglongjmp() calls will result in an infinite loop.  Program
92 	 * control is returned to the assignment statement after the execution
93 	 * of the signal handler and another SIGSEGV will be generated.
94 	 */
95 
96 	if (sigsetjmp(env, 1) == 0)
97 		*shared = 2;
98 
99 	if (pass)
100 		tst_res(TPASS, "huge shared memory detached correctly");
101 	else
102 		tst_res(TFAIL, "huge shared memory was not detached "
103 			 "correctly");
104 }
105 
sighandler(int sig)106 static void sighandler(int sig)
107 {
108 	/* if we have received a SIGSEGV, we are almost done */
109 	if (sig == SIGSEGV) {
110 		/* set the global variable and jump back */
111 		pass = 1;
112 		siglongjmp(env, 1);
113 	} else {
114 		tst_brk(TBROK, "unexpected signal received: %d", sig);
115 	}
116 }
117 
setup(void)118 void setup(void)
119 {
120 	long hpage_size;
121 
122 	if (tst_hugepages == 0)
123 		tst_brk(TCONF, "No enough hugepages for testing.");
124 
125 	hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024;
126 
127 	shm_size = hpage_size * tst_hugepages / 2;
128 	update_shm_size(&shm_size);
129 	shmkey = getipckey();
130 
131 	/* create a shared memory resource with read and write permissions */
132 	shm_id_1 = shmget(shmkey, shm_size,
133 			  SHM_HUGETLB | SHM_RW | IPC_CREAT | IPC_EXCL);
134 	if (shm_id_1 == -1)
135 		tst_brk(TBROK | TERRNO, "shmget");
136 
137 	/* attach the shared memory segment */
138 	shared = shmat(shm_id_1, 0, 0);
139 	if (shared == (void *)-1)
140 		tst_brk(TBROK | TERRNO, "shmat #1");
141 
142 	/* give a value to the shared memory integer */
143 	*shared = 4;
144 }
145 
cleanup(void)146 void cleanup(void)
147 {
148 	rm_shm(shm_id_1);
149 }
150 
151 static struct tst_test test = {
152 	.needs_root = 1,
153 	.options = options,
154 	.setup = setup,
155 	.cleanup = cleanup,
156 	.test_all = hugeshmdt_test,
157 	.request_hugepages = 128,
158 };
159