xfs: Verify correctness of upgrading an fs to support large extent counters
[xfstests-dev.git] / src / bulkstat_unlink_test_modified.c
1 /*
2  * $Id: bulkstat_unlink_test_modified.c,v 1.1 2007/10/03 16:23:57 mohamedb.longdrop.melbourne.sgi.com Exp $
3  * Test bulkstat doesn't returned unlinked inodes.
4  * Mark Goodwin <markgw@sgi.com> Fri Jul 20 09:13:57 EST 2007
5  *
6  * This is a modified version of bulkstat_unlink_test.c to reproduce a specific
7  * problem see pv 969192
8  */
9 #include <stdlib.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <xfs/xfs.h>
14 #include <unistd.h>
15 #include <string.h>
16
17 int
18 main(int argc, char *argv[])
19 {
20     int e;
21     int fd = 0;
22     int i;
23     int j;
24     int k;
25     int nfiles;
26     int stride;
27     struct stat sbuf;
28     ino_t *inodelist;
29     __u32 *genlist;
30     struct xfs_fsop_bulkreq a;
31     struct xfs_bstat *ret;
32     int iterations;
33     char fname[MAXPATHLEN];
34     char *dirname;
35
36     if (argc != 5) {
37         fprintf(stderr, "Usage: %s iterations nfiles stride dir\n", argv[0]);
38         fprintf(stderr, "Create dir with nfiles, unlink each stride'th file, sync, bulkstat\n");
39         exit(1);
40     }
41
42     iterations = atoi(argv[1]);
43     nfiles = atoi(argv[2]);
44     stride = atoi(argv[3]);
45     dirname = argv[4];
46     if (!nfiles || !iterations) {
47         fprintf(stderr, "Iterations and nfiles showld be non zero.\n");
48         exit(1);
49     }
50
51     inodelist = (ino_t *)malloc(nfiles * sizeof(ino_t));
52     genlist = (__u32 *)malloc(nfiles * sizeof(__u32));
53     ret = (struct xfs_bstat *)malloc(nfiles * sizeof(struct xfs_bstat));
54
55     for (k=0; k < iterations; k++) {
56         xfs_ino_t last_inode = 0;
57         int count = 0;
58         int testFiles = 0;
59
60         printf("Iteration %d ... \n", k);
61
62         memset(inodelist, 0, nfiles * sizeof(ino_t));
63         memset(genlist, 0, nfiles * sizeof(__u32));
64         memset(ret, 0, nfiles * sizeof(struct xfs_bstat));
65         memset(&a, 0, sizeof(struct xfs_fsop_bulkreq));
66         a.lastip = (__u64 *)&last_inode;
67         a.icount = nfiles;
68         a.ubuffer = ret;
69         a.ocount = &count;
70
71         if (mkdir(dirname, 0755) < 0) {
72             perror(dirname);
73             exit(1);
74         }
75
76         /* create nfiles and store their inode numbers in inodelist */
77         for (i=0; i < nfiles; i++) {
78             sprintf(fname, "%s/file%06d", dirname, i);
79             if ((fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644)) < 0) {
80                 perror(fname);
81                 exit(1);
82             }
83             write(fd, fname, sizeof(fname));
84             if (fstat(fd, &sbuf) < 0) {
85                 perror(fname);
86                 exit(1);
87             }
88             inodelist[i] = sbuf.st_ino;
89             close(fd);
90         }
91         
92         sync();
93         
94         /* collect bs_gen for the nfiles files */
95         if ((fd = open(dirname, O_RDONLY)) < 0) {
96             perror(dirname);
97             exit(1);
98         }
99
100         testFiles = 0;
101         for (;;) {
102             if ((e = xfsctl(dirname, fd, XFS_IOC_FSBULKSTAT, &a)) < 0) {
103                 perror("XFS_IOC_FSBULKSTAT1:");
104                 exit(1);
105             }
106
107             if (count == 0)
108                 break;
109
110             for (i=0; i < count; i++) {
111                 for (j=0; j < nfiles; j += stride) {
112                     if (ret[i].bs_ino == inodelist[j]) {
113                         genlist[j] = ret[i].bs_gen;
114                         testFiles++;
115                     }
116                 }
117             }
118         }
119         close(fd);
120         
121         printf("testFiles %d ... \n", testFiles);
122
123         /* remove some of the first set of files */
124         for (i=0; i < nfiles; i += stride) {
125             sprintf(fname, "%s/file%06d", dirname, i);
126             if (unlink(fname) < 0) {
127                 perror(fname);
128                 exit(1);
129             }
130         }
131
132         /* create a new set of files (replacing the unlinked ones) */
133         for (i=0; i < nfiles; i += stride) {
134             sprintf(fname, "%s/file%06d", dirname, i);
135             if ((fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644)) < 0) {
136                 perror(fname);
137                 exit(1);
138             }
139             write(fd, fname, sizeof(fname));
140             close(fd);
141         }
142
143         sync();
144         last_inode = 0; count = 0;
145
146         if ((fd = open(dirname, O_RDONLY)) < 0) {
147             perror(dirname);
148             exit(1);
149         }
150
151         for (;;) {
152             if ((e = xfsctl(dirname, fd, XFS_IOC_FSBULKSTAT, &a)) < 0) {
153                 perror("XFS_IOC_FSBULKSTAT:");
154                 exit(1);
155             }
156
157             if (count == 0)
158                     break;
159
160             for (i=0; i < count; i++) {
161                 for (j=0; j < nfiles; j += stride) {
162                     if ((ret[i].bs_ino == inodelist[j]) &&
163                         (ret[i].bs_gen == genlist[j])) {
164                         /* oops, the same inode with old gen number */
165                         printf("Unlinked inode %llu with generation %d "
166                                "returned by bulkstat\n",
167                                 (unsigned long long)inodelist[j],
168                                  genlist[j]);
169                         exit(1);
170                     }
171                     if (ret[i].bs_ino == inodelist[j] &&
172                         ret[i].bs_gen != genlist[j] + 1) {
173                         /* oops, the new gen number is not 1 bigger than the old */
174                         printf("Inode with old generation %d, new generation %d\n",
175                         genlist[j], ret[i].bs_gen);
176                         exit(1);
177                     }
178                 }
179             }
180         }
181
182         close(fd);
183
184         sprintf(fname, "rm -rf %s\n", dirname);
185         system(fname);
186
187         sync();
188         sleep(2);
189         printf("passed\n");
190     }
191
192     exit(0);
193 }