update a comment.
[xfstests-dev.git] / src / randholes.c
1 /*
2  * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
3  * 
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  * 
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  * 
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  * 
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc., 59
21  * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22  * 
23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24  * Mountain View, CA  94043, or:
25  * 
26  * http://www.sgi.com 
27  * 
28  * For further information regarding this notice, see: 
29  * 
30  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31  */
32  
33 #include "global.h"
34
35 unsigned char   *valid; /* Bit-vector array showing which blocks have been written */
36 int             nvalid; /* number of bytes in valid array */
37 #define SETBIT(ARRAY, N)        ((ARRAY)[(N)/8] |= (1 << ((N)%8)))
38 #define BITVAL(ARRAY, N)        ((ARRAY)[(N)/8] & (1 << ((N)%8)))
39
40 off64_t filesize;
41 int blocksize;
42 int count;
43 int verbose;
44 int wsync;
45 int direct;
46 int alloconly;
47 int rt;
48 int extsize;
49 int preserve;
50 int test;
51 off64_t fileoffset;
52 struct dioattr diob;
53 struct fsxattr rtattr;
54
55 #define READ_XFER       10      /* block to read at a time when checking */
56
57 void usage(char *progname);
58 int findblock(void);
59 void writeblks(int fd);
60 int readblks(int fd);
61 void dumpblock(int *buffer, off64_t offset, int blocksize);
62
63 void
64 usage(char *progname)
65 {
66         fprintf(stderr, "usage: %s [-l filesize] [-b blocksize] [-c count] [-o write offset] [-s seed] [-x extentsize] [-w] [-v] [-d] [-r] [-a] [-p] filename\n",
67                         progname);
68         exit(1);
69 }
70
71 int
72 main(int argc, char *argv[])
73 {
74         int seed, ch, fd, oflags;
75         char *filename = NULL;
76         int r;
77
78         filesize = ((off64_t)256)*1024*1024;
79         blocksize = 512;
80         count = filesize/blocksize;
81         verbose = 0;
82         wsync = 0;
83         seed = time(NULL);
84         test = 0;
85         while ((ch = getopt(argc, argv, "b:l:s:c:o:x:vwdrapt")) != EOF) {
86                 switch(ch) {
87                 case 'b':       blocksize  = atoi(optarg);      break;
88                 case 'l':       filesize   = strtoll(optarg, NULL, 16); break;
89                 case 's':       seed       = atoi(optarg);      break;
90                 case 'c':       count      = atoi(optarg);      break;
91                 case 'o':       fileoffset = strtoll(optarg, NULL, 16); break;
92                 case 'x':       extsize    = atoi(optarg);      break;
93                 case 'v':       verbose++;                      break;
94                 case 'w':       wsync++;                        break;
95                 case 'd':       direct++;                       break;
96                 case 'r':       rt++;                           break;
97                 case 'a':       alloconly++;                    break;
98                 case 'p':       preserve++;                     break;
99                 case 't':       test++; preserve++;             break;
100                 default:        usage(argv[0]);                 break;
101                 }
102         }
103         if (optind == argc-1)
104                 filename = argv[optind];
105         else
106                 usage(argv[0]);
107         if ((filesize % blocksize) != 0) {
108                 filesize -= filesize % blocksize;
109                 printf("filesize not a multiple of blocksize, reducing filesize to %lld\n",
110                                  filesize);
111         }
112         if ((fileoffset % blocksize) != 0) {
113                 fileoffset -= fileoffset % blocksize;
114                 printf("fileoffset not a multiple of blocksize, reducing fileoffset to %lld\n",
115                        fileoffset);
116         }
117         if (count > (filesize/blocksize)) {
118                 count = (filesize/blocksize);
119                 printf("count of blocks written is too large, setting to %d\n",
120                               count);
121         } else if (count < 1) {
122                 count = 1;
123                 printf("count of blocks written is too small, setting to %d\n",
124                               count);
125         }
126         printf("randholes: Seed = %d (use \"-s %d\" to re-execute this test)\n", seed, seed);
127         srandom(seed);
128         
129         printf("randholes: blocksize=%d, filesize=%Ld, seed=%d\n"
130                "randholes: count=%d, offset=%Ld, extsize=%d\n",
131                 blocksize, filesize, seed, count, fileoffset, extsize);
132         printf("randholes: verbose=%d, wsync=%d, direct=%d, rt=%d, alloconly=%d, preserve=%d, test=%d\n",
133                 verbose, wsync, direct, rt, alloconly, preserve, test);
134         
135         /*
136          * Open the file, write rand block in random places, read them all
137          * back to check for correctness, then close the file.
138          */
139         nvalid = (filesize / blocksize) / 8 + 1;
140         if ((valid = (unsigned char *)calloc(1, (unsigned)nvalid)) == NULL) {
141                 perror("malloc");
142                 return 1;
143         }
144         if (rt)
145                 direct++;
146         
147         oflags=test?(O_RDONLY):(O_RDWR | O_CREAT);
148         oflags |=   (preserve ? 0 : O_TRUNC) |
149                     (wsync ? O_SYNC : 0) |
150                     (direct ? O_DIRECT : 0);
151         
152         if ((fd = open(filename, oflags, 0666)) < 0) {
153                 perror("open");
154                 return 1;
155         }
156         if (rt) {
157                 if (ioctl(fd, XFS_IOC_FSGETXATTR, &rtattr) < 0) {
158                         perror("ioctl(XFS_IOC_FSGETXATTR)");
159                         return 1;
160                 }
161                 if ((rtattr.fsx_xflags & XFS_XFLAG_REALTIME) == 0 ||
162                     (extsize && rtattr.fsx_extsize != extsize * blocksize)) {
163                         rtattr.fsx_xflags |= XFS_XFLAG_REALTIME;
164                         if (extsize)
165                                 rtattr.fsx_extsize = extsize * blocksize;
166                         if (ioctl(fd, XFS_IOC_FSSETXATTR, &rtattr) < 0) {
167                                 perror("ioctl(XFS_IOC_FSSETXATTR)");
168                                 return 1;
169                         }
170                 }
171         }
172         if (direct) {
173                 if (ioctl(fd, XFS_IOC_DIOINFO, &diob) < 0) {
174                         perror("ioctl(XFS_IOC_FIOINFO)");
175                         return 1;
176                 }
177                 if (blocksize % diob.d_miniosz) {
178                         fprintf(stderr, "blocksize %d must be a multiple of %d for direct I/O\n", blocksize, diob.d_miniosz);
179                         return 1;
180                 }
181         }
182         printf(test?"write (skipped)\n":"write\n");
183         writeblks(fd);
184         printf("readback\n");
185         r=readblks(fd);
186         if (close(fd) < 0) {
187                 perror("close");
188                 return 1;
189         }
190         free(valid);
191         
192         if (r) {
193             printf("randholes: %d errors found during readback\n", r);
194             return 2;
195         } else {
196             printf("randholes: ok\n");
197             return 0;
198         }
199 }
200
201 void
202 writeblks(int fd)
203 {
204         off64_t offset;
205         char *buffer;
206         int block;
207         struct flock64 fl;
208
209         if (direct)
210                 buffer = memalign(diob.d_mem, blocksize);
211         else
212                 buffer = malloc(blocksize);
213         if (buffer == NULL) {
214                 perror("malloc");
215                 exit(1);
216         }
217         memset(buffer, 0, blocksize);
218
219         for (  ; count > 0; count--) {
220                 if (verbose && ((count % 100) == 0)) {
221                         printf(".");
222                         fflush(stdout);
223                 }
224                 block = findblock();
225                 offset = (off64_t)block * blocksize;
226                 if (alloconly) {
227                         if (test) continue;
228                         
229                         fl.l_start = offset;
230                         fl.l_len = blocksize;
231                         fl.l_whence = 0;
232                         if (ioctl(fd, XFS_IOC_RESVSP64, &fl) < 0) {
233                                 perror("ioctl(XFS_IOC_RESVSP64)");
234                                 exit(1);
235                         }
236                         continue;
237                 }
238                 SETBIT(valid, block);
239                 if (!test) {
240                         if (lseek64(fd, fileoffset + offset, SEEK_SET) < 0) {
241                                 perror("lseek");
242                                 exit(1);
243                         }
244                 }
245                 *(off64_t *)buffer = *(off64_t *)(buffer+256) =
246                         fileoffset + offset;
247                 if (!test) {
248                         if (write(fd, buffer, blocksize) < blocksize) {
249                                 perror("write");
250                                 exit(1);
251                         }
252                 }
253                 if (test && verbose>1) printf("NOT ");
254                 if (verbose > 1) {
255                         printf("writing data at offset=%llx, value 0x%llx and 0x%llx\n",
256                                fileoffset + offset,
257                                *(off64_t *)buffer, *(off64_t *)(buffer+256));
258                 }
259         }
260
261         free(buffer);
262 }
263
264 int
265 readblks(int fd)
266 {
267         long offset;
268         char *buffer, *tmp;
269         int xfer, block, i;
270         int err=0;
271
272         if (alloconly)
273                 return 0;
274         xfer = READ_XFER*blocksize;
275         if (direct)
276                 buffer = memalign(diob.d_mem, xfer);
277         else
278                 buffer = malloc(xfer);
279         if (buffer == NULL) {
280                 perror("malloc");
281                 exit(1);
282         }
283         memset(buffer, 0, xfer);
284         if (verbose)
285                 printf("\n");
286
287         if (lseek64(fd, fileoffset, SEEK_SET) < 0) {
288                 perror("lseek");
289                 exit(1);
290         }
291         for (offset = 0, block = 0; offset < filesize; offset += xfer) {
292                 if ((i = read(fd, buffer, xfer) < xfer)) {
293                         if (i < 2)
294                                 break;
295                         perror("read");
296                         exit(1);
297                 }
298                 for (tmp = buffer, i = 0; i < READ_XFER; i++, block++, tmp += blocksize) {
299                         if (verbose && ((block % 100) == 0)) {
300                                 printf("+");
301                                 fflush(stdout);
302                         }
303                         if (BITVAL(valid, block) == 0) {
304                                 if ((*(off64_t *)tmp != 0LL) ||
305                                     (*(off64_t *)(tmp+256) != 0LL)) {
306                                         printf("mismatched data at offset=%llx, expected 0x%llx, got 0x%llx and 0x%llx\n",
307                                                fileoffset + block * blocksize,
308                                                0LL,
309                                                *(off64_t *)tmp,
310                                                *(off64_t *)(tmp+256));
311                                         err++;
312                                 }
313                         } else {
314                                 if ( (*(off64_t *)tmp !=
315                                       fileoffset + block * blocksize) ||
316                                      (*(off64_t *)(tmp+256) !=
317                                       fileoffset + block * blocksize) ) {
318                                         printf("mismatched data at offset=%llx, expected 0x%llx, got 0x%llx and 0x%llx\n",
319                                                fileoffset + block * blocksize,
320                                                fileoffset + block * blocksize,
321                                                *(off64_t *)tmp,
322                                                *(off64_t *)(tmp+256));
323                                         err++;
324                                 }
325                         }
326                         if (verbose > 2) {
327                                 printf("block %d blocksize %d\n", block,
328                                        blocksize);
329                                 dumpblock((int *)tmp,
330                                           fileoffset + block * blocksize,
331                                           blocksize);
332                         }
333                 }
334         }
335         if (verbose)
336                 printf("\n");
337
338         free(buffer);
339         return err;
340 }
341
342 int
343 findblock(void)
344 {
345         int block, numblocks;
346
347         numblocks = filesize / blocksize;
348         block = random() % numblocks;
349         if (BITVAL(valid, block) == 0)
350                 return(block);
351
352         for (  ; BITVAL(valid, block) != 0; block++) {
353                 if (block == (numblocks-1))
354                         block = -1;
355         }
356         if (block == -1)
357                 printf("returning block -1\n");
358         return(block);
359 }
360
361 void
362 dumpblock(int *buffer, off64_t offset, int blocksize)
363 {
364         int     i;
365
366         for (i = 0; i < (blocksize / 16); i++) {
367                 printf("%llx: 0x%08x 0x%08x 0x%08x 0x%08x\n",
368                        offset, *buffer, *(buffer + 1), *(buffer + 2),
369                        *(buffer + 3));
370                 offset += 16;
371                 buffer += 4;
372         }
373 }