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