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