1 /*
2  *   Copyright (c) 2004 Daniel McNeil <daniel@osdl.org>
3  *                 2004 Open Source Development Lab
4  *
5  *   Copyright (c) 2004 Marty Ridgeway <mridge@us.ibm.com>
6  *
7  *   Copyright (c) 2011 Cyril Hrubis <chrubis@suse.cz>
8  *
9  *   This program is free software;  you can redistribute it and/or modify
10  *   it under the terms of the GNU General Public License as published by
11  *   the Free Software Foundation; either version 2 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This program is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17  *   the GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with this program;  if not, write to the Free Software
21  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23 
24 #define _GNU_SOURCE
25 
26 #include <stdlib.h>
27 #include <sys/types.h>
28 #include <signal.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <memory.h>
34 #include <sys/mman.h>
35 #include <sys/wait.h>
36 #include <limits.h>
37 #include <getopt.h>
38 
39 #include "test.h"
40 #include "safe_macros.h"
41 
42 #define NUM_CHILDREN 1000
43 
44 static void setup(void);
45 static void cleanup(void);
46 static void usage(void);
47 static int debug = 0;
48 static int fd;
49 
50 char *TCID = "dio_sparse";
51 int TST_TOTAL = 1;
52 
53 #include "common_sparse.h"
54 
55 /*
56  * Write zeroes using O_DIRECT into sparse file.
57  */
dio_sparse(int fd,int align,int writesize,int filesize,int offset)58 int dio_sparse(int fd, int align, int writesize, int filesize, int offset)
59 {
60 	void *bufptr;
61 	int i, w;
62 
63 	TEST(posix_memalign(&bufptr, align, writesize));
64 	if (TEST_RETURN) {
65 		tst_resm(TBROK | TRERRNO, "cannot allocate aligned memory");
66 		return 1;
67 	}
68 
69 	memset(bufptr, 0, writesize);
70 	lseek(fd, offset, SEEK_SET);
71 	for (i = offset; i < filesize;) {
72 		if ((w = write(fd, bufptr, writesize)) != writesize) {
73 			tst_resm(TBROK | TERRNO, "write() returned %d", w);
74 			return 1;
75 		}
76 
77 		i += w;
78 	}
79 
80 	return 0;
81 }
82 
usage(void)83 void usage(void)
84 {
85 	fprintf(stderr, "usage: dio_sparse [-d] [-n children] [-s filesize]"
86 		" [-w writesize] [-o offset]]\n");
87 	exit(1);
88 }
89 
main(int argc,char ** argv)90 int main(int argc, char **argv)
91 {
92 	char *filename = "dio_sparse";
93 	int pid[NUM_CHILDREN];
94 	int num_children = 1;
95 	int i;
96 	long alignment = 512;
97 	int writesize = 65536;
98 	int filesize = 100 * 1024 * 1024;
99 	int offset = 0;
100 	int c;
101 	int children_errors = 0;
102 	int ret;
103 
104 	while ((c = getopt(argc, argv, "dw:n:a:s:o:")) != -1) {
105 		char *endp;
106 		switch (c) {
107 		case 'd':
108 			debug++;
109 			break;
110 		case 'a':
111 			alignment = strtol(optarg, &endp, 0);
112 			alignment = scale_by_kmg(alignment, *endp);
113 			break;
114 		case 'w':
115 			writesize = strtol(optarg, &endp, 0);
116 			writesize = scale_by_kmg(writesize, *endp);
117 			break;
118 		case 's':
119 			filesize = strtol(optarg, &endp, 0);
120 			filesize = scale_by_kmg(filesize, *endp);
121 			break;
122 		case 'o':
123 			offset = strtol(optarg, &endp, 0);
124 			offset = scale_by_kmg(offset, *endp);
125 			break;
126 		case 'n':
127 			num_children = atoi(optarg);
128 			if (num_children > NUM_CHILDREN) {
129 				fprintf(stderr,
130 					"number of children limited to %d\n",
131 					NUM_CHILDREN);
132 				num_children = NUM_CHILDREN;
133 			}
134 			break;
135 		case '?':
136 			usage();
137 			break;
138 		}
139 	}
140 
141 	setup();
142 	tst_resm(TINFO, "Dirtying free blocks");
143 	dirty_freeblocks(filesize);
144 
145 	fd = SAFE_OPEN(cleanup, filename,
146 		O_DIRECT | O_WRONLY | O_CREAT | O_EXCL, 0600);
147 	SAFE_FTRUNCATE(cleanup, fd, filesize);
148 
149 	tst_resm(TINFO, "Starting I/O tests");
150 	signal(SIGTERM, SIG_DFL);
151 	for (i = 0; i < num_children; i++) {
152 		switch (pid[i] = fork()) {
153 		case 0:
154 			SAFE_CLOSE(NULL, fd);
155 			read_sparse(filename, filesize);
156 			break;
157 		case -1:
158 			while (i-- > 0)
159 				kill(pid[i], SIGTERM);
160 
161 			tst_brkm(TBROK | TERRNO, cleanup, "fork()");
162 		default:
163 			continue;
164 		}
165 	}
166 	tst_sig(FORK, DEF_HANDLER, cleanup);
167 
168 	ret = dio_sparse(fd, alignment, writesize, filesize, offset);
169 
170 	tst_resm(TINFO, "Killing childrens(s)");
171 
172 	for (i = 0; i < num_children; i++)
173 		kill(pid[i], SIGTERM);
174 
175 	for (i = 0; i < num_children; i++) {
176 		int status;
177 		pid_t p;
178 
179 		p = waitpid(pid[i], &status, 0);
180 		if (p < 0) {
181 			tst_resm(TBROK | TERRNO, "waitpid()");
182 		} else {
183 			if (WIFEXITED(status) && WEXITSTATUS(status) == 10)
184 				children_errors++;
185 		}
186 	}
187 
188 	if (children_errors)
189 		tst_resm(TFAIL, "%i children(s) exited abnormally",
190 			 children_errors);
191 
192 	if (!children_errors && !ret)
193 		tst_resm(TPASS, "Test passed");
194 
195 	cleanup();
196 	tst_exit();
197 }
198 
setup(void)199 static void setup(void)
200 {
201 	tst_sig(FORK, DEF_HANDLER, cleanup);
202 	tst_tmpdir();
203 }
204 
cleanup(void)205 static void cleanup(void)
206 {
207 	if (fd > 0 && close(fd))
208 		tst_resm(TWARN | TERRNO, "Failed to close file");
209 
210 	tst_rmdir();
211 }
212