/* * $Id: bulkstat_unlink_test_modified.c,v 1.1 2007/10/03 16:23:57 mohamedb.longdrop.melbourne.sgi.com Exp $ * Test bulkstat doesn't returned unlinked inodes. * Mark Goodwin Fri Jul 20 09:13:57 EST 2007 * * This is a modified version of bulkstat_unlink_test.c to reproduce a specific * problem see pv 969192 */ #include #include #include #include #include #include #include int main(int argc, char *argv[]) { int e; int fd = 0; int i; int j; int k; int nfiles; int stride; struct stat sbuf; ino_t *inodelist; __u32 *genlist; struct xfs_fsop_bulkreq a; struct xfs_bstat *ret; int iterations; char fname[MAXPATHLEN]; char *dirname; if (argc != 5) { fprintf(stderr, "Usage: %s iterations nfiles stride dir\n", argv[0]); fprintf(stderr, "Create dir with nfiles, unlink each stride'th file, sync, bulkstat\n"); exit(1); } iterations = atoi(argv[1]); nfiles = atoi(argv[2]); stride = atoi(argv[3]); dirname = argv[4]; if (!nfiles || !iterations) { fprintf(stderr, "Iterations and nfiles showld be non zero.\n"); exit(1); } inodelist = (ino_t *)malloc(nfiles * sizeof(ino_t)); genlist = (__u32 *)malloc(nfiles * sizeof(__u32)); ret = (struct xfs_bstat *)malloc(nfiles * sizeof(struct xfs_bstat)); for (k=0; k < iterations; k++) { xfs_ino_t last_inode = 0; int count = 0; int testFiles = 0; printf("Iteration %d ... \n", k); memset(inodelist, 0, nfiles * sizeof(ino_t)); memset(genlist, 0, nfiles * sizeof(__u32)); memset(ret, 0, nfiles * sizeof(struct xfs_bstat)); memset(&a, 0, sizeof(struct xfs_fsop_bulkreq)); a.lastip = (__u64 *)&last_inode; a.icount = nfiles; a.ubuffer = ret; a.ocount = &count; if (mkdir(dirname, 0755) < 0) { perror(dirname); exit(1); } /* create nfiles and store their inode numbers in inodelist */ for (i=0; i < nfiles; i++) { sprintf(fname, "%s/file%06d", dirname, i); if ((fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644)) < 0) { perror(fname); exit(1); } write(fd, fname, sizeof(fname)); if (fstat(fd, &sbuf) < 0) { perror(fname); exit(1); } inodelist[i] = sbuf.st_ino; close(fd); } sync(); /* collect bs_gen for the nfiles files */ if ((fd = open(dirname, O_RDONLY)) < 0) { perror(dirname); exit(1); } testFiles = 0; for (;;) { if ((e = xfsctl(dirname, fd, XFS_IOC_FSBULKSTAT, &a)) < 0) { perror("XFS_IOC_FSBULKSTAT1:"); exit(1); } if (count == 0) break; for (i=0; i < count; i++) { for (j=0; j < nfiles; j += stride) { if (ret[i].bs_ino == inodelist[j]) { genlist[j] = ret[i].bs_gen; testFiles++; } } } } close(fd); printf("testFiles %d ... \n", testFiles); /* remove some of the first set of files */ for (i=0; i < nfiles; i += stride) { sprintf(fname, "%s/file%06d", dirname, i); if (unlink(fname) < 0) { perror(fname); exit(1); } } /* create a new set of files (replacing the unlinked ones) */ for (i=0; i < nfiles; i += stride) { sprintf(fname, "%s/file%06d", dirname, i); if ((fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644)) < 0) { perror(fname); exit(1); } write(fd, fname, sizeof(fname)); close(fd); } sync(); last_inode = 0; count = 0; if ((fd = open(dirname, O_RDONLY)) < 0) { perror(dirname); exit(1); } for (;;) { if ((e = xfsctl(dirname, fd, XFS_IOC_FSBULKSTAT, &a)) < 0) { perror("XFS_IOC_FSBULKSTAT:"); exit(1); } if (count == 0) break; for (i=0; i < count; i++) { for (j=0; j < nfiles; j += stride) { if ((ret[i].bs_ino == inodelist[j]) && (ret[i].bs_gen == genlist[j])) { /* oops, the same inode with old gen number */ printf("Unlinked inode %llu with generation %d " "returned by bulkstat\n", (unsigned long long)inodelist[j], genlist[j]); exit(1); } if (ret[i].bs_ino == inodelist[j] && ret[i].bs_gen != genlist[j] + 1) { /* oops, the new gen number is not 1 bigger than the old */ printf("Inode with old generation %d, new generation %d\n", genlist[j], ret[i].bs_gen); exit(1); } } } } close(fd); sprintf(fname, "rm -rf %s\n", dirname); system(fname); sync(); sleep(2); printf("passed\n"); } exit(0); }