Home | History | Annotate | Download | only in writev
      1 /*
      2  * Copyright (C) 2007  Monakhov Dmitriy
      3  *
      4  * This program is free software;  you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License as published by
      6  * the Free Software Foundation; either version 2 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     12  * the GNU General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program;  if not, write to the Free Software
     16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     17  */
     18 
     19 /*
     20  * NAME
     21  *	writev06.c
     22  *
     23  * DESCRIPTION
     24  *	These testcases are written to test fault in pages readable
     25  *	feature in generic write path. Because before actual write
     26  *	kernel may want check is buffer passed is realy readable.
     27  *
     28  * USAGE:  <for command-line>
     29  *      writev06 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
     30  *      where,  -c n : Run n copies concurrently.
     31  *              -e   : Turn on errno logging.
     32  *              -i n : Execute test n times.
     33  *              -I x : Execute test for x seconds.
     34  *              -P x : Pause for x seconds between iterations.
     35  *              -t   : Turn on syscall timing.
     36  *
     37  * History
     38  *
     39  * Restrictions
     40  *	NONE
     41  */
     42 
     43 #include <sys/types.h>
     44 #include <signal.h>
     45 #include <sys/uio.h>
     46 #include <fcntl.h>
     47 #include <memory.h>
     48 #include <errno.h>
     49 #include "test.h"
     50 #include <sys/mman.h>
     51 
     52 #define	K_1	1024
     53 #define	NBUFS		2
     54 #define	MAX_IOVEC	2
     55 #define	DATA_FILE	"writev_data_file"
     56 
     57 int page_size;
     58 
     59 char *good_addr[2] = { NULL, NULL };
     60 char *bad_addr[2] = { NULL, NULL };
     61 
     62 struct iovec wr_iovec[MAX_IOVEC] = {
     63 	{(caddr_t) - 1, 1},
     64 	{(caddr_t) - 1, 1}
     65 };
     66 
     67 char name[K_1], f_name[K_1];
     68 int fd[2], in_sighandler;
     69 
     70 char *TCID = "writev06";
     71 int TST_TOTAL = 1;
     72 
     73 void sighandler(int);
     74 void setup(void);
     75 void cleanup(void);
     76 int fail;
     77 
     78 int main(int argc, char **argv)
     79 {
     80 	int lc;
     81 
     82 	tst_parse_opts(argc, argv, NULL, NULL);
     83 
     84 	setup();		/* set "tstdir", and "testfile" vars */
     85 
     86 	/* The following loop checks looping state if -i option given */
     87 	for (lc = 0; TEST_LOOPING(lc); lc++) {
     88 
     89 		/* reset tst_count in case we are looping */
     90 		tst_count = 0;
     91 
     92 		fd[1] = -1;	/* Invalid file descriptor */
     93 
     94 		if (signal(SIGTERM, sighandler) == SIG_ERR) {
     95 			perror("signal");
     96 			tst_resm(TFAIL, "signal() SIGTERM FAILED");
     97 			cleanup();
     98 
     99 		}
    100 
    101 		if (signal(SIGPIPE, sighandler) == SIG_ERR) {
    102 			perror("signal");
    103 			tst_resm(TFAIL, "signal() SIGPIPE FAILED");
    104 			cleanup();
    105 
    106 		}
    107 
    108 		if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) {
    109 			tst_resm(TFAIL, "open(2) failed: fname = %s, "
    110 				 "errno = %d", f_name, errno);
    111 			cleanup();
    112 
    113 		}
    114 
    115 		/*
    116 		 * Iovecs passed to writev points to valid (readable) regions,
    117 		 * so all bytes must be successfully written.
    118 		 */
    119 //block1:
    120 
    121 		tst_resm(TINFO, "Enter block 1");
    122 		fail = 0;
    123 
    124 		TEST(writev(fd[0], wr_iovec, 2));
    125 		if (TEST_RETURN >= 0) {
    126 			if (TEST_RETURN == 2) {
    127 				tst_resm(TINFO,
    128 					 "writev returned %d as expected", 2);
    129 			} else {
    130 				tst_resm(TFAIL, "Expected nbytes = %d, got "
    131 					 "%ld", 2, TEST_RETURN);
    132 				fail = 1;
    133 			}
    134 		} else {
    135 			tst_resm(TFAIL | TTERRNO,
    136 				 "Error writev return value = %ld",
    137 				 TEST_RETURN);
    138 			fail = 1;
    139 		}
    140 		if (fail) {
    141 			tst_resm(TINFO, "block 1 FAILED");
    142 		} else {
    143 			tst_resm(TINFO, "block 1 PASSED");
    144 		}
    145 		tst_resm(TINFO, "Exit block 1");
    146 	}
    147 	cleanup();
    148 	tst_exit();
    149 
    150 }
    151 
    152 /*
    153  * setup()
    154  *	performs all ONE TIME setup for this test
    155  */
    156 void setup(void)
    157 {
    158 
    159 	tst_sig(FORK, DEF_HANDLER, cleanup);
    160 
    161 	/* Pause if that option was specified.
    162 	 * TEST_PAUSE contains the code to fork the test with the -i option.
    163 	 * You want to make sure you do this before you create your temporary
    164 	 * directory.
    165 	 */
    166 	TEST_PAUSE;
    167 
    168 	/* Create a unique temporary directory and chdir() to it. */
    169 	tst_tmpdir();
    170 
    171 	strcpy(name, DATA_FILE);
    172 	sprintf(f_name, "%s.%d", name, getpid());
    173 
    174 	page_size = getpagesize();
    175 
    176 	/* Crate two readable and writeble mappings with non reabable
    177 	 * mapping around */
    178 	bad_addr[0] = mmap(NULL, page_size * 3, PROT_NONE,
    179 			   MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
    180 	if (bad_addr[0] == MAP_FAILED)
    181 		tst_brkm(TBROK, cleanup, "mmap failed for bad_addr[0]");
    182 
    183 	good_addr[0] = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
    184 			    MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
    185 	if (good_addr[0] == MAP_FAILED)
    186 		tst_brkm(TBROK, cleanup, "mmap failed for good_addr[0]");
    187 
    188 	bad_addr[1] = mmap(NULL, page_size * 3, PROT_NONE,
    189 			   MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
    190 	if (bad_addr[1] == MAP_FAILED)
    191 		tst_brkm(TBROK, cleanup, "mmap failed for bad_addr[1]");
    192 
    193 	good_addr[1] = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
    194 			    MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
    195 	if (good_addr[1] == MAP_FAILED)
    196 		tst_brkm(TBROK, cleanup, "mmap failed for good_addr[1]");
    197 
    198 	/* force page fault for writable mappings */
    199 	memset(good_addr[0], 'a', page_size);
    200 	memset(good_addr[1], 'b', page_size);
    201 
    202 	wr_iovec[0].iov_base = good_addr[0] + page_size - 1;
    203 	wr_iovec[1].iov_base = good_addr[1] + page_size - 1;
    204 
    205 }
    206 
    207 /*
    208  * cleanup()
    209  *	performs all ONE TIME cleanup for this test at
    210  *	completion or premature exit
    211  */
    212 void cleanup(void)
    213 {
    214 
    215 	close(fd[0]);
    216 
    217 	if (unlink(f_name) < 0) {
    218 		tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
    219 			 f_name, errno);
    220 	}
    221 	tst_rmdir();
    222 
    223 }
    224 
    225 /*
    226  * sighandler()
    227  *	Signal handler for SIGTERM and SIGPIPE
    228  */
    229 void sighandler(int sig)
    230 {
    231 	switch (sig) {
    232 	case SIGTERM:
    233 		break;
    234 	case SIGPIPE:
    235 		++in_sighandler;
    236 		return;
    237 	default:
    238 		tst_resm(TFAIL, "sighandler() received invalid signal "
    239 			 ": %d", sig);
    240 		break;
    241 	}
    242 
    243 	if ((unlink(f_name) < 0) && (errno != ENOENT)) {
    244 		tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
    245 			 f_name, errno);
    246 		cleanup();
    247 
    248 	}
    249 	exit(sig);
    250 }
    251