1 /****************************************************************************** 2 * 3 * Copyright (c) International Business Machines Corp., 2007 4 * Created by <rsalveti (at) linux.vnet.ibm.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 14 * the GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * 20 ******************************************************************************/ 21 22 /* 23 * This test case checks whether swapon(2) system call returns: 24 * - EPERM when there are more than MAX_SWAPFILES already in use. 25 * 26 */ 27 28 #include <sys/types.h> 29 #include <unistd.h> 30 #include <errno.h> 31 #include <stdlib.h> 32 #include <sys/wait.h> 33 #include <sys/stat.h> 34 #include <sys/utsname.h> 35 #include <fcntl.h> 36 #include <pwd.h> 37 #include <string.h> 38 #include <signal.h> 39 #include "test.h" 40 #include "lapi/syscalls.h" 41 #include "swaponoff.h" 42 #include "libswapon.h" 43 44 static void setup(void); 45 static void cleanup(void); 46 static int setup_swap(void); 47 static int clean_swap(void); 48 static int check_and_swapoff(const char *filename); 49 50 char *TCID = "swapon03"; 51 int TST_TOTAL = 1; 52 53 static int swapfiles; 54 55 static long fs_type; 56 57 int testfiles = 3; 58 static struct swap_testfile_t { 59 char *filename; 60 } swap_testfiles[] = { 61 {"firstswapfile"}, 62 {"secondswapfile"}, 63 {"thirdswapfile"} 64 }; 65 66 int expected_errno = EPERM; 67 68 int main(int ac, char **av) 69 { 70 int lc; 71 72 tst_parse_opts(ac, av, NULL, NULL); 73 74 setup(); 75 76 for (lc = 0; TEST_LOOPING(lc); lc++) { 77 tst_count = 0; 78 79 if (setup_swap() < 0) { 80 clean_swap(); 81 tst_brkm(TBROK, cleanup, 82 "Setup failed, quitting the test"); 83 } 84 85 TEST(ltp_syscall(__NR_swapon, swap_testfiles[0].filename, 0)); 86 87 if ((TEST_RETURN == -1) && (TEST_ERRNO == expected_errno)) { 88 tst_resm(TPASS, "swapon(2) got expected failure (%d),", 89 expected_errno); 90 } else if (TEST_RETURN < 0) { 91 tst_resm(TFAIL | TTERRNO, 92 "swapon(2) failed to produce expected error " 93 "(%d). System reboot recommended.", 94 expected_errno); 95 } else { 96 /* Probably the system supports MAX_SWAPFILES > 30, 97 * let's try with MAX_SWAPFILES == 32 */ 98 99 /* Call swapon sys call once again for 32 100 * now we can't receive an error */ 101 TEST(ltp_syscall 102 (__NR_swapon, swap_testfiles[1].filename, 0)); 103 104 /* Check return code (now we're expecting success) */ 105 if (TEST_RETURN < 0) { 106 tst_resm(TFAIL | TTERRNO, 107 "swapon(2) got an unexpected failure"); 108 } else { 109 /* Call swapon sys call once again for 33 110 * now we have to receive an error */ 111 TEST(ltp_syscall 112 (__NR_swapon, swap_testfiles[2].filename, 113 0)); 114 115 /* Check return code (should be an error) */ 116 if ((TEST_RETURN == -1) 117 && (TEST_ERRNO == expected_errno)) { 118 tst_resm(TPASS, 119 "swapon(2) got expected failure;" 120 " Got errno = %d, probably your" 121 " MAX_SWAPFILES is 32", 122 expected_errno); 123 } else { 124 tst_resm(TFAIL, 125 "swapon(2) failed to produce" 126 " expected error: %d, got %s." 127 " System reboot after execution of LTP" 128 " test suite is recommended.", 129 expected_errno, 130 strerror(TEST_ERRNO)); 131 } 132 133 } 134 } 135 136 if (clean_swap() < 0) 137 tst_brkm(TBROK, cleanup, 138 "Cleanup failed, quitting the test"); 139 140 } 141 142 cleanup(); 143 tst_exit(); 144 145 } 146 147 /* 148 * Create 33 and activate 30 swapfiles. 149 */ 150 static int setup_swap(void) 151 { 152 pid_t pid; 153 int j, fd; 154 int status; 155 int res = 0; 156 char filename[15]; 157 char buf[BUFSIZ + 1]; 158 159 /* Find out how many swapfiles (1 line per entry) already exist */ 160 swapfiles = 0; 161 162 if (seteuid(0) < 0) { 163 tst_brkm(TFAIL | TERRNO, cleanup, "Failed to call seteuid"); 164 } 165 166 /* This includes the first (header) line */ 167 if ((fd = open("/proc/swaps", O_RDONLY)) == -1) { 168 tst_brkm(TFAIL | TERRNO, cleanup, 169 "Failed to find out existing number of swap files"); 170 } 171 do { 172 char *p = buf; 173 res = read(fd, buf, BUFSIZ); 174 if (res < 0) { 175 tst_brkm(TFAIL | TERRNO, cleanup, 176 "Failed to find out existing number of swap " 177 "files"); 178 } 179 buf[res] = '\0'; 180 while ((p = strchr(p, '\n'))) { 181 p++; 182 swapfiles++; 183 } 184 } while (BUFSIZ <= res); 185 close(fd); 186 if (swapfiles) 187 swapfiles--; /* don't count the /proc/swaps header */ 188 189 if (swapfiles < 0) { 190 tst_brkm(TFAIL, cleanup, 191 "Failed to find existing number of swapfiles"); 192 } 193 194 /* Determine how many more files are to be created */ 195 swapfiles = MAX_SWAPFILES - swapfiles; 196 if (swapfiles > MAX_SWAPFILES) { 197 swapfiles = MAX_SWAPFILES; 198 } 199 200 pid = FORK_OR_VFORK(); 201 if (pid == 0) { 202 /*create and turn on remaining swapfiles */ 203 for (j = 0; j < swapfiles; j++) { 204 205 /* prepare filename for the iteration */ 206 if (sprintf(filename, "swapfile%02d", j + 2) < 0) { 207 printf("sprintf() failed to create " 208 "filename"); 209 exit(1); 210 } 211 212 /* Create the swapfile */ 213 make_swapfile(cleanup, filename); 214 215 /* turn on the swap file */ 216 res = ltp_syscall(__NR_swapon, filename, 0); 217 if (res != 0) { 218 if (fs_type == TST_BTRFS_MAGIC && errno == EINVAL) 219 exit(2); 220 221 if (errno == EPERM) { 222 printf("Successfully created %d " 223 "swapfiles\n", j); 224 break; 225 } else { 226 printf("Failed to create " 227 "swapfile: %s\n", filename); 228 exit(1); 229 } 230 } 231 } 232 exit(0); 233 } else 234 waitpid(pid, &status, 0); 235 236 switch (WEXITSTATUS(status)) { 237 case 0: 238 break; 239 case 2: 240 tst_brkm(TCONF, cleanup, "Swapfile on BTRFS not implemeted"); 241 break; 242 default: 243 tst_brkm(TFAIL, cleanup, "Failed to setup swaps"); 244 break; 245 } 246 247 /* Create all needed extra swapfiles for testing */ 248 for (j = 0; j < testfiles; j++) 249 make_swapfile(cleanup, swap_testfiles[j].filename); 250 251 return 0; 252 253 } 254 255 /* 256 * Turn off all swapfiles previously turned on 257 */ 258 static int clean_swap(void) 259 { 260 int j; 261 char filename[FILENAME_MAX]; 262 263 for (j = 0; j < swapfiles; j++) { 264 if (snprintf(filename, sizeof(filename), 265 "swapfile%02d", j + 2) < 0) { 266 tst_resm(TWARN, "sprintf() failed to create filename"); 267 tst_resm(TWARN, "Failed to turn off swap files. System" 268 " reboot after execution of LTP test" 269 " suite is recommended"); 270 return -1; 271 } 272 if (check_and_swapoff(filename) != 0) { 273 tst_resm(TWARN, "Failed to turn off swap file %s.", 274 filename); 275 return -1; 276 } 277 } 278 279 for (j = 0; j < testfiles; j++) { 280 if (check_and_swapoff(swap_testfiles[j].filename) != 0) { 281 tst_resm(TWARN, "Failed to turn off swap file %s.", 282 swap_testfiles[j].filename); 283 return -1; 284 } 285 } 286 287 return 0; 288 } 289 290 /* 291 * Check if the file is at /proc/swaps and remove it giving swapoff 292 */ 293 static int check_and_swapoff(const char *filename) 294 { 295 char cmd_buffer[256]; 296 int rc = -1; 297 298 if (snprintf(cmd_buffer, sizeof(cmd_buffer), 299 "grep -q '%s.*file' /proc/swaps", filename) < 0) { 300 tst_resm(TWARN, 301 "sprintf() failed to create the command string"); 302 } else { 303 304 rc = 0; 305 306 if (system(cmd_buffer) == 0) { 307 308 /* now we need to swapoff the file */ 309 if (ltp_syscall(__NR_swapoff, filename) != 0) { 310 311 tst_resm(TWARN, "Failed to turn off swap " 312 "file. system reboot after " 313 "execution of LTP test suite " 314 "is recommended"); 315 rc = -1; 316 317 } 318 319 } 320 } 321 322 return rc; 323 } 324 325 static void setup(void) 326 { 327 tst_sig(FORK, DEF_HANDLER, cleanup); 328 329 tst_require_root(); 330 331 if (access("/proc/swaps", F_OK)) 332 tst_brkm(TCONF, NULL, "swap not supported by kernel"); 333 334 tst_tmpdir(); 335 336 switch ((fs_type = tst_fs_type(cleanup, "."))) { 337 case TST_NFS_MAGIC: 338 case TST_TMPFS_MAGIC: 339 tst_brkm(TCONF, cleanup, 340 "Cannot do swapon on a file on %s filesystem", 341 tst_fs_type_name(fs_type)); 342 break; 343 } 344 345 TEST_PAUSE; 346 } 347 348 static void cleanup(void) 349 { 350 clean_swap(); 351 352 tst_rmdir(); 353 } 354