btreplay: fix memory corruption caused by CPU_ZERO_S
[blktrace.git] / btreplay / btreplay.c
index 89881cbd48b7baacf0f8ff34c8140839a0df516d..2a1525e046620ecae71d2b8eea88b8da921c7e93 100644 (file)
@@ -154,6 +154,7 @@ static LIST_HEAD(input_files);              // List of input files to handle
 static LIST_HEAD(map_devs);            // List of device maps
 static int nfiles = 0;                 // Number of files to handle
 static int no_stalls = 0;              // Boolean: Disable pre-stalls
+static unsigned acc_factor = 1;                // Int: Acceleration factor
 static int find_records = 0;           // Boolean: Find record files auto
 
 /*
@@ -501,19 +502,34 @@ static inline void start_iter(void)
  */
 static void get_ncpus(void)
 {
-       cpu_set_t cpus;
-
-       if (sched_getaffinity(getpid(), sizeof(cpus), &cpus)) {
+#ifdef _SC_NPROCESSORS_ONLN
+       ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+       int nrcpus = 4096;
+       cpu_set_t * cpus;
+       
+realloc:
+       cpus = CPU_ALLOC(nrcpus);
+       size = CPU_ALLOC_SIZE(nrcpus);
+       CPU_ZERO_S(size, cpus);
+
+       if (sched_getaffinity(getpid(), size, cpus)) {
+               if( errno == EINVAL && nrcpus < (4096<<4) ) {
+                       CPU_FREE(cpus);
+                       nrcpus <<= 1;
+                       goto realloc;
+               }
                fatal("sched_getaffinity", ERR_SYSCALL, "Can't get CPU info\n");
                /*NOTREACHED*/
        }
 
-       /*
-        * XXX This assumes (perhaps wrongly) that there are no /holes/ 
-        * XXX in the mask.
-        */
-       for (ncpus = 0; ncpus < CPU_SETSIZE && CPU_ISSET(ncpus, &cpus); ncpus++)
-               ;
+       ncpus = -1;
+       for (last_cpu = 0; last_cpu < CPU_SETSIZE && CPU_ISSET(last_cpu, &cpus); last_cpu++)
+               if (CPU_ISSET( last_cpu, &cpus) ) 
+                       ncpus = last_cpu;
+       ncpus++;
+       CPU_FREE(cpus);
+#endif
        if (ncpus == 0) {
                fatal(NULL, ERR_SYSCALL, "Insufficient number of CPUs\n");
                /*NOTREACHED*/
@@ -526,25 +542,29 @@ static void get_ncpus(void)
  */
 static void pin_to_cpu(struct thr_info *tip)
 {
-       cpu_set_t cpus;
+       cpu_set_t *cpus;
+       size_t size;
+
+       cpus = CPU_ALLOC(ncpus);
+       size = CPU_ALLOC_SIZE(ncpus);   
 
        assert(0 <= tip->cpu && tip->cpu < ncpus);
 
-       CPU_ZERO(&cpus);
-       CPU_SET(tip->cpu, &cpus);
-       if (sched_setaffinity(getpid(), sizeof(cpus), &cpus)) {
+       CPU_ZERO_S(size, cpus);
+       CPU_SET_S(tip->cpu, size, cpus);
+       if (sched_setaffinity(getpid(), sizecpus)) {
                fatal("sched_setaffinity", ERR_SYSCALL, "Failed to pin CPU\n");
                /*NOTREACHED*/
        }
 
        if (verbose > 1) {
                int i;
-               cpu_set_t now;
+               cpu_set_t *now = CPU_ALLOC(ncpus);
 
-               (void)sched_getaffinity(getpid(), sizeof(now), &now);
+               (void)sched_getaffinity(getpid(), sizenow);
                fprintf(tip->vfp, "Pinned to CPU %02d ", tip->cpu);
                for (i = 0; i < ncpus; i++)
-                       fprintf(tip->vfp, "%1d", CPU_ISSET(i, &now));
+                       fprintf(tip->vfp, "%1d", CPU_ISSET_S(i, size, now));
                fprintf(tip->vfp, "\n");
        }
 }
@@ -595,7 +615,7 @@ static void find_input_devs(char *idir)
        }
 
        while ((ent = readdir(dir)) != NULL) {
-               char *p, *dsf = malloc(256);
+               char *p, *dsf;
 
                if (strstr(ent->d_name, ".replay.") == NULL)
                        continue;
@@ -626,7 +646,7 @@ static void find_input_devs(char *idir)
 static void read_map_devs(char *file_name)
 {
        FILE *fp;
-       char *from_dev, *to_dev;
+       char from_dev[256], to_dev[256];
 
        fp = fopen(file_name, "r");
        if (!fp) {
@@ -634,7 +654,7 @@ static void read_map_devs(char *file_name)
                /*NOTREACHED*/
        }
 
-       while (fscanf(fp, "%as %as", &from_dev, &to_dev) == 2) {
+       while (fscanf(fp, "%s %s", from_dev, to_dev) == 2) {
                struct map_dev *mdp = malloc(sizeof(*mdp));
 
                mdp->from_dev = from_dev;
@@ -1175,6 +1195,8 @@ static void stall(struct thr_info *tip, long long oclock)
        struct timespec req;
        long long dreal, tclock = gettime() - rgenesis;
 
+       oclock /= acc_factor;
+       
        if (verbose > 1)
                fprintf(tip->vfp, "   stall(%lld.%09lld, %lld.%09lld)\n",
                        du64_to_sec(oclock), du64_to_nsec(oclock),
@@ -1311,14 +1333,30 @@ static void reset_input_file(struct thr_info *tip)
  */
 static void *replay_sub(void *arg)
 {
+        unsigned int i;
+       char *mdev;
        char path[MAXPATHLEN];
        struct io_bunch bunch;
        struct thr_info *tip = arg;
+       int oflags;
 
        pin_to_cpu(tip);
 
-       sprintf(path, "/dev/%s", map_dev(tip->devnm));
-       tip->ofd = open(path, O_RDWR | O_DIRECT);
+       mdev = map_dev(tip->devnm);
+       sprintf(path, "/dev/%s", mdev);
+       /*
+        * convert underscores to slashes to
+        * restore device names that have larger paths
+        */
+       for (i = 0; i < strlen(mdev); i++)
+               if (path[strlen("/dev/") + i] == '_')
+                       path[strlen("/dev/") + i] = '/';
+#ifdef O_NOATIME
+       oflags = O_NOATIME;
+#else
+       oflags = 0;
+#endif
+       tip->ofd = open(path, O_RDWR | O_DIRECT | oflags);
        if (tip->ofd < 0) {
                fatal(path, ERR_SYSCALL, "Failed device open\n");
                /*NOTREACHED*/
@@ -1327,7 +1365,7 @@ static void *replay_sub(void *arg)
        set_replay_ready();
        while (!is_send_done(tip) && tip->iterations--) {
                wait_iter_start();
-               if (verbose)
+               if (verbose > 1)
                        fprintf(tip->vfp, "\n=== %d ===\n", tip->iterations);
                while (!is_send_done(tip) && next_bunch(tip, &bunch))
                        process_bunch(tip, &bunch);
@@ -1347,22 +1385,23 @@ static void *replay_sub(void *arg)
  */
 
 static char usage_str[] =                                              \
-        "\n"                                                           \
+        "\n"                                                           \
         "\t[ -c <cpus> : --cpus=<cpus>           ] Default: 1\n"        \
         "\t[ -d <dir>  : --input-directory=<dir> ] Default: .\n"        \
-       "\t[ -F        : --find-records          ] Default: Off\n"         \
+       "\t[ -F        : --find-records          ] Default: Off\n"      \
         "\t[ -h        : --help                  ] Default: Off\n"      \
         "\t[ -i <base> : --input-base=<base>     ] Default: replay\n"   \
         "\t[ -I <iters>: --iterations=<iters>    ] Default: 1\n"        \
         "\t[ -M <file> : --map-devs=<file>       ] Default: None\n"     \
         "\t[ -N        : --no-stalls             ] Default: Off\n"      \
+        "\t[ -x        : --acc-factor            ] Default: 1\n"       \
         "\t[ -v        : --verbose               ] Default: Off\n"      \
         "\t[ -V        : --version               ] Default: Off\n"      \
         "\t[ -W        : --write-enable          ] Default: Off\n"      \
         "\t<dev...>                                Default: None\n"     \
         "\n";
 
-#define S_OPTS "c:d:Fhi:I:M:Nt:vVW"
+#define S_OPTS "c:d:Fhi:I:M:Nx:t:vVW"
 static struct option l_opts[] = {
        {
                .name = "cpus",
@@ -1412,6 +1451,12 @@ static struct option l_opts[] = {
                .flag = NULL,
                .val = 'N'
        },
+       {
+               .name = "acc-factor",
+               .has_arg = required_argument,
+               .flag = NULL,
+               .val = 'x'
+       },
        {
                .name = "verbose",
                .has_arg = no_argument,
@@ -1445,6 +1490,7 @@ static struct option l_opts[] = {
 static void handle_args(int argc, char *argv[])
 {
        int c;
+       int r;
 
        while ((c = getopt_long(argc, argv, S_OPTS, l_opts, NULL)) != -1) {
                switch (c) {
@@ -1499,6 +1545,16 @@ static void handle_args(int argc, char *argv[])
                        no_stalls = 1;
                        break;
 
+               case 'x':
+                       r = sscanf(optarg,"%u",&acc_factor);
+                       if (r!=1) {
+                               fprintf(stderr,
+                                       "Invalid acceleration factor\n");
+                               exit(ERR_ARGS);
+                               /*NOTREACHED*/
+                       }
+                       break;
+
                case 'V':
                        fprintf(stderr, "btreplay -- version %s\n", 
                                my_btversion);