replay-log: add support for replaying ops in target device sector range
[xfstests-dev.git] / src / holes.c
1 /*
2  * Copyright (c) 2000-2001 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18  
19 #include "global.h"
20
21 int verbose;            /* print lots of debugging info */
22
23 void usage(char *progname);
24 void writeblks(int fd, long filesize, int blocksize,
25                    int interleave, int base, int rev);
26 int readblks(int fd, long filesize, int blocksize,
27                   int interleave, int count);
28
29 void
30 usage(char *progname)
31 {
32         fprintf(stderr, "usage: %s [-l filesize] [-b blocksize] [-i interleave]\n"
33                         "\t\t[-c count] [-r(everse)] [-v(erbose)] filename\n",
34                         progname);
35         exit(1);
36 }
37
38 int
39 main(int argc, char *argv[])
40 {
41         int interleave, blocksize, count, rev, i, ch, fd;
42         long filesize;
43         char *filename = NULL;
44         int errs;
45
46         filesize = 1024*1024;
47         blocksize = 4096;
48         count = interleave = 4;
49         rev = verbose = 0;
50         while ((ch = getopt(argc, argv, "b:l:i:c:rv")) != EOF) {
51                 switch(ch) {
52                 case 'b':       blocksize  = atoi(optarg);      break;
53                 case 'c':       count      = atoi(optarg);      break;
54                 case 'i':       interleave = atoi(optarg);      break;
55                 case 'l':       filesize   = atol(optarg);      break;
56                 case 'v':       verbose++;                      break;
57                 case 'r':       rev++;                          break;
58                 default:        usage(argv[0]);                 break;
59                 }
60         }
61         if (optind == argc-1)
62                 filename = argv[optind];
63         else
64                 usage(argv[0]);
65         if ((filesize % (blocksize*interleave)) != 0) {
66                 filesize -= filesize % (blocksize * interleave);
67                 printf("filesize not a multiple of blocksize*interleave,\n");
68                 printf("reducing filesize to %ld\n", filesize);
69         }
70         if (count > interleave) {
71                 count = interleave;
72                 printf("count of passes is too large, setting to %d\n", count);
73         } else if (count < 1) {
74                 count = 1;
75                 printf("count of passes is too small, setting to %d\n", count);
76         }
77
78         if ((fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) {
79                 perror("open");
80                 return 1;
81         }
82
83         /*
84          * Avoid allocation patterns being perturbed by different speculative
85          * preallocation beyond EOF configurations by first truncating the file
86          * to the expected maximum file size.
87          */
88         if (ftruncate(fd, filesize) < 0) {
89                 perror("ftruncate");
90                 exit(EXIT_FAILURE);
91         }
92
93         for (i = 0; i < count; i++) {
94                 writeblks(fd, filesize, blocksize, interleave, i, rev);
95         }
96         errs=readblks(fd, filesize, blocksize, interleave, count);
97         if (close(fd) < 0) {
98                 perror("close");
99                 return 1;
100         }
101         if (errs) {
102             printf("%d errors detected during readback\n", errs);
103             return 1;
104         }
105         return 0;
106 }
107
108 void
109 writeblks(int fd, long filesize, int blocksize, int interleave, int base, int rev)
110 {
111         long offset;
112         char *buffer;
113
114         if ((buffer = calloc(1, blocksize)) == NULL) {
115                 perror("malloc");
116                 exit(1);
117         }
118
119         if (rev) {
120                 offset = (filesize-blocksize) - (base * blocksize);
121         } else {
122                 offset = base * blocksize;
123         }
124         for (;;) {
125                 if (lseek(fd, offset, SEEK_SET) < 0) {
126                         perror("lseek");
127                         exit(1);
128                 }
129                 *(long *)buffer = *(long *)(buffer+256) = offset;
130                 if (write(fd, buffer, blocksize) < blocksize) {
131                         perror("write");
132                         exit(1);
133                 }
134                 if (verbose) {
135                         printf("writing data at offset=%ld, delta=%d, value 0x%lx and 0x%lx\n",
136                                         offset-base*blocksize, base,
137                                         *(long *)buffer,
138                                         *(long *)(buffer+256));
139                 }
140
141                 if (rev) {
142                         offset -= interleave*blocksize;
143                         if (offset < 0)
144                                 break;
145                 } else {
146                         offset += interleave*blocksize;
147                         if (offset >= filesize)
148                                 break;
149                 }
150         }
151         
152         {
153             /* pad file out to full length */
154             char *zero="";
155             if (lseek(fd, filesize-1, SEEK_SET)<0) {
156                 perror("lseek");
157                 exit(1);
158             }
159             if (write(fd, zero, 1)!=1) {
160                 perror("write");
161                 exit(1);
162             }
163         }
164
165         free(buffer);
166 }
167
168 int
169 readblks(int fd, long filesize, int blocksize, int interleave, int count)
170 {
171         long offset;
172         char *buffer, *tmp;
173         int xfer, i;
174         int errs=0;
175
176         if ((buffer = calloc(interleave, blocksize)) == NULL) {
177                 perror("malloc");
178                 exit(1);
179         }
180         xfer = interleave * blocksize;
181
182         if (lseek(fd, (long)0, SEEK_SET) < 0) {
183                 perror("lseek");
184                 exit(1);
185         }
186         for (offset = 0; offset < filesize; offset += xfer) {
187                 if ((i = read(fd, buffer, xfer) < xfer)) {
188                         if (i == 0)
189                                 break;
190                         if (i < 0)
191                                 perror("read");
192                         printf("short read: %d of %d bytes read\n", i, xfer);
193                         
194                         exit(1);
195                 }
196                 for (tmp = buffer, i = 0; i < count; i++, tmp += blocksize) {
197                         if ( (*(long *)tmp != (offset+i*blocksize)) ||
198                              (*(long *)(tmp+256) != (offset+i*blocksize)) ) {
199                                 printf("mismatched data at offset=%ld, delta=%d, expected 0x%lx, got 0x%lx and 0x%lx\n",
200                                                    offset, i,
201                                                    offset+i*blocksize,
202                                                    *(long *)tmp,
203                                                    *(long *)(tmp+256));
204                                 errs++;
205                         }
206                 }
207         }
208
209         free(buffer);
210         return errs;
211 }