Imported Upstream version 20081219
[ltp-debian.git] / testcases / kernel / io / ltp-aiodio / dio_sparse.c
blobfe51b15512685cc65077068c1b3c8c2009a90781
2 /*
3 * Copyright (c) 2004 Daniel McNeil <daniel@osdl.org>
4 * 2004 Open Source Development Lab
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * Module: .c
23 * Change History:
25 * 2/2004 Marty Ridgeway (mridge@us.ibm.com) Changes to adapt to LTP
28 #define _GNU_SOURCE
30 #include <stdlib.h>
31 #include <sys/types.h>
32 #include <signal.h>
33 #include <fcntl.h>
34 #include <stdio.h>
35 #include <unistd.h>
36 #include <memory.h>
37 #include <sys/mman.h>
38 #include <sys/wait.h>
40 #include "test.h"
42 #define NUM_CHILDREN 1000
44 int debug;
46 const char* filename1=NULL;
47 const char* filename2=NULL;
49 static void setup(void);
50 static void cleanup(void);
52 #define barrier() __asm__ __volatile__("": : :"memory")
53 #define WITH_SIGNALS_BLOCKED(code) { \
54 sigset_t held_sigs_; \
55 sigfillset(&held_sigs_); \
56 sigprocmask(SIG_SETMASK, &held_sigs_, &held_sigs_); \
57 barrier(); \
58 code; \
59 barrier(); \
60 sigprocmask(SIG_SETMASK, &held_sigs_, NULL); \
63 char *TCID="dio_sparse"; /* Test program identifier. */
64 int TST_TOTAL=1; /* Total number of test cases. */
66 * dio_sparse - issue O_DIRECT writes to holes is a file while concurrently
67 * reading the file and checking that the read never reads uninitailized
68 * data.
71 char *check_zero(unsigned char *buf, int size)
73 unsigned char *p;
75 p = buf;
77 while (size > 0) {
78 if (*buf != 0) {
79 fprintf(stderr, "non zero buffer at buf[%d] => 0x%02x,%02x,%02x,%02x\n",
80 buf - p, (unsigned int)buf[0],
81 size > 1 ? (unsigned int)buf[1] : 0,
82 size > 2 ? (unsigned int)buf[2] : 0,
83 size > 3 ? (unsigned int)buf[3] : 0);
84 return buf;
86 buf++;
87 size--;
89 return 0; /* all zeros */
92 int read_sparse(char *filename, int filesize)
94 int fd;
95 int i;
96 int j;
97 int r;
98 char buf[4096];
100 while ((fd = open(filename, O_RDONLY)) < 0) {
101 sleep(1); /* wait for file to be created */
104 for (i = 0 ; i < 100000000; i++) {
105 off_t offset = 0;
106 char *badbuf;
108 if (debug > 1 && (i % 10) == 0) {
109 fprintf(stderr, "child %d, read loop count %d\n",
110 getpid(), i);
112 lseek(fd, SEEK_SET, 0);
113 for (j = 0; j < filesize+1; j += sizeof(buf)) {
114 r = read(fd, buf, sizeof(buf));
115 if (r > 0) {
116 if ((badbuf = check_zero(buf, r))) {
117 fprintf(stderr, "non-zero read at offset %d\n",
118 offset + badbuf - buf);
119 kill(getppid(), SIGTERM);
120 exit(10);
123 offset += r;
126 return 0;
129 volatile int got_signal;
131 void
132 sig_term_func(int i, siginfo_t *si, void *p)
134 if (debug)
135 fprintf(stderr, "sig(%d, %p, %p)\n", i, si, p);
136 got_signal++;
140 * do DIO writes to a sparse file
142 void dio_sparse(char *filename, int align, int writesize, int filesize)
144 int fd;
145 void *bufptr;
146 int i;
147 int w;
148 static struct sigaction s;
150 s.sa_sigaction = sig_term_func;
151 s.sa_flags = SA_SIGINFO;
152 sigaction(SIGTERM, &s, 0);
154 WITH_SIGNALS_BLOCKED(
155 fd = open(filename, O_DIRECT|O_WRONLY|O_CREAT|O_EXCL, 0600);
156 if(fd >= 0)
157 filename1 = filename;
160 if (fd < 0) {
161 perror("cannot create file");
162 return;
165 ftruncate(fd, filesize);
167 if (posix_memalign(&bufptr, align, writesize)) {
168 perror("cannot malloc aligned memory");
169 close(fd);
170 WITH_SIGNALS_BLOCKED(
171 filename1=NULL;
172 unlink(filename);
174 return;
177 memset(bufptr, 0, writesize);
178 for (i = 0; i < filesize; ) {
179 if (debug > 1 && ((i % writesize) % 100)) {
180 fprintf(stderr, "DIO write # %d\n", i);
182 if ((w = write(fd, bufptr, writesize)) != writesize) {
183 fprintf(stderr, "write %d returned %d\n", i, w);
184 break;
186 i += w;
187 if (got_signal) {
188 if (debug)
189 fprintf(stderr, "signal -- stop at %d\n", i);
190 break;
193 if (debug)
194 fprintf(stderr, "DIO write done unlinking file\n");
195 close(fd);
196 WITH_SIGNALS_BLOCKED(
197 filename1=NULL;
198 unlink(filename);
203 void dirty_freeblocks(int size)
205 int fd;
206 void *p;
207 int pg;
208 char filename[1024];
210 pg = getpagesize();
211 size = ((size + pg - 1) / pg) * pg;
212 sprintf(filename, "file.xx.%d", getpid());
214 WITH_SIGNALS_BLOCKED(
215 fd = open(filename, O_CREAT|O_RDWR|O_EXCL, 0600);
216 if(fd >= 0)
217 filename2=filename;
219 if (fd < 0) {
220 perror("cannot open file");
221 exit(2);
223 ftruncate(fd, size);
224 p = mmap(0, size, PROT_WRITE|PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
225 if (p == MAP_FAILED) {
226 perror("cannot mmap");
227 close(fd);
228 WITH_SIGNALS_BLOCKED(
229 filename2=NULL;
230 unlink(filename);
232 exit(2);
234 memset(p, 0xaa, size);
235 msync(p, size, MS_SYNC);
236 munmap(p, size);
237 close(fd);
238 WITH_SIGNALS_BLOCKED(
239 filename2=NULL;
240 unlink(filename);
244 int usage()
246 fprintf(stderr, "usage: dio_sparse [-n children] [-s filesize]"
247 " [-w writesize] [-r readsize] \n");
248 exit(1);
252 * Scale value by kilo, mega, or giga.
254 long long scale_by_kmg(long long value, char scale)
256 switch (scale) {
257 case 'g':
258 case 'G':
259 value *= 1024;
260 case 'm':
261 case 'M':
262 value *= 1024;
263 case 'k':
264 case 'K':
265 value *= 1024;
266 break;
267 case '\0':
268 break;
269 default:
270 usage();
271 break;
273 return value;
277 * usage: dio_sparse [-r readsize] [-w writesize] [-n chilren] [-a align]
280 int main(int argc, char **argv)
282 int pid[NUM_CHILDREN];
283 int num_children = 1;
284 int i;
285 char *filename = "/test/aiodio/file";
286 long alignment = 512;
287 int readsize = 65536;
288 int writesize = 65536;
289 int filesize = 100*1024*1024;
290 int c;
291 int children_errors = 0;
292 extern char *optarg;
293 extern int optind, optopt, opterr;
295 while ((c = getopt(argc, argv, "dr:w:n:a:s:")) != -1) {
296 char *endp;
297 switch (c) {
298 case 'd':
299 debug++;
300 break;
301 case 'a':
302 alignment = strtol(optarg, &endp, 0);
303 alignment = (int)scale_by_kmg((long long)alignment,
304 *endp);
305 break;
306 case 'r':
307 readsize = strtol(optarg, &endp, 0);
308 readsize = (int)scale_by_kmg((long long)readsize, *endp);
309 break;
310 case 'w':
311 writesize = strtol(optarg, &endp, 0);
312 writesize = (int)scale_by_kmg((long long)writesize, *endp);
313 break;
314 case 's':
315 filesize = strtol(optarg, &endp, 0);
316 filesize = (int)scale_by_kmg((long long)filesize, *endp);
317 break;
318 case 'n':
319 num_children = atoi(optarg);
320 if (num_children > NUM_CHILDREN) {
321 fprintf(stderr,
322 "number of children limited to %d\n",
323 NUM_CHILDREN);
324 num_children = NUM_CHILDREN;
326 break;
327 case '?':
328 usage();
329 break;
333 setup();
335 * Create some dirty free blocks by allocating, writing, syncing,
336 * and then unlinking and freeing.
338 dirty_freeblocks(filesize);
340 for (i = 0; i < num_children; i++) {
341 if ((pid[i] = fork()) == 0) {
342 /* child */
343 return read_sparse(filename, filesize);
344 } else if (pid[i] < 0) {
345 /* error */
346 perror("fork error");
347 break;
348 } else {
349 /* Parent */
350 continue;
355 * Parent write to a hole in a file using direct i/o
358 dio_sparse(filename, alignment, writesize, filesize);
360 if (debug)
361 fprintf(stderr, "dio_sparse done writing, kill children\n");
362 for (i = 0; i < num_children; i++) {
363 kill(pid[i], SIGTERM);
366 for (i = 0; i < num_children; i++) {
367 int status;
368 pid_t p;
370 p = waitpid(pid[i], &status, 0);
371 if (p < 0) {
372 perror("waitpid");
373 } else {
374 if (WIFEXITED(status) && WEXITSTATUS(status) == 10) {
375 children_errors++;
376 if (debug) {
377 fprintf(stderr, "child %d bad exit\n", p);
382 if (debug)
383 fprintf(stderr, "dio_sparse %d children had errors\n",
384 children_errors);
385 if (children_errors)
386 exit(10);
387 return 0;
390 static void setup(void)
392 tst_sig(FORK, DEF_HANDLER, cleanup);
393 signal(SIGTERM, SIG_DFL);
396 static void cleanup(void)
398 if(filename1)
399 unlink(filename1);
400 if(filename2)
401 unlink(filename2);