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