• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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