• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) International Business Machines Corp., 2007
4  * Created by <rsalveti@linux.vnet.ibm.com>
5  *
6  */
7 
8 /*\
9  * [Description]
10  *
11  * This test case checks whether swapon(2) system call returns:
12  *  - EPERM when there are more than MAX_SWAPFILES already in use.
13  */
14 
15 #include <stdio.h>
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <sys/wait.h>
19 
20 #include "tst_test.h"
21 #include "lapi/syscalls.h"
22 #include "swaponoff.h"
23 #include "libswap.h"
24 
25 static int setup_swap(void);
26 static int clean_swap(void);
27 static int check_and_swapoff(const char *filename);
28 
29 static int swapfiles;
30 
31 int testfiles = 3;
32 static struct swap_testfile_t {
33 	char *filename;
34 } swap_testfiles[] = {
35 	{"firstswapfile"},
36 	{"secondswapfile"},
37 	{"thirdswapfile"}
38 };
39 
40 int expected_errno = EPERM;
41 
verify_swapon(void)42 static void verify_swapon(void)
43 {
44 	if (setup_swap() < 0) {
45 		clean_swap();
46 		tst_brk(TBROK, "Setup failed, quitting the test");
47 	}
48 
49 	TEST(tst_syscall(__NR_swapon, swap_testfiles[0].filename, 0));
50 
51 	if ((TST_RET == -1) && (TST_ERR == expected_errno)) {
52 		tst_res(TPASS, "swapon(2) got expected failure (%d),",
53 			expected_errno);
54 	} else if (TST_RET < 0) {
55 		tst_res(TFAIL | TTERRNO,
56 			"swapon(2) failed to produce expected error "
57 			"(%d). System reboot recommended.",
58 			expected_errno);
59 	} else {
60 		/* Probably the system supports MAX_SWAPFILES > 30,
61 		 * let's try with MAX_SWAPFILES == 32 */
62 
63 		/* Call swapon sys call once again for 32
64 		 * now we can't receive an error */
65 		TEST(tst_syscall(__NR_swapon, swap_testfiles[1].filename, 0));
66 
67 		/* Check return code (now we're expecting success) */
68 		if (TST_RET < 0) {
69 			tst_res(TFAIL | TTERRNO,
70 				"swapon(2) got an unexpected failure");
71 		} else {
72 			/* Call swapon sys call once again for 33
73 			 * now we have to receive an error */
74 			TEST(tst_syscall(__NR_swapon, swap_testfiles[2].filename, 0));
75 
76 			/* Check return code (should be an error) */
77 			if ((TST_RET == -1) && (TST_ERR == expected_errno)) {
78 				tst_res(TPASS,
79 					"swapon(2) got expected failure;"
80 					" Got errno = %d, probably your"
81 					" MAX_SWAPFILES is 32",
82 					expected_errno);
83 			} else {
84 				tst_res(TFAIL,
85 					"swapon(2) failed to produce"
86 					" expected error: %d, got %s."
87 					" System reboot after execution of LTP"
88 					" test suite is recommended.",
89 					expected_errno, strerror(TST_ERR));
90 			}
91 		}
92 	}
93 
94 	if (clean_swap() < 0)
95 		tst_brk(TBROK, "Cleanup failed, quitting the test");
96 }
97 
98 /*
99  * Create 33 and activate 30 swapfiles.
100  */
setup_swap(void)101 static int setup_swap(void)
102 {
103 	pid_t pid;
104 	int j, fd;
105 	int status;
106 	int res = 0;
107 	char filename[FILENAME_MAX];
108 	char buf[BUFSIZ + 1];
109 
110 	/* Find out how many swapfiles (1 line per entry) already exist */
111 	swapfiles = 0;
112 
113 	if (seteuid(0) < 0)
114 		tst_brk(TFAIL | TERRNO, "Failed to call seteuid");
115 
116 	/* This includes the first (header) line */
117 	if ((fd = open("/proc/swaps", O_RDONLY)) == -1) {
118 		tst_brk(TFAIL | TERRNO,
119 			"Failed to find out existing number of swap files");
120 	}
121 	do {
122 		char *p = buf;
123 		res = read(fd, buf, BUFSIZ);
124 		if (res < 0) {
125 			tst_brk(TFAIL | TERRNO,
126 				 "Failed to find out existing number of swap files");
127 		}
128 		buf[res] = '\0';
129 		while ((p = strchr(p, '\n'))) {
130 			p++;
131 			swapfiles++;
132 		}
133 	} while (BUFSIZ <= res);
134 	close(fd);
135 	if (swapfiles)
136 		swapfiles--;	/* don't count the /proc/swaps header */
137 
138 	if (swapfiles < 0)
139 		tst_brk(TFAIL, "Failed to find existing number of swapfiles");
140 
141 	/* Determine how many more files are to be created */
142 	swapfiles = MAX_SWAPFILES - swapfiles;
143 	if (swapfiles > MAX_SWAPFILES)
144 		swapfiles = MAX_SWAPFILES;
145 	pid = SAFE_FORK();
146 	if (pid == 0) {
147 		/*create and turn on remaining swapfiles */
148 		for (j = 0; j < swapfiles; j++) {
149 
150 			/* prepare filename for the iteration */
151 			if (sprintf(filename, "swapfile%02d", j + 2) < 0) {
152 				printf("sprintf() failed to create "
153 				       "filename");
154 				exit(1);
155 			}
156 
157 			/* Create the swapfile */
158 			make_swapfile(filename, 0);
159 
160 			/* turn on the swap file */
161 			res = tst_syscall(__NR_swapon, filename, 0);
162 			if (res != 0) {
163 				if (errno == EPERM) {
164 					printf("Successfully created %d swapfiles\n", j);
165 					break;
166 				} else {
167 					printf("Failed to create swapfile: %s\n", filename);
168 					exit(1);
169 				}
170 			}
171 		}
172 		exit(0);
173 	} else
174 		waitpid(pid, &status, 0);
175 
176 	if (WEXITSTATUS(status))
177 		tst_brk(TFAIL, "Failed to setup swaps");
178 
179 	/* Create all needed extra swapfiles for testing */
180 	for (j = 0; j < testfiles; j++)
181 		make_swapfile(swap_testfiles[j].filename, 0);
182 
183 	return 0;
184 }
185 
186 /*
187  * Turn off all swapfiles previously turned on
188  */
clean_swap(void)189 static int clean_swap(void)
190 {
191 	int j;
192 	char filename[FILENAME_MAX];
193 
194 	for (j = 0; j < swapfiles; j++) {
195 		if (snprintf(filename, sizeof(filename),
196 			     "swapfile%02d", j + 2) < 0) {
197 			tst_res(TWARN, "sprintf() failed to create filename");
198 			tst_res(TWARN, "Failed to turn off swap files. System"
199 				 " reboot after execution of LTP test"
200 				 " suite is recommended");
201 			return -1;
202 		}
203 		if (check_and_swapoff(filename) != 0) {
204 			tst_res(TWARN, "Failed to turn off swap file %s.", filename);
205 			return -1;
206 		}
207 	}
208 
209 	for (j = 0; j < testfiles; j++) {
210 		if (check_and_swapoff(swap_testfiles[j].filename) != 0) {
211 			tst_res(TWARN, "Failed to turn off swap file %s.",
212 				 swap_testfiles[j].filename);
213 			return -1;
214 		}
215 	}
216 
217 	return 0;
218 }
219 
220 /*
221  * Check if the file is at /proc/swaps and remove it giving swapoff
222  */
check_and_swapoff(const char * filename)223 static int check_and_swapoff(const char *filename)
224 {
225 	char cmd_buffer[256];
226 	int rc = -1;
227 
228 	if (snprintf(cmd_buffer, sizeof(cmd_buffer),
229 		     "grep -q '%s.*file' /proc/swaps", filename) < 0) {
230 		tst_res(TWARN, "sprintf() failed to create the command string");
231 	} else {
232 
233 		rc = 0;
234 
235 		if (system(cmd_buffer) == 0) {
236 
237 			/* now we need to swapoff the file */
238 			if (tst_syscall(__NR_swapoff, filename) != 0) {
239 
240 				tst_res(TWARN, "Failed to turn off swap "
241 					 "file. system reboot after "
242 					 "execution of LTP test suite "
243 					 "is recommended");
244 				rc = -1;
245 
246 			}
247 
248 		}
249 	}
250 
251 	return rc;
252 }
253 
setup(void)254 static void setup(void)
255 {
256 	if (access("/proc/swaps", F_OK))
257 		tst_brk(TCONF, "swap not supported by kernel");
258 
259 	is_swap_supported("./tstswap");
260 }
261 
cleanup(void)262 static void cleanup(void)
263 {
264 	clean_swap();
265 }
266 
267 static struct tst_test test = {
268 	.needs_root = 1,
269 	.needs_tmpdir = 1,
270 	.forks_child = 1,
271 	.test_all = verify_swapon,
272 	.setup = setup,
273 	.cleanup = cleanup
274 };
275