init: set fail error return on bad parse
[fio.git] / init.c
diff --git a/init.c b/init.c
index 8268ed59e99668216fdee94a1a921ef0ae319bce..861b1f5fd0f466d35dfd9a12ed606b80f98e0b1d 100644 (file)
--- a/init.c
+++ b/init.c
@@ -380,6 +380,7 @@ static struct thread_data *get_new_job(int global, struct thread_data *parent,
        profile_add_hooks(td);
 
        td->thread_number = thread_number;
+       td->subjob_number = 0;
 
        if (jobname)
                td->o.name = strdup(jobname);
@@ -635,6 +636,15 @@ static int fixup_options(struct thread_data *td)
                if (o->max_bs[DDIR_WRITE] != o->min_bs[DDIR_WRITE] &&
                    !o->verify_interval)
                        o->verify_interval = o->min_bs[DDIR_WRITE];
+
+               /*
+                * Verify interval must be smaller or equal to the
+                * write size.
+                */
+               if (o->verify_interval > o->min_bs[DDIR_WRITE])
+                       o->verify_interval = o->min_bs[DDIR_WRITE];
+               else if (td_read(td) && o->verify_interval > o->min_bs[DDIR_READ])
+                       o->verify_interval = o->min_bs[DDIR_READ];
        }
 
        if (o->pre_read) {
@@ -826,7 +836,9 @@ static void td_fill_rand_seeds_internal(struct thread_data *td)
 void td_fill_rand_seeds(struct thread_data *td)
 {
        if (td->o.allrand_repeatable) {
-               for (int i = 0; i < FIO_RAND_NR_OFFS; i++)
+               unsigned int i;
+
+               for (i = 0; i < FIO_RAND_NR_OFFS; i++)
                        td->rand_seeds[i] = FIO_RANDSEED * td->thread_number
                                + i;
        }
@@ -837,6 +849,9 @@ void td_fill_rand_seeds(struct thread_data *td)
                td_fill_rand_seeds_internal(td);
 
        init_rand_seed(&td->buf_state, td->rand_seeds[FIO_RAND_BUF_OFF]);
+       frand_copy(&td->buf_state_prev, &td->buf_state);
+
+       init_rand_seed(&td->dedupe_state, td->rand_seeds[FIO_DEDUPE_OFF]);
 }
 
 /*
@@ -1167,14 +1182,14 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                else
                        suf = "log";
 
-               snprintf(logname, sizeof(logname), "%s_lat.%s",
-                               o->lat_log_file, suf);
+               snprintf(logname, sizeof(logname), "%s_lat.%d.%s",
+                               o->lat_log_file, td->thread_number, suf);
                setup_log(&td->lat_log, &p, logname);
-               snprintf(logname, sizeof(logname), "%s_slat.%s",
-                               o->lat_log_file, suf);
+               snprintf(logname, sizeof(logname), "%s_slat.%d.%s",
+                               o->lat_log_file, td->thread_number, suf);
                setup_log(&td->slat_log, &p, logname);
-               snprintf(logname, sizeof(logname), "%s_clat.%s",
-                               o->lat_log_file, suf);
+               snprintf(logname, sizeof(logname), "%s_clat.%d.%s",
+                               o->lat_log_file, td->thread_number, suf);
                setup_log(&td->clat_log, &p, logname);
        }
        if (o->bw_log_file) {
@@ -1193,8 +1208,8 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                else
                        suf = "log";
 
-               snprintf(logname, sizeof(logname), "%s_bw.%s",
-                               o->bw_log_file, suf);
+               snprintf(logname, sizeof(logname), "%s_bw.%d.%s",
+                               o->bw_log_file, td->thread_number, suf);
                setup_log(&td->bw_log, &p, logname);
        }
        if (o->iops_log_file) {
@@ -1213,8 +1228,8 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                else
                        suf = "log";
 
-               snprintf(logname, sizeof(logname), "%s_iops.%s",
-                               o->iops_log_file, suf);
+               snprintf(logname, sizeof(logname), "%s_iops.%d.%s",
+                               o->iops_log_file, td->thread_number, suf);
                setup_log(&td->iops_log, &p, logname);
        }
 
@@ -1279,6 +1294,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                td_new->o.numjobs = 1;
                td_new->o.stonewall = 0;
                td_new->o.new_group = 0;
+               td_new->subjob_number = numjobs;
 
                if (file_alloced) {
                        if (td_new->files) {
@@ -1381,11 +1397,12 @@ static int is_empty_or_comment(char *line)
 /*
  * This is our [ini] type file parser.
  */
-int parse_jobs_ini(char *file, int is_buf, int stonewall_flag, int type)
+int __parse_jobs_ini(struct thread_data *td,
+               char *file, int is_buf, int stonewall_flag, int type,
+               int nested, char *name, char ***popts, int *aopts, int *nopts)
 {
-       unsigned int global;
-       struct thread_data *td;
-       char *string, *name;
+       unsigned int global = 0;
+       char *string;
        FILE *f;
        char *p;
        int ret = 0, stonewall;
@@ -1395,6 +1412,9 @@ int parse_jobs_ini(char *file, int is_buf, int stonewall_flag, int type)
        char **opts;
        int i, alloc_opts, num_opts;
 
+       dprint(FD_PARSE, "Parsing ini file %s\n", file);
+       assert(td || !nested);
+
        if (is_buf)
                f = NULL;
        else {
@@ -1414,12 +1434,23 @@ int parse_jobs_ini(char *file, int is_buf, int stonewall_flag, int type)
        /*
         * it's really 256 + small bit, 280 should suffice
         */
-       name = malloc(280);
-       memset(name, 0, 280);
+       if (!nested) {
+               name = malloc(280);
+               memset(name, 0, 280);
+       }
+
+       opts = NULL;
+       if (nested && popts) {
+               opts = *popts;
+               alloc_opts = *aopts;
+               num_opts = *nopts;
+       }
 
-       alloc_opts = 8;
-       opts = malloc(sizeof(char *) * alloc_opts);
-       num_opts = 0;
+       if (!opts) {
+               alloc_opts = 8;
+               opts = malloc(sizeof(char *) * alloc_opts);
+               num_opts = 0;
+       }
 
        stonewall = stonewall_flag;
        do {
@@ -1440,58 +1471,73 @@ int parse_jobs_ini(char *file, int is_buf, int stonewall_flag, int type)
                strip_blank_front(&p);
                strip_blank_end(p);
 
+               dprint(FD_PARSE, "%s\n", p);
                if (is_empty_or_comment(p))
                        continue;
-               if (sscanf(p, "[%255[^\n]]", name) != 1) {
-                       if (inside_skip)
+
+               if (!nested) {
+                       if (sscanf(p, "[%255[^\n]]", name) != 1) {
+                               if (inside_skip)
+                                       continue;
+
+                               log_err("fio: option <%s> outside of "
+                                       "[] job section\n", p);
+                               ret = 1;
+                               break;
+                       }
+
+                       name[strlen(name) - 1] = '\0';
+
+                       if (skip_this_section(name)) {
+                               inside_skip = 1;
                                continue;
-                       log_err("fio: option <%s> outside of [] job section\n",
-                                                                       p);
-                       break;
-               }
+                       } else
+                               inside_skip = 0;
 
-               name[strlen(name) - 1] = '\0';
+                       dprint(FD_PARSE, "Parsing section [%s]\n", name);
 
-               if (skip_this_section(name)) {
-                       inside_skip = 1;
-                       continue;
-               } else
-                       inside_skip = 0;
+                       global = !strncmp(name, "global", 6);
 
-               global = !strncmp(name, "global", 6);
+                       if (dump_cmdline) {
+                               if (first_sect)
+                                       log_info("fio ");
+                               if (!global)
+                                       log_info("--name=%s ", name);
+                               first_sect = 0;
+                       }
 
-               if (dump_cmdline) {
-                       if (first_sect)
-                               log_info("fio ");
-                       if (!global)
-                               log_info("--name=%s ", name);
-                       first_sect = 0;
-               }
+                       td = get_new_job(global, &def_thread, 0, name);
+                       if (!td) {
+                               ret = 1;
+                               break;
+                       }
 
-               td = get_new_job(global, &def_thread, 0, name);
-               if (!td) {
-                       ret = 1;
-                       break;
-               }
+                       /*
+                        * Separate multiple job files by a stonewall
+                        */
+                       if (!global && stonewall) {
+                               td->o.stonewall = stonewall;
+                               stonewall = 0;
+                       }
 
-               /*
-                * Separate multiple job files by a stonewall
-                */
-               if (!global && stonewall) {
-                       td->o.stonewall = stonewall;
-                       stonewall = 0;
+                       num_opts = 0;
+                       memset(opts, 0, alloc_opts * sizeof(char *));
                }
-
-               num_opts = 0;
-               memset(opts, 0, alloc_opts * sizeof(char *));
+               else
+                       skip_fgets = 1;
 
                while (1) {
-                       if (is_buf)
-                               p = strsep(&file, "\n");
+                       if (!skip_fgets) {
+                               if (is_buf)
+                                       p = strsep(&file, "\n");
+                               else
+                                       p = fgets(string, 4096, f);
+                               if (!p)
+                                       break;
+                               dprint(FD_PARSE, "%s", p);
+                       }
                        else
-                               p = fgets(string, 4096, f);
-                       if (!p)
-                               break;
+                               skip_fgets = 0;
 
                        if (is_empty_or_comment(p))
                                continue;
@@ -1503,12 +1549,30 @@ int parse_jobs_ini(char *file, int is_buf, int stonewall_flag, int type)
                         * fgets() a new line at the top.
                         */
                        if (p[0] == '[') {
+                               if (nested) {
+                                       log_err("No new sections in included files\n");
+                                       return 1;
+                               }
+
                                skip_fgets = 1;
                                break;
                        }
 
                        strip_blank_end(p);
 
+                       if (!strncmp(p, "include", strlen("include"))) {
+                               char *filename = p + strlen("include") + 1;
+
+                               if ((ret = __parse_jobs_ini(td, filename,
+                                               is_buf, stonewall_flag, type, 1,
+                                               name, &opts, &alloc_opts, &num_opts))) {
+                                       log_err("Error %d while parsing include file %s\n",
+                                               ret, filename);
+                                       break;
+                               }
+                               continue;
+                       }
+
                        if (num_opts == alloc_opts) {
                                alloc_opts <<= 1;
                                opts = realloc(opts,
@@ -1519,6 +1583,13 @@ int parse_jobs_ini(char *file, int is_buf, int stonewall_flag, int type)
                        num_opts++;
                }
 
+               if (nested) {
+                       *popts = opts;
+                       *aopts = alloc_opts;
+                       *nopts = num_opts;
+                       goto out;
+               }
+
                ret = fio_options_parse(td, opts, num_opts, dump_cmdline);
                if (!ret)
                        ret = add_job(td, name, 0, 0, type);
@@ -1541,14 +1612,22 @@ int parse_jobs_ini(char *file, int is_buf, int stonewall_flag, int type)
                i++;
        }
 
-       free(string);
-       free(name);
        free(opts);
+out:
+       free(string);
+       if (!nested)
+               free(name);
        if (!is_buf && f != stdin)
                fclose(f);
        return ret;
 }
 
+int parse_jobs_ini(char *file, int is_buf, int stonewall_flag, int type)
+{
+       return __parse_jobs_ini(NULL, file, is_buf, stonewall_flag, type,
+                       0, NULL, NULL, NULL, NULL);
+}
+
 static int fill_def_thread(void)
 {
        memset(&def_thread, 0, sizeof(def_thread));
@@ -1569,7 +1648,7 @@ static void usage(const char *name)
        printf("%s [options] [job options] <job file(s)>\n", name);
        printf("  --debug=options\tEnable debug logging. May be one/more of:\n"
                "\t\t\tprocess,file,io,mem,blktrace,verify,random,parse,\n"
-               "\t\t\tdiskutil,job,mutex,profile,time,net,rate\n");
+               "\t\t\tdiskutil,job,mutex,profile,time,net,rate,compress\n");
        printf("  --parse-only\t\tParse options only, don't start any IO\n");
        printf("  --output\t\tWrite output to file\n");
        printf("  --runtime\t\tRuntime in seconds\n");
@@ -1677,6 +1756,10 @@ struct debug_level debug_levels[] = {
          .help = "Rate logging",
          .shift = FD_RATE,
        },
+       { .name = "compress",
+         .help = "Log compression logging",
+         .shift = FD_COMPRESS,
+       },
        { .name = NULL, },
 };