Fixup new and wrong file name behaviour
[fio.git] / init.c
diff --git a/init.c b/init.c
index 888e68b67137f95f5763d232992e07790d2ceaa9..1c62c5ad10af97a2ed1c610323ceccfddde89646 100644 (file)
--- a/init.c
+++ b/init.c
@@ -33,6 +33,7 @@ static int str_cpumask_cb(void *, unsigned int *);
 static int str_fst_cb(void *, const char *);
 static int str_filename_cb(void *, const char *);
 static int str_directory_cb(void *, const char *);
+static int str_opendir_cb(void *, const char *);
 
 #define __stringify_1(x)       #x
 #define __stringify(x)         __stringify_1(x)
@@ -67,6 +68,13 @@ static struct fio_option options[] = {
                .cb     = str_filename_cb,
                .help   = "File(s) to use for the workload",
        },
+       {
+               .name   = "opendir",
+               .type   = FIO_OPT_STR_STORE,
+               .off1   = td_var_offset(opendir),
+               .cb     = str_opendir_cb,
+               .help   = "Recursively add files from this directory and down",
+       },
        {
                .name   = "rw",
                .type   = FIO_OPT_STR,
@@ -74,13 +82,31 @@ static struct fio_option options[] = {
                .help   = "IO direction",
                .def    = "read",
                .posval = {
-                         { .ival = "read", .oval = TD_DDIR_READ },
-                         { .ival = "write", .oval = TD_DDIR_WRITE },
-                         { .ival = "randread", .oval = TD_DDIR_RANDREAD },
-                         { .ival = "randwrite", .oval = TD_DDIR_RANDWRITE },
-                         { .ival = "rw", .oval = TD_DDIR_RW },
-                         { .ival = "randrw", .oval = TD_DDIR_RANDRW },
+                         { .ival = "read",
+                           .oval = TD_DDIR_READ,
+                           .help = "Sequential read",
+                         },
+                         { .ival = "write",
+                           .oval = TD_DDIR_WRITE,
+                           .help = "Sequential write",
+                         },
+                         { .ival = "randread",
+                           .oval = TD_DDIR_RANDREAD,
+                           .help = "Random read",
+                         },
+                         { .ival = "randwrite",
+                           .oval = TD_DDIR_RANDWRITE,
+                           .help = "Random write",
+                         },
+                         { .ival = "rw",
+                           .oval = TD_DDIR_RW,
+                           .help = "Sequential read and write mix",
                          },
+                         { .ival = "randrw",
+                           .oval = TD_DDIR_RANDRW,
+                           .help = "Random read and write mix"
+                         },
+               },
        },
        {
                .name   = "ioengine",
@@ -89,27 +115,50 @@ static struct fio_option options[] = {
                .help   = "IO engine to use",
                .def    = "sync",
                .posval = {
-                         { .ival = "sync", },
+                         { .ival = "sync",
+                           .help = "Use read/write",
+                         },
 #ifdef FIO_HAVE_LIBAIO
-                         { .ival = "libaio", },
+                         { .ival = "libaio",
+                           .help = "Linux native asynchronous IO",
+                         },
 #endif
 #ifdef FIO_HAVE_POSIXAIO
-                         { .ival = "posixaio", },
+                         { .ival = "posixaio",
+                           .help = "POSIX asynchronous IO",
+                         },
 #endif
-                         { .ival = "mmap", },
+                         { .ival = "mmap",
+                           .help = "Memory mapped IO",
+                         },
 #ifdef FIO_HAVE_SPLICE
-                         { .ival = "splice", },
+                         { .ival = "splice",
+                           .help = "splice/vmsplice based IO",
+                         },
 #endif
 #ifdef FIO_HAVE_SGIO
-                         { .ival = "sg", },
+                         { .ival = "sg",
+                           .help = "SCSI generic v3 IO",
+                         },
 #endif
-                         { .ival = "null", }, { .ival = "net", },
+                         { .ival = "null",
+                           .help = "Testing engine (no data transfer)",
+                         },
+                         { .ival = "net",
+                           .help = "Network IO",
+                         },
 #ifdef FIO_HAVE_SYSLET
-                         { .ival = "syslet-rw", },
+                         { .ival = "syslet-rw",
+                           .help = "syslet enabled async pread/pwrite IO",
+                         },
 #endif
-                         { .ival = "cpuio", },
-                         { .ival = "external", },
+                         { .ival = "cpuio",
+                           .help = "CPU cycler burner engine",
+                         },
+                         { .ival = "external",
+                           .help = "Load external engine (append name)",
                          },
+               },
        },
        {
                .name   = "iodepth",
@@ -200,9 +249,15 @@ static struct fio_option options[] = {
                .help   = "How to select which file to service next",
                .def    = "roundrobin",
                .posval = {
-                         { .ival = "random", .oval = FIO_FSERVICE_RANDOM },
-                         { .ival = "roundrobin", .oval = FIO_FSERVICE_RR },
+                         { .ival = "random",
+                           .oval = FIO_FSERVICE_RANDOM,
+                           .help = "Choose a file at random",
                          },
+                         { .ival = "roundrobin",
+                           .oval = FIO_FSERVICE_RR,
+                           .help = "Round robin select files",
+                         },
+               },
        },
        {
                .name   = "fsync",
@@ -270,28 +325,52 @@ static struct fio_option options[] = {
                .help   = "Backing type for IO buffers",
                .def    = "malloc",
                .posval = {
-                         { .ival = "malloc", .oval = MEM_MALLOC },
-                         { .ival = "shm", .oval = MEM_SHM },
+                         { .ival = "malloc",
+                           .oval = MEM_MALLOC,
+                           .help = "Use malloc(3) for IO buffers",
+                         },
+                         { .ival = "shm",
+                           .oval = MEM_SHM,
+                           .help = "Use shared memory segments for IO buffers",
+                         },
 #ifdef FIO_HAVE_HUGETLB
-                         { .ival = "shmhuge", .oval = MEM_SHMHUGE },
+                         { .ival = "shmhuge",
+                           .oval = MEM_SHMHUGE,
+                           .help = "Like shm, but use huge pages",
+                         },
 #endif
-                         { .ival = "mmap", .oval = MEM_MMAP },
+                         { .ival = "mmap",
+                           .oval = MEM_MMAP,
+                           .help = "Use mmap(2) (file or anon) for IO buffers",
+                         },
 #ifdef FIO_HAVE_HUGETLB
-                         { .ival = "mmaphuge", .oval = MEM_MMAPHUGE },
-#endif
+                         { .ival = "mmaphuge",
+                           .oval = MEM_MMAPHUGE,
+                           .help = "Like mmap, but use huge pages",
                          },
+#endif
+                 },
        },
        {
                .name   = "verify",
                .type   = FIO_OPT_STR,
                .off1   = td_var_offset(verify),
-               .help   = "Verify sum function",
+               .help   = "Verify data written",
                .def    = "0",
                .posval = {
-                         { .ival = "0", .oval = VERIFY_NONE },
-                         { .ival = "crc32", .oval = VERIFY_CRC32 },
-                         { .ival = "md5", .oval = VERIFY_MD5 },
+                         { .ival = "0",
+                           .oval = VERIFY_NONE,
+                           .help = "Don't do IO verification",
+                         },
+                         { .ival = "crc32",
+                           .oval = VERIFY_CRC32,
+                           .help = "Use crc32 checksums for verification",
+                         },
+                         { .ival = "md5",
+                           .oval = VERIFY_MD5,
+                           .help = "Use md5 checksums for verification",
                          },
+               },
        },
        {
                .name   = "write_iolog",
@@ -499,6 +578,13 @@ static struct fio_option options[] = {
                .help   = "Include fsync at the end of job",
                .def    = "0",
        },
+       {
+               .name   = "fsync_on_close",
+               .type   = FIO_OPT_BOOL,
+               .off1   = td_var_offset(fsync_on_close),
+               .help   = "fsync files on close",
+               .def    = "0",
+       },
        {
                .name   = "unlink",
                .type   = FIO_OPT_BOOL,
@@ -610,7 +696,7 @@ static struct option long_options[FIO_JOB_OPTS + FIO_CMD_OPTS] = {
 
 static int def_timeout = 0;
 
-static char fio_version_string[] = "fio 1.13";
+static char fio_version_string[] = "fio 1.14";
 
 static char **ini_file;
 static int max_jobs = MAX_JOBS;
@@ -752,9 +838,10 @@ static void fixup_options(struct thread_data *td)
        if (td->iodepth_batch > td->iodepth || !td->iodepth_batch)
                td->iodepth_batch = td->iodepth;
 
-       if (!td->nr_files)
-               td->nr_files = td->open_files;
-       else if (td->open_files > td->nr_files || !td->open_files)
+       if (td->nr_files > td->files_index)
+               td->nr_files = td->files_index;
+
+       if (td->open_files > td->nr_files || !td->open_files)
                td->open_files = td->nr_files;
 }
 
@@ -793,6 +880,19 @@ static const char *get_engine_name(const char *str)
        return p;
 }
 
+static int exists_and_not_file(const char *filename)
+{
+       struct stat sb;
+
+       if (lstat(filename, &sb) == -1)
+               return 0;
+
+       if (S_ISREG(sb.st_mode))
+               return 0;
+
+       return 1;
+}
+
 /*
  * Adds a job to the list of things todo. Sanitizes the various options
  * to make sure we don't have conflicts, and initializes various
@@ -806,7 +906,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num)
        struct fio_file *f;
        const char *engine;
        char fname[PATH_MAX];
-       int numjobs;
+       int numjobs, file_alloced;
 
        /*
         * the def_thread is just for options, it's not a real job
@@ -829,14 +929,15 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num)
        if (td->odirect)
                td->io_ops->flags |= FIO_RAWIO;
 
-       if (!td->filename) {
-               td->filename = strdup(jobname);
+       file_alloced = 0;
+       if (!td->filename && !td->files_index) {
+               file_alloced = 1;
 
-               if (td->nr_files == 1)
-                       add_file(td, td->filename);
+               if (td->nr_files == 1 && exists_and_not_file(jobname))
+                       add_file(td, jobname);
                else {
                        for (i = 0; i < td->nr_files; i++) {
-                               sprintf(fname, "%s.%d.%d", td->filename, td->thread_number, i);
+                               sprintf(fname, "%s.%d.%d", jobname, td->thread_number, i);
                                add_file(td, fname);
                        }
                }
@@ -849,9 +950,6 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num)
                        sprintf(fname, "%s/%s", td->directory, f->file_name);
                        f->file_name = strdup(fname);
                }
-
-               f->file_size = td->total_file_size / td->nr_files;
-               f->file_offset = td->start_offset;
        }
                
        td->mutex = fio_sem_init(0);
@@ -917,6 +1015,13 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num)
 
                td_new->numjobs = 1;
                td_new->stonewall = 0;
+
+               if (file_alloced) {
+                       td_new->filename = NULL;
+                       td_new->files_index = 0;
+                       td_new->files = NULL;
+               }
+
                job_add_num = numjobs - 1;
 
                if (add_job(td_new, jobname, job_add_num))
@@ -1109,12 +1214,14 @@ static int str_filename_cb(void *data, const char *input)
        struct thread_data *td = data;
        char *fname, *str, *p;
 
-       td->nr_files = 0;
        p = str = strdup(input);
 
        strip_blank_front(&str);
        strip_blank_end(str);
 
+       if (!td->files_index)
+               td->nr_files = 0;
+
        while ((fname = strsep(&str, ":")) != NULL) {
                if (!strlen(fname))
                        break;
@@ -1144,6 +1251,16 @@ static int str_directory_cb(void *data, const char fio_unused *str)
        return 0;
 }
 
+static int str_opendir_cb(void *data, const char fio_unused *str)
+{
+       struct thread_data *td = data;
+
+       if (!td->files_index)
+               td->nr_files = 0;
+
+       return add_dir_files(td, td->opendir);
+}
+
 /*
  * This is our [ini] type file parser.
  */