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
main(int argc,char ** argv)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 */
setup(void)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 */
cleanup(void)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 */
sighandler(int sig)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