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 <fcntl.h>
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <memory.h>
33 #include <sys/mman.h>
34 #include <sys/wait.h>
35 #include <limits.h>
36 #include <getopt.h>
37 
38 #include "test.h"
39 #include "safe_macros.h"
40 
41 #define NUM_CHILDREN 1000
42 
43 static void setup(void);
44 static void cleanup(void);
45 static void usage(void);
46 static int debug = 0;
47 
48 char *TCID = "dio_sparse";
49 int TST_TOTAL = 1;
50 
51 #include "common_sparse.h"
52 
53 /*
54  * Write zeroes using O_DIRECT into sparse file.
55  */
dio_sparse(char * filename,int align,int writesize,int filesize)56 int dio_sparse(char *filename, int align, int writesize, int filesize)
57 {
58 	int fd;
59 	void *bufptr;
60 	int i, w;
61 
62 	fd = open(filename, O_DIRECT | O_WRONLY | O_CREAT | O_EXCL, 0600);
63 
64 	if (fd < 0) {
65 		tst_resm(TBROK | TERRNO, "open()");
66 		return 1;
67 	}
68 
69 	SAFE_FTRUNCATE(cleanup, fd, filesize);
70 
71 	if (posix_memalign(&bufptr, align, writesize)) {
72 		close(fd);
73 		tst_resm(TBROK | TERRNO, "posix_memalign()");
74 		return 1;
75 	}
76 
77 	memset(bufptr, 0, writesize);
78 	for (i = 0; i < filesize;) {
79 		if ((w = write(fd, bufptr, writesize)) != writesize) {
80 			tst_resm(TBROK | TERRNO, "write() returned %d", w);
81 			close(fd);
82 			return 1;
83 		}
84 
85 		i += w;
86 	}
87 
88 	close(fd);
89 	unlink(filename);
90 
91 	return 0;
92 }
93 
usage(void)94 void usage(void)
95 {
96 	fprintf(stderr, "usage: dio_sparse [-d] [-n children] [-s filesize]"
97 		" [-w writesize]\n");
98 	exit(1);
99 }
100 
main(int argc,char ** argv)101 int main(int argc, char **argv)
102 {
103 	char *filename = "dio_sparse";
104 	int pid[NUM_CHILDREN];
105 	int num_children = 1;
106 	int i;
107 	long alignment = 512;
108 	int writesize = 65536;
109 	int filesize = 100 * 1024 * 1024;
110 	int c;
111 	int children_errors = 0;
112 	int ret;
113 
114 	while ((c = getopt(argc, argv, "dw:n:a:s:")) != -1) {
115 		char *endp;
116 		switch (c) {
117 		case 'd':
118 			debug++;
119 			break;
120 		case 'a':
121 			alignment = strtol(optarg, &endp, 0);
122 			alignment = scale_by_kmg(alignment, *endp);
123 			break;
124 		case 'w':
125 			writesize = strtol(optarg, &endp, 0);
126 			writesize = scale_by_kmg(writesize, *endp);
127 			break;
128 		case 's':
129 			filesize = strtol(optarg, &endp, 0);
130 			filesize = scale_by_kmg(filesize, *endp);
131 			break;
132 		case 'n':
133 			num_children = atoi(optarg);
134 			if (num_children > NUM_CHILDREN) {
135 				fprintf(stderr,
136 					"number of children limited to %d\n",
137 					NUM_CHILDREN);
138 				num_children = NUM_CHILDREN;
139 			}
140 			break;
141 		case '?':
142 			usage();
143 			break;
144 		}
145 	}
146 
147 	setup();
148 	tst_resm(TINFO, "Dirtying free blocks");
149 	dirty_freeblocks(filesize);
150 
151 	tst_resm(TINFO, "Starting I/O tests");
152 	signal(SIGTERM, SIG_DFL);
153 	for (i = 0; i < num_children; i++) {
154 		switch (pid[i] = fork()) {
155 		case 0:
156 			read_sparse(filename, filesize);
157 			break;
158 		case -1:
159 			while (i-- > 0)
160 				kill(pid[i], SIGTERM);
161 
162 			tst_brkm(TBROK | TERRNO, cleanup, "fork()");
163 		default:
164 			continue;
165 		}
166 	}
167 	tst_sig(FORK, DEF_HANDLER, cleanup);
168 
169 	ret = dio_sparse(filename, alignment, writesize, filesize);
170 
171 	tst_resm(TINFO, "Killing childrens(s)");
172 
173 	for (i = 0; i < num_children; i++)
174 		kill(pid[i], SIGTERM);
175 
176 	for (i = 0; i < num_children; i++) {
177 		int status;
178 		pid_t p;
179 
180 		p = waitpid(pid[i], &status, 0);
181 		if (p < 0) {
182 			tst_resm(TBROK | TERRNO, "waitpid()");
183 		} else {
184 			if (WIFEXITED(status) && WEXITSTATUS(status) == 10)
185 				children_errors++;
186 		}
187 	}
188 
189 	if (children_errors)
190 		tst_resm(TFAIL, "%i children(s) exited abnormally",
191 			 children_errors);
192 
193 	if (!children_errors && !ret)
194 		tst_resm(TPASS, "Test passed");
195 
196 	cleanup();
197 	tst_exit();
198 }
199 
setup(void)200 static void setup(void)
201 {
202 	tst_sig(FORK, DEF_HANDLER, cleanup);
203 	tst_tmpdir();
204 }
205 
cleanup(void)206 static void cleanup(void)
207 {
208 	tst_rmdir();
209 }
210