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