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