|  | /* | 
|  | * $Id: bulkstat_unlink_test.c,v 1.3 2007/10/30 03:07:42 mohamedb.longdrop.melbourne.sgi.com Exp $ | 
|  | * Test bulkstat doesn't returned unlinked inodes. | 
|  | * Mark Goodwin <markgw@sgi.com> Fri Jul 20 09:13:57 EST 2007 | 
|  | */ | 
|  | #include <stdlib.h> | 
|  | #include <sys/types.h> | 
|  | #include <sys/stat.h> | 
|  | #include <fcntl.h> | 
|  | #include <xfs/xfs.h> | 
|  | #include <unistd.h> | 
|  | #include <getopt.h> | 
|  | #include <string.h> | 
|  |  | 
|  | int | 
|  | main(int argc, char *argv[]) | 
|  | { | 
|  | int e; | 
|  | int i; | 
|  | int j; | 
|  | int k; | 
|  | int nfiles; | 
|  | int stride; | 
|  |  | 
|  | int c; | 
|  |  | 
|  | struct stat sbuf; | 
|  | ino_t *inodelist; | 
|  | struct xfs_fsop_bulkreq a; | 
|  | struct xfs_bstat *ret; | 
|  | int iterations; | 
|  | char fname[MAXPATHLEN]; | 
|  | char *dirname; | 
|  | int chknb = 0; | 
|  |  | 
|  | while ((c = getopt(argc, argv, "r")) != -1) { | 
|  | switch(c) { | 
|  | case 'r': | 
|  | chknb = 1; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if ((argc - optind) != 4) { | 
|  | fprintf(stderr, "Usage: %s iterations nfiles stride dir [options]\n", argv[0]); | 
|  | fprintf(stderr, "Create dir with nfiles, unlink each stride'th file, sync, bulkstat\n"); | 
|  | exit(1); | 
|  | } | 
|  |  | 
|  |  | 
|  | iterations = atoi(argv[optind++]); | 
|  | nfiles     = atoi(argv[optind++]); | 
|  | stride     = atoi(argv[optind++]); | 
|  |  | 
|  | dirname = argv[optind++]; | 
|  |  | 
|  | if (chknb) | 
|  | printf("Runing extended checks.\n"); | 
|  |  | 
|  | inodelist = (ino_t *)malloc(nfiles * sizeof(ino_t)); | 
|  | ret = (struct xfs_bstat *)malloc(nfiles * sizeof(struct xfs_bstat)); | 
|  |  | 
|  | for (k=0; k < iterations; k++) { | 
|  | int fd[nfiles + 1]; | 
|  | xfs_ino_t last_inode = 0; | 
|  | int count = 0, scount = -1; | 
|  |  | 
|  | printf("Iteration %d ... (%d files)", k, nfiles); | 
|  |  | 
|  | 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) { | 
|  | printf("Warning (%s,%d), mkdir(%s) failed.\n", __FILE__, __LINE__, dirname); | 
|  | perror(dirname); | 
|  | exit(1); | 
|  | } | 
|  |  | 
|  | if ((fd[nfiles] = open(dirname, O_RDONLY)) < 0) { | 
|  | printf("Warning (%s,%d), open(%s) failed.\n", __FILE__, __LINE__, dirname); | 
|  | perror(dirname); | 
|  | exit(1); | 
|  | } | 
|  |  | 
|  | if (chknb) { /* Get the original number of inodes (lazy) */ | 
|  | sync(); | 
|  | if (xfsctl(dirname, fd[nfiles], XFS_IOC_FSBULKSTAT, &a) != 0) { | 
|  | printf("Warning (%s:%d), xfsctl(XFS_IOC_FSBULKSTAT) FAILED.\n", __FILE__, __LINE__); | 
|  | } | 
|  |  | 
|  | scount = count; | 
|  | } | 
|  |  | 
|  | for (i=0; i < nfiles; i++) { /* Open the files */ | 
|  | sprintf(fname, "%s/file%06d", dirname, i); | 
|  | if ((fd[i] = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644)) < 0) { | 
|  | printf("Warning (%s,%d), open(%s) failed.\n", __FILE__, __LINE__, fname); | 
|  | perror(fname); | 
|  | exit(1); | 
|  | } | 
|  | write(fd[i], fname, sizeof(fname)); | 
|  | if (fstat(fd[i], &sbuf) < 0) { | 
|  | printf("Warning (%s,%d), fstat failed.\n", __FILE__, __LINE__); | 
|  | perror(fname); | 
|  | exit(1); | 
|  | } | 
|  | inodelist[i] = sbuf.st_ino; | 
|  | unlink(fname); | 
|  | } | 
|  |  | 
|  | if (chknb) { | 
|  | /* | 
|  | *The files are still opened (but unlink()ed) , | 
|  | * we should have more inodes than before | 
|  | */ | 
|  | sync(); | 
|  | last_inode = 0; | 
|  | if (xfsctl(dirname, fd[nfiles], XFS_IOC_FSBULKSTAT, &a) != 0) { | 
|  | printf("Warning (%s:%d), xfsctl(XFS_IOC_FSBULKSTAT) FAILED.\n", __FILE__, __LINE__); | 
|  | } | 
|  | if (count < scount) { | 
|  | printf("ERROR, count(%d) < scount(%d).\n", count, scount); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Close all the files */ | 
|  | for (i = 0; i < nfiles; i++) { | 
|  | close(fd[i]); | 
|  | } | 
|  |  | 
|  | if (chknb) { | 
|  | /* | 
|  | * The files are now closed, we should be back to our, | 
|  | * previous inode count | 
|  | */ | 
|  | sync(); | 
|  | last_inode = 0; | 
|  | if (xfsctl(dirname, fd[nfiles], XFS_IOC_FSBULKSTAT, &a) != 0) { | 
|  | printf("Warning (%s:%d), xfsctl(XFS_IOC_FSBULKSTAT) FAILED.\n", __FILE__, __LINE__); | 
|  | } | 
|  | if (count != scount) { | 
|  | printf("ERROR, count(%d) != scount(%d).\n", count, scount); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | sync(); | 
|  | last_inode = 0; | 
|  | for (;;) { | 
|  | if ((e = xfsctl(dirname, fd[nfiles], XFS_IOC_FSBULKSTAT, &a)) < 0) { | 
|  | printf("Warning (%s,%d), xfsctl failed.\n", __FILE__, __LINE__); | 
|  | 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]) { | 
|  | /* oops ... */ | 
|  | printf("failed. Unlinked inode %llu returned by bulkstat\n", (unsigned long long)inodelist[j]); | 
|  | exit(1); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | close(fd[nfiles]); | 
|  | sprintf(fname, "rm -rf %s\n", dirname); | 
|  | system(fname); | 
|  |  | 
|  | sync(); | 
|  | sleep(2); | 
|  | printf("passed\n"); | 
|  | } | 
|  |  | 
|  | exit(0); | 
|  | } |