LCA2011 version
[tridge/junkcode.git] / tsm_torture.c
index 3a8b50f5b36eeeb0eb3d2f90af73cb29f34a5545..cc3e0372a6522e475b21f39cd6768397a32d45e1 100644 (file)
@@ -59,6 +59,9 @@ static struct {
        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,
@@ -68,6 +71,9 @@ static struct {
        .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;
@@ -75,6 +81,7 @@ 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;
@@ -147,7 +154,7 @@ static char *filename(int i)
 
 static void sigio_handler(int sig)
 {
-       printf("\nGot SIGIO\n");
+       printf("Got SIGIO\n");
 }
 
 static volatile bool signal_received;
@@ -178,7 +185,7 @@ static ssize_t pread_aio(int fd, void *buf, size_t count, off_t offset)
 
        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);
                }
        }
@@ -187,7 +194,7 @@ static ssize_t pread_aio(int fd, void *buf, size_t count, off_t offset)
        }
        if (options.io_uid) {
                if (seteuid(0) != 0) {
-                       printf("\nFailed to become root\n");
+                       printf("Failed to become root\n");
                        exit(1);
                }
        }
@@ -198,7 +205,7 @@ static ssize_t pread_aio(int fd, void *buf, size_t count, off_t offset)
 
        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;
        }
 
@@ -227,7 +234,7 @@ static ssize_t pwrite_aio(int fd, void *buf, size_t count, off_t offset)
 
        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);
                }
        }
@@ -236,7 +243,7 @@ static ssize_t pwrite_aio(int fd, void *buf, size_t count, off_t offset)
        }
        if (options.io_uid) {
                if (seteuid(0) != 0) {
-                       printf("\nFailed to become root\n");
+                       printf("Failed to become root\n");
                        exit(1);
                }
        }
@@ -247,7 +254,7 @@ static ssize_t pwrite_aio(int fd, void *buf, size_t count, off_t offset)
 
        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;
        }
 
@@ -267,17 +274,21 @@ static void child_loadfile(struct child *child, const char *fname, unsigned fnum
        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;
        }
@@ -289,19 +300,21 @@ static void child_loadfile(struct child *child, const char *fname, unsigned fnum
                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;
                }
        }
 
@@ -327,18 +340,18 @@ static void child_savefile(struct child *child, const char *fname, unsigned fnum
 
 #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);
@@ -346,9 +359,7 @@ static void child_savefile(struct child *child, const char *fname, unsigned fnum
                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;
@@ -365,17 +376,25 @@ static void child_getoffline(struct child *child, const char *fname)
 {
        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++;
@@ -394,12 +413,20 @@ static void child_migrate(struct child *child, const char *fname)
        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 */
@@ -424,6 +451,7 @@ static void child_migrate(struct child *child, const char *fname)
        free(cmd);
 }
 
+
 /*
   main child loop
  */
@@ -484,7 +512,7 @@ static void sig_alarm(int sig)
        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);
                }
@@ -496,6 +524,9 @@ static void sig_alarm(int sig)
        }
 
        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;
@@ -525,7 +556,7 @@ static void sig_alarm(int sig)
                }
        }
 
-       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,
@@ -553,6 +584,9 @@ static void usage(void)
        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);
 }
 
@@ -563,7 +597,7 @@ int main(int argc, char * const argv[])
        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;
@@ -574,6 +608,9 @@ int main(int argc, char * const argv[])
                case 'A':
                        options.use_aio = true;
                        break;
+               case 'C':
+                       options.skip_file_creation = true;
+                       break;
                case 'N':
                        options.nprocesses = atoi(optarg);
                        break;
@@ -592,6 +629,13 @@ int main(int argc, char * const argv[])
                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;
@@ -602,7 +646,8 @@ int main(int argc, char * const argv[])
                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;
@@ -620,28 +665,31 @@ int main(int argc, char * const argv[])
 
        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();
@@ -654,6 +702,7 @@ int main(int argc, char * const argv[])
                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;
@@ -667,7 +716,12 @@ int main(int argc, char * const argv[])
 
        /* 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;