const char *migrate_cmd;
bool use_aio;
uid_t io_uid;
+ bool skip_file_creation;
+ bool exit_child_on_error;
+ bool die_on_error;
} options = {
.use_lease = false,
.use_sharemode = false,
.timelimit = 30,
.migrate_cmd = "dsmmigrate",
.use_aio = false,
+ .skip_file_creation = false,
+ .exit_child_on_error = false,
+ .die_on_error = false,
};
static pid_t parent_pid;
enum offline_op {OP_LOADFILE, OP_SAVEFILE, OP_MIGRATE, OP_GETOFFLINE, OP_ENDOFLIST};
struct child {
+ unsigned child_num;
unsigned offline_count;
unsigned online_count;
unsigned migrate_fail_count;
static void sigio_handler(int sig)
{
- printf("\nGot SIGIO\n");
+ printf("Got SIGIO\n");
}
static volatile bool signal_received;
if (options.io_uid) {
if (seteuid(options.io_uid) != 0) {
- printf("\nFailed to become uid %u\n", options.io_uid);
+ printf("Failed to become uid %u\n", options.io_uid);
exit(1);
}
}
}
if (options.io_uid) {
if (seteuid(0) != 0) {
- printf("\nFailed to become root\n");
+ printf("Failed to become root\n");
exit(1);
}
}
ret = aio_error(&acb);
if (ret != 0) {
- printf("\naio operation failed - %s\n", strerror(ret));
+ printf("aio operation failed - %s\n", strerror(ret));
return -1;
}
if (options.io_uid) {
if (seteuid(options.io_uid) != 0) {
- printf("\nFailed to become uid %u\n", options.io_uid);
+ printf("Failed to become uid %u\n", options.io_uid);
exit(1);
}
}
}
if (options.io_uid) {
if (seteuid(0) != 0) {
- printf("\nFailed to become root\n");
+ printf("Failed to become root\n");
exit(1);
}
}
ret = aio_error(&acb);
if (ret != 0) {
- printf("\naio operation failed - %s\n", strerror(ret));
+ printf("aio operation failed - %s\n", strerror(ret));
return -1;
}
fd = open(fname, O_RDONLY);
if (fd == -1) {
perror(fname);
- exit(1);
+ if (options.exit_child_on_error) {
+ exit(1);
+ }
+ child->io_fail_count++;
+ return;
}
#if WITH_GPFS
if (options.use_lease && gpfs_set_lease(fd, GPFS_LEASE_READ) != 0) {
- printf("\ngpfs_set_lease on '%s' - %s\n", fname, strerror(errno));
+ printf("gpfs_set_lease on '%s' - %s\n", fname, strerror(errno));
close(fd);
return;
}
if (options.use_sharemode && gpfs_set_share(fd, 1, 2) != 0) {
- printf("\ngpfs_set_share on '%s' - %s\n", fname, strerror(errno));
+ printf("gpfs_set_share on '%s' - %s\n", fname, strerror(errno));
close(fd);
return;
}
ret = pread(fd, buf, options.fsize, 0);
}
if (ret != options.fsize) {
- if (child->io_fail_count == 0) {
- printf("\npread failed on '%s' - %s\n", fname, strerror(errno));
- }
+ printf("pread failed on '%s' - %s\n", fname, strerror(errno));
child->io_fail_count++;
close(fd);
return;
}
for (i=0;i<options.fsize;i++) {
- if (buf[i] != fnumber % 256) {
- printf("\nBad data %u - expected %u for '%s'\n",
- buf[i], fnumber%256, fname);
- exit(1);
+ if (buf[i] != 1+(fnumber % 255)) {
+ printf("Bad data %u - expected %u for '%s'\n",
+ buf[i], 1+(fnumber%255), fname);
+ if (options.exit_child_on_error) {
+ exit(1);
+ }
+ child->io_fail_count++;
+ break;
}
}
#if WITH_GPFS
if (options.use_lease && gpfs_set_lease(fd, GPFS_LEASE_WRITE) != 0) {
- printf("\ngpfs_set_lease on '%s' - %s\n", fname, strerror(errno));
+ printf("gpfs_set_lease on '%s' - %s\n", fname, strerror(errno));
close(fd);
return;
}
if (options.use_sharemode && gpfs_set_share(fd, 1, 2) != 0) {
- printf("\ngpfs_set_share on '%s' - %s\n", fname, strerror(errno));
+ printf("gpfs_set_share on '%s' - %s\n", fname, strerror(errno));
close(fd);
return;
}
#endif
- memset(buf, fnumber%256, options.fsize);
+ memset(buf, 1+(fnumber%255), options.fsize);
if (options.use_aio) {
ret = pwrite_aio(fd, buf, options.fsize, 0);
ret = pwrite(fd, buf, options.fsize, 0);
}
if (ret != options.fsize) {
- if (child->io_fail_count == 0) {
- printf("\npwrite failed on '%s' - %s\n", fname, strerror(errno));
- }
+ printf("pwrite failed on '%s' - %s\n", fname, strerror(errno));
child->io_fail_count++;
close(fd);
return;
{
struct stat st;
if (stat(fname, &st) != 0) {
- printf("\nFailed to stat '%s' - %s\n", fname, strerror(errno));
- exit(1);
+ printf("Failed to stat '%s' - %s\n", fname, strerror(errno));
+ if (options.exit_child_on_error) {
+ exit(1);
+ }
+ child->io_fail_count++;
+ return;
}
if (st.st_size != options.fsize) {
- printf("\nWrong file size for '%s' - %u\n", fname, (unsigned)st.st_size);
- exit(1);
+ printf("Wrong file size for '%s' - %u\n", fname, (unsigned)st.st_size);
+ if (options.exit_child_on_error) {
+ exit(1);
+ }
+ child->io_fail_count++;
+ return;
}
if (st.st_blocks == 0) {
child->offline_count++;
if (strcmp(options.migrate_cmd, "/bin/true") == 0) {
- printf("\nFile '%s' is offline with no migration command\n", fname);
+ printf("File '%s' is offline with no migration command\n", fname);
}
} else {
child->online_count++;
struct stat st;
if (stat(fname, &st) != 0) {
- printf("\nFailed to stat '%s' - %s\n", fname, strerror(errno));
- exit(1);
+ printf("Failed to stat '%s' - %s\n", fname, strerror(errno));
+ if (options.exit_child_on_error) {
+ exit(1);
+ }
+ child->io_fail_count++;
+ return;
}
if (st.st_size != options.fsize) {
- printf("\nWrong file size for '%s' - %u\n", fname, (unsigned)st.st_size);
- exit(1);
+ printf("Wrong file size for '%s' - %u\n", fname, (unsigned)st.st_size);
+ if (options.exit_child_on_error) {
+ exit(1);
+ }
+ child->io_fail_count++;
+ return;
}
if (st.st_blocks == 0) {
/* already offline */
free(cmd);
}
+
/*
main child loop
*/
double worst_latencies[OP_ENDOFLIST];
if (timeval_elapsed(&tv_start) >= options.timelimit) {
- printf("\ntimelimit reached - killing children\n");
+ printf("timelimit reached - killing children\n");
for (i=0;i<options.nprocesses;i++) {
kill(children[i].pid, SIGTERM);
}
}
for (i=0;i<options.nprocesses;i++) {
+ if (kill(children[i].pid, 0) != 0) {
+ continue;
+ }
total += children[i].count - children[i].lastcount;
children[i].lastcount = children[i].count;
total_online += children[i].online_count;
}
}
- printf("ops/s=%4u offline=%u/%u failures: mig=%u io=%u latencies: mig=%.1f/%.1f stat=%.1f/%.1f write=%.1f/%.1f read=%.1f/%.1f \r",
+ printf("ops/s=%4u offline=%u/%u failures: mig=%u io=%u latencies: mig=%4.1f/%4.1f stat=%4.1f/%4.1f write=%4.1f/%4.1f read=%4.1f/%4.1f\n",
total, total_offline, total_online+total_offline,
total_migrate_failures,
total_io_failures,
printf(" -L use gpfs leases\n");
printf(" -S use gpfs sharemodes\n");
printf(" -A use Posix async IO\n");
+ printf(" -C skip file creation\n");
+ printf(" -E exit child on IO error\n");
+ printf(" -D die on error\n");
exit(0);
}
struct stat st;
/* parse command-line options */
- while ((opt = getopt(argc, argv, "LSN:F:t:s:M:U:Ah")) != -1) {
+ while ((opt = getopt(argc, argv, "LSN:F:t:s:M:U:AhCED")) != -1) {
switch (opt){
case 'L':
options.use_lease = true;
case 'A':
options.use_aio = true;
break;
+ case 'C':
+ options.skip_file_creation = true;
+ break;
case 'N':
options.nprocesses = atoi(optarg);
break;
case 't':
options.timelimit = atoi(optarg);
break;
+ case 'E':
+ options.exit_child_on_error = true;
+ break;
+ case 'D':
+ options.die_on_error = true;
+ options.exit_child_on_error = true;
+ break;
default:
usage();
break;
printf("ERROR: you must invoke as smbd to use leases or share modes - use a symlink\n");
exit(1);
}
-
+
+ setlinebuf(stdout);
argv += optind;
argc -= optind;
children = shm_setup(sizeof(*children) * options.nprocesses);
- printf("Creating %u files of size %u in '%s'\n",
- options.nfiles, options.fsize, options.dir);
buf = malloc(options.fsize);
- for (i=0;i<options.nfiles;i++) {
- int fd;
- char *fname = filename(i);
- fd = open(fname, O_CREAT|O_RDWR, 0600);
- if (fd == -1) {
- perror(fname);
- exit(1);
- }
- ftruncate(fd, options.fsize);
- memset(buf, i%256, options.fsize);
- if (write(fd, buf, options.fsize) != options.fsize) {
- printf("Failed to write '%s'\n", fname);
- exit(1);
+ if (!options.skip_file_creation) {
+ printf("Creating %u files of size %u in '%s'\n",
+ options.nfiles, options.fsize, options.dir);
+
+ for (i=0;i<options.nfiles;i++) {
+ int fd;
+ char *fname = filename(i);
+ fd = open(fname, O_CREAT|O_RDWR, 0600);
+ if (fd == -1) {
+ perror(fname);
+ exit(1);
+ }
+ ftruncate(fd, options.fsize);
+ memset(buf, 1+(i%255), options.fsize);
+ if (write(fd, buf, options.fsize) != options.fsize) {
+ printf("Failed to write '%s'\n", fname);
+ exit(1);
+ }
+ fsync(fd);
+ close(fd);
+ free(fname);
}
- fsync(fd);
- close(fd);
- free(fname);
}
parent_pid = getpid();
pid_t pid = fork();
if (pid == 0) {
children[i].pid = getpid();
+ children[i].child_num = i;
run_child(&children[i]);
} else {
children[i].pid = pid;
/* wait for the children to finish */
for (i=0;i<options.nprocesses;i++) {
- while (waitpid(children[i].pid, 0, 0) != 0 && errno != ECHILD) ;
+ int status;
+ while (waitpid(-1, &status, 0) != 0 && errno != ECHILD) ;
+ if (WEXITSTATUS(status) != 0 &&
+ options.die_on_error) {
+ exit(1);
+ }
}
return 0;