xfs: test fallocate ops when rt extent size is and isn't a power of 2
[xfstests-dev.git] / dmapi / src / suite2 / src / test_hole.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 <sys/types.h>
8 #include <sys/stat.h>
9
10 #include <lib/hsm.h>
11 #include <lib/errtest.h>
12
13 #include <getopt.h>
14 #include <string.h>
15
16
17 /*---------------------------------------------------------------------------
18
19 Test program used to test the DMAPI function dm_punch_hole().  The
20 command line is:
21
22         test_hole [-v] [-s sid] pathname
23
24 where 
25    ls_path
26       is the path to a specific copy of ls, important only for its size
27    pathname 
28       is the path to the test filesystem
29    sid
30       is the session ID whose events you you are interested in.
31
32 ----------------------------------------------------------------------------*/
33
34 #ifndef linux
35 extern  char    *sys_errlist[];
36 #endif
37 extern  int     optind;
38 extern  char    *optarg;
39
40 char    *Progname;
41
42
43 static void
44 usage(void)
45 {
46         fprintf(stderr, "usage:\t%s [-v] [-s sid] ls_path directoryname\n",
47                 Progname);
48         exit(1);
49 }
50
51
52 int
53 main(
54         int     argc, 
55         char    **argv)
56 {
57         dm_sessid_t     sid = DM_NO_SESSION;
58         char            *pathname = NULL;
59         char            *ls_path = NULL;
60         dm_off_t        offset = 0, end;
61         dm_off_t        ex_off = 0;
62         dm_extent_t     extent[20];
63         u_int           nelem;
64         dm_size_t       length = 0;
65         void            *hanp;
66         size_t          hlen;
67         dm_token_t      test_token;
68         char            *name;
69         int             opt;
70         int             Vflag = 0;
71         char            filename[128];
72         char            command[128];
73         dm_off_t        roff;
74         dm_size_t       rlen;
75         dm_off_t        blocksize = 5; 
76         void            *test_vp;
77         struct stat    buf;
78         struct stat    checkbuf;
79
80
81         Progname = strrchr(argv[0], '/');
82         if (Progname) {
83                 Progname++;
84         } else {
85                 Progname = argv[0];
86         }
87
88         /* Crack and validate the command line options. */
89
90         while ((opt = getopt(argc, argv, "vs:")) != EOF) {
91                 switch (opt) {
92                 case 'v':
93                         Vflag++;
94                         break;
95                 case 's':
96                         sid = atol(optarg);
97                         break;
98                 case '?':
99                         usage();
100                 }
101         }
102         if (optind + 2 != argc)
103                 usage();
104         ls_path = argv[optind];
105         pathname = argv[optind+1];
106
107         if (dm_init_service(&name) == -1)  {
108                 fprintf(stdout, "Can't initialize the DMAPI\n");
109                 exit(1);
110         }
111         if (sid == DM_NO_SESSION)
112                 find_test_session(&sid);
113
114         /* Get the directory handle. */
115
116         if (dm_path_to_handle(pathname, &hanp, &hlen)) {
117                 fprintf(stdout, 
118                      "ERROR: can't get handle for directory %s\n", pathname);
119                 exit(1);
120         }
121         
122         printf("Hole test beginning...\n");
123         sprintf(filename, "%s/VeryLongUnlikelyFilename.HOLETEST", pathname);
124         sprintf(command, "cp %s %s \n", ls_path, filename); 
125         system(command);
126
127         if (dm_path_to_handle(filename, &hanp, &hlen)) {
128           fprintf(stdout, "can't get handle for %s\n; aborting test",
129                   filename);
130           
131           sprintf(command, "rm %s \n", filename); 
132           system(command);
133           fprintf(stdout, "\tHole test aborted.\n");
134           
135           dm_handle_free(hanp, hlen);
136           exit(1);
137         }
138    
139         /*   ## Get the block size using a length-1 probe. ##   */
140         dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 1, 0,
141                       &blocksize, &rlen);
142         
143         if (blocksize==0) {
144           fprintf(stdout, "Error: block size appears to be 0!\n");
145           
146           sprintf(command, "rm %s \n", filename); 
147           system(command);
148           fprintf(stdout, "\tHole test aborted.\n");
149           
150           dm_handle_free(hanp, hlen);
151           exit(1);
152         }
153
154         /*
155          * The kernel always rounds the offset up to the next block
156          * size, so we can only probes up to the previous to last block.
157          */
158         end = (29604 / blocksize) * blocksize;
159
160         /* Check that dm_probe_hole returns an extent from the next
161          * highest multiple of the block size, to the end of the file
162          */
163         for (offset = 0; offset < end; offset++) { 
164           if (dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length,
165                             &roff, &rlen)) {
166             fprintf(stdout, "dm_probe_hole failed on pass %lld (%s)\n",
167                     (long long)offset, ERR_NAME);
168           }
169           else {
170             if (rlen != 0) {
171                 fprintf(stdout, 
172                         "Error: hole did not extend to end of file!\n");
173             }
174             if (blocksize*(roff/blocksize) != roff) {
175                 fprintf(stdout,
176                         "Error: offset not a multiple of block size!\n");
177             }
178           }
179         }
180         
181         /* Be sure dm_punch_hole doesn't change the time stamp, 
182          * and verify that dm_get_allocinfo shows a hole
183          * followed by an extent to the end of the file.
184          */
185         for(offset = 28672; offset > 0; offset-=blocksize) {
186           if (stat(filename, &buf)){
187             fprintf(stdout, 
188                     "Error: unable to stat the test file; %s (1st)\n", 
189                     filename);
190             continue;
191           }
192           if (dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length,
193                             &roff, &rlen)) {
194             fprintf(stdout, "dm_probe_hole failed, %s\n",
195                     ERR_NAME);
196             continue;
197           }
198           if (roff != offset) {
199             fprintf(stdout, 
200                     "Error: presumed offset was not %lld.\n",
201                     (long long)(roff));
202           }
203           if (dm_punch_hole(sid, hanp, hlen, DM_NO_TOKEN,
204                             roff, length)) {
205             fprintf(stdout, "dm_punch_hole failed, %s\n",
206                     ERR_NAME);
207             continue;
208           }
209           if (stat(filename, &checkbuf)){
210             fprintf(stdout, 
211                     "Error: unable to stat the test file. (2nd)\n");
212             continue;
213           }
214           else {
215             /* COMPARE BUF AND CHECKBUF! */
216 #ifdef linux
217             if ((buf.st_atime == checkbuf.st_atime) &&
218                 (buf.st_mtime == checkbuf.st_mtime) &&
219                 (buf.st_ctime == checkbuf.st_ctime))
220 #else
221             if ((buf.st_atim.tv_sec == checkbuf.st_atim.tv_sec) &&
222                 (buf.st_atim.tv_nsec == checkbuf.st_atim.tv_nsec) &&
223                 (buf.st_mtim.tv_sec == checkbuf.st_mtim.tv_sec) &&
224                 (buf.st_mtim.tv_nsec == checkbuf.st_mtim.tv_nsec) &&
225                 (buf.st_ctim.tv_sec == checkbuf.st_ctim.tv_sec) &&
226                 (buf.st_ctim.tv_nsec == checkbuf.st_ctim.tv_nsec))
227 #endif
228            {
229               if (Vflag) {
230                 fprintf(stdout, 
231                         "\tTime stamp unchanged by hole from offset %lld.\n",
232                         (long long)(offset));
233               }
234             }
235             else {
236               fprintf(stdout,
237                       "Error: punch_hole changed file's time stamp.\n");
238             }
239             ex_off=0;
240             if ((dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN, 
241                                   &ex_off, 1, extent, &nelem) == 1) &&
242                 (extent->ex_type == DM_EXTENT_RES) &&
243                 (dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN,
244                                   &ex_off, 1, extent, &nelem) == 0) &&
245                 (extent->ex_type == DM_EXTENT_HOLE)) {
246               if (extent->ex_offset == roff){
247                 if (Vflag) {
248                   fprintf(stdout, "\tVerified hole at %lld\n", 
249                           (long long)(extent->ex_offset));
250                 }
251               }
252               else {
253                 fprintf(stdout, "\tError: get_allocinfo found hole at %lld\n",
254                         (long long)(extent->ex_offset));
255               }
256             }
257             else {
258                 fprintf(stdout, "\tError: get_allocinfo did not find an "
259                         "extent followed by a hole!\n");
260             }
261           }
262         }
263         /*------------------------*\
264         |*  ## Errno subtests ##  *|
265         \*------------------------*/
266         fprintf(stdout, "\t(beginning errno subtests...)\n");
267         /*---------------------------------------------------------*/
268         ERRTEST(E2BIG,
269                 "probe (from past EOF)",
270                 dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 30000, length,
271                               &roff, &rlen))
272         /*---------------------------------------------------------*/
273         ERRTEST(E2BIG,
274                 "probe (to past EOF)",
275                 dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 15000, 150000,
276                               &roff, &rlen))
277         /*---------------------------------------------------------*/
278         SHAREDTEST("probe", hanp, hlen, test_token, 
279                  dm_probe_hole(sid, hanp, hlen, test_token, 
280                                0, 0, &roff, &rlen)) 
281         /*---------------------------------------------------------*/
282         EXCLTEST("punch", hanp, hlen, test_token, 
283                    dm_punch_hole(sid, hanp, hlen, test_token, 0, 0)) 
284         /*---------------------------------------------------------*/
285         /*
286          * No idea where that EAGAIN should come from, it's never
287          * returned from the kernel.
288          *
289          *              -- hch
290          */
291 #if 0
292         ERRTEST(EAGAIN,
293                 "punch",
294                 dm_punch_hole(sid, hanp, hlen, DM_NO_TOKEN,
295                               1, length))       
296 #endif
297         /*---------------------------------------------------------*/
298         if ((test_vp = handle_clone(hanp, hlen)) == NULL) {
299           fprintf(stderr, 
300                   "Cannot create a test handle (%s); skipping EBADF test\n",
301                   ERR_NAME);
302         }
303         else {
304          ((char *) test_vp)[hlen/2]++;
305           ERRTEST(EBADF,
306                   "probe",
307                   dm_probe_hole(sid, test_vp, hlen, DM_NO_TOKEN,
308                                 offset, length,
309                                 &roff, &rlen))
310           ERRTEST(EBADF,
311                   "punch",
312                   dm_punch_hole(sid, test_vp, hlen, DM_NO_TOKEN,
313                                 offset, length))
314         }
315         dm_handle_free(test_vp, hlen);
316         /*---------------------------------------------------------*/
317         ERRTEST(EFAULT,
318                 "probe (null handle)",
319                 dm_probe_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length,
320                                 &roff, &rlen))
321         ERRTEST(EFAULT,
322                 "probe (bad rlen)",
323                 dm_probe_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length,
324                                 &roff, (dm_size_t*)(-1000)))
325         ERRTEST(EFAULT,
326                 "probe (bad roff)",
327                 dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length,
328                                 (dm_off_t*)(-1000), &rlen))
329         /*---------------------------------------------------------*/
330         ERRTEST(EFAULT,
331                 "punch",
332                 dm_punch_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length))
333         /*---------------------------------------------------------*/
334         ERRTEST(EINVAL,
335                 "probe (bad session)",
336                 dm_probe_hole(-100, hanp, hlen, DM_NO_TOKEN, offset, length,
337                                 &roff, &rlen))
338         /*---------------------------------------------------------*/
339         ERRTEST(EINVAL, 
340                 "probe (bad token)",
341                 dm_probe_hole(sid, hanp, hlen, 0, offset, length,
342                                 &roff, &rlen))
343         /*---------------------------------------------------------*/
344         ERRTEST(EINVAL, 
345                 "probe (bad token 2)",
346                 dm_probe_hole(sid, hanp, hlen, 0, offset, length,
347                                 &roff, &rlen))
348         /*---------------------------------------------------------*/
349         fprintf(stdout, "\t(errno subtests complete)\n");
350                 
351
352         sprintf(command, "rm %s \n", filename); 
353         system(command);
354         printf("Hole test complete.\n");
355
356         dm_handle_free(hanp, hlen);
357         exit(0);
358 }
359