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
main(int argc,char ** argv)77 int main(int argc, char **argv)
78 {
79 int lc;
80
81 tst_parse_opts(argc, argv, NULL, NULL);
82
83 setup(); /* set "tstdir", and "testfile" vars */
84
85 /* The following loop checks looping state if -i option given */
86 for (lc = 0; TEST_LOOPING(lc); lc++) {
87
88 /* reset tst_count in case we are looping */
89 tst_count = 0;
90
91 fd[1] = -1; /* Invalid file descriptor */
92
93 if (signal(SIGTERM, sighandler) == SIG_ERR) {
94 perror("signal");
95 tst_resm(TFAIL, "signal() SIGTERM FAILED");
96 cleanup();
97
98 }
99
100 if (signal(SIGPIPE, sighandler) == SIG_ERR) {
101 perror("signal");
102 tst_resm(TFAIL, "signal() SIGPIPE FAILED");
103 cleanup();
104
105 }
106
107 if ((fd[0] = open(f_name, O_WRONLY | O_CREAT, 0666)) < 0) {
108 tst_resm(TFAIL, "open(2) failed: fname = %s, "
109 "errno = %d", f_name, errno);
110 cleanup();
111
112 }
113
114 /*
115 * Iovecs passed to writev points to valid (readable) regions,
116 * so all bytes must be successfully written.
117 */
118 TEST(writev(fd[0], wr_iovec, 2));
119 if (TEST_RETURN >= 0) {
120 if (TEST_RETURN == 2) {
121 tst_resm(TPASS,
122 "writev returned %d as expected", 2);
123 } else {
124 tst_resm(TFAIL, "Expected nbytes = %d, got "
125 "%ld", 2, TEST_RETURN);
126 }
127 } else {
128 tst_resm(TFAIL | TTERRNO,
129 "Error writev return value = %ld",
130 TEST_RETURN);
131 }
132 }
133 cleanup();
134 tst_exit();
135
136 }
137
138 /*
139 * setup()
140 * performs all ONE TIME setup for this test
141 */
setup(void)142 void setup(void)
143 {
144
145 tst_sig(FORK, DEF_HANDLER, cleanup);
146
147 /* Pause if that option was specified.
148 * TEST_PAUSE contains the code to fork the test with the -i option.
149 * You want to make sure you do this before you create your temporary
150 * directory.
151 */
152 TEST_PAUSE;
153
154 /* Create a unique temporary directory and chdir() to it. */
155 tst_tmpdir();
156
157 strcpy(name, DATA_FILE);
158 sprintf(f_name, "%s.%d", name, getpid());
159
160 page_size = getpagesize();
161
162 /* Crate two readable and writeble mappings with non reabable
163 * mapping around */
164 bad_addr[0] = mmap(NULL, page_size * 3, PROT_NONE,
165 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
166 if (bad_addr[0] == MAP_FAILED)
167 tst_brkm(TBROK, cleanup, "mmap failed for bad_addr[0]");
168
169 good_addr[0] = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
170 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
171 if (good_addr[0] == MAP_FAILED)
172 tst_brkm(TBROK, cleanup, "mmap failed for good_addr[0]");
173
174 bad_addr[1] = mmap(NULL, page_size * 3, PROT_NONE,
175 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
176 if (bad_addr[1] == MAP_FAILED)
177 tst_brkm(TBROK, cleanup, "mmap failed for bad_addr[1]");
178
179 good_addr[1] = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
180 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
181 if (good_addr[1] == MAP_FAILED)
182 tst_brkm(TBROK, cleanup, "mmap failed for good_addr[1]");
183
184 /* force page fault for writable mappings */
185 memset(good_addr[0], 'a', page_size);
186 memset(good_addr[1], 'b', page_size);
187
188 wr_iovec[0].iov_base = good_addr[0] + page_size - 1;
189 wr_iovec[1].iov_base = good_addr[1] + page_size - 1;
190
191 }
192
193 /*
194 * cleanup()
195 * performs all ONE TIME cleanup for this test at
196 * completion or premature exit
197 */
cleanup(void)198 void cleanup(void)
199 {
200
201 close(fd[0]);
202
203 if (unlink(f_name) < 0) {
204 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
205 f_name, errno);
206 }
207 tst_rmdir();
208
209 }
210
211 /*
212 * sighandler()
213 * Signal handler for SIGTERM and SIGPIPE
214 */
sighandler(int sig)215 void sighandler(int sig)
216 {
217 switch (sig) {
218 case SIGTERM:
219 break;
220 case SIGPIPE:
221 ++in_sighandler;
222 return;
223 default:
224 tst_resm(TFAIL, "sighandler() received invalid signal "
225 ": %d", sig);
226 break;
227 }
228
229 if ((unlink(f_name) < 0) && (errno != ENOENT)) {
230 tst_resm(TFAIL, "unlink Failed--file = %s, errno = %d",
231 f_name, errno);
232 cleanup();
233
234 }
235 exit(sig);
236 }
237