• 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 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