blob: a106749dc12412582019c7114ba5605472decc91 [file] [log] [blame]
/*
* $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 <markgw@sgi.com> 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 <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <xfs/xfs.h>
#include <unistd.h>
#include <string.h>
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);
}