Home | History | Annotate | Download | only in swapon
      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