Merge branch 'master' of git://github.com/cvubrugier/fio
authorJens Axboe <axboe@fb.com>
Mon, 19 May 2014 15:50:54 +0000 (09:50 -0600)
committerJens Axboe <axboe@fb.com>
Mon, 19 May 2014 15:50:54 +0000 (09:50 -0600)
51 files changed:
FIO-VERSION-GEN
HOWTO
Makefile
arch/arch-s390.h
backend.c
blktrace.c
cconv.c
client.c
configure
crc/test.c
diskutil.c
diskutil.h
engines/binject.c
engines/cpu.c
engines/e4defrag.c
engines/gfapi.h [new file with mode: 0644]
engines/glusterfs.c [new file with mode: 0644]
engines/glusterfs_async.c [new file with mode: 0644]
engines/glusterfs_sync.c [new file with mode: 0644]
engines/net.c
engines/rbd.c
engines/sg.c
eta.c
filesetup.c
fio.1
fio.h
fio_time.h [new file with mode: 0644]
gclient.c
gettime.c
idletime.c
init.c
io_u.c
ioengines.c
iolog.c
iolog.h
lib/num2str.c
libfio.c
memory.c
mutex.c
options.c
options.h
os/os.h
os/windows/install.wxs
os/windows/posix/include/sys/un.h
parse.c
server.c
server.h
stat.c
thread_options.h
time.h [deleted file]
verify.c

index 918a9dfac016b99168f174b1e6b6458b337680c9..4cb3545ea89e88bc47ed0968ea43fdf2136c3d62 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=FIO-VERSION-FILE
-DEF_VER=fio-2.1.7
+DEF_VER=fio-2.1.9
 
 LF='
 '
diff --git a/HOWTO b/HOWTO
index 7db7b8929a21a46b971bb9a45f5a774e721f96a1..1c89d75f29cf6a01264d9f6dbbaaefc9b529a9e8 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -430,6 +430,14 @@ size=int   The total size of file io for this job. Fio will run until
                is given, fio will use 20% of the full size of the given
                files or devices.
 
+io_limit=int   Normally fio operates within the region set by 'size', which
+               means that the 'size' option sets both the region and size of
+               IO to be performed. Sometimes that is not what you want. With
+               this option, it is possible to define just the amount of IO
+               that fio should do. For instance, if 'size' is set to 20G and
+               'io_limit' is set to 5G, fio will perform IO within the first
+               20G but exit when 5G have been done.
+
 filesize=int   Individual file sizes. May be a range, in which case fio
                will select sizes for files at random within the given range
                and limited to 'size' in total (if that is given). If not
@@ -1505,6 +1513,8 @@ that defines them is selected.
 [cpu] cpuchunks=int Split the load into cycles of the given time. In
                microseconds.
 
+[cpu] exit_on_io_done=bool Detect when IO threads are done, then exit.
+
 [netsplice] hostname=str
 [net] hostname=str The host name or IP address to use for TCP or UDP based IO.
                If the job is a TCP listener or UDP reader, the hostname is not
index 3c9e0ee467fe72256f8d0cd2916d62ec7a603d64..59fae9c1d7433e9f3d696cb1a5d938d92f5c1a0d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,7 @@ include config-host.mak
 endif
 
 DEBUGFLAGS = -D_FORTIFY_SOURCE=2 -DFIO_INC_DEBUG
-CPPFLAGS= -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 $(DEBUGFLAGS)
+CPPFLAGS= -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -DFIO_INTERNAL $(DEBUGFLAGS)
 OPTFLAGS= -O3 -g -ffast-math
 CFLAGS = -std=gnu99 -Wwrite-strings -Wall -Wdeclaration-after-statement $(OPTFLAGS) $(EXTFLAGS) $(BUILD_CFLAGS)
 LIBS   += -lm $(EXTLIBS)
@@ -91,6 +91,14 @@ endif
 ifndef CONFIG_INET_ATON
   SOURCE += lib/inet_aton.c
 endif
+ifdef CONFIG_GFAPI
+  SOURCE += engines/glusterfs.c
+  SOURCE += engines/glusterfs_sync.c
+  SOURCE += engines/glusterfs_async.c
+  ifdef CONFIG_GF_FADVISE
+    CFLAGS += "-DGFAPI_USE_FADVISE"
+  endif
+endif
 
 ifeq ($(CONFIG_TARGET_OS), Linux)
   SOURCE += diskutil.c fifo.c blktrace.c cgroup.c trim.c engines/sg.c \
@@ -274,7 +282,7 @@ t/lfsr-test: $(T_LFSR_TEST_OBJS)
        $(QUIET_LINK)$(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(T_LFSR_TEST_OBJS) $(LIBS)
 
 clean: FORCE
-       -rm -f .depend $(FIO_OBJS) $(GFIO_OBJS) $(OBJS) $(T_OBJS) $(PROGS) $(T_PROGS) core.* core gfio FIO-VERSION-FILE *.d config-host.mak config-host.h
+       -rm -f .depend $(FIO_OBJS) $(GFIO_OBJS) $(OBJS) $(T_OBJS) $(PROGS) $(T_PROGS) core.* core gfio FIO-VERSION-FILE *.d lib/*.d crc/*.d engines/*.d profiles/*.d t/*.d config-host.mak config-host.h
 
 distclean: clean FORCE
        @rm -f cscope.out fio.pdf fio_generate_plots.pdf fio2gnuplot.pdf
index bcd91636d04d8e6e3bd2137672377f84813cd57e..169282b9d4d308de3e3ca23aa6ba5be7c46613e1 100644 (file)
@@ -18,7 +18,7 @@
 #define __NR_sys_vmsplice      309
 #endif
 
-#define nop            asm volatile ("diag 0,0,68" : : : "memory")
+#define nop            asm volatile("nop" : : : "memory")
 #define read_barrier() asm volatile("bcr 15,0" : : : "memory")
 #define write_barrier()        asm volatile("bcr 15,0" : : : "memory")
 
@@ -26,10 +26,21 @@ static inline unsigned long long get_cpu_clock(void)
 {
        unsigned long long clk;
 
+#ifdef CONFIG_S390_Z196_FACILITIES
+       /*
+        * Fio needs monotonic (never lower), but not strict monotonic (never
+        * the same) so store clock fast is enough.
+        */
+       __asm__ __volatile__("stckf %0" : "=Q" (clk) : : "cc");
+#else
        __asm__ __volatile__("stck %0" : "=Q" (clk) : : "cc");
-       return clk;
+#endif
+       return clk>>12;
 }
 
+#define ARCH_CPU_CLOCK_CYCLES_PER_USEC 1
+#define ARCH_HAVE_CPU_CLOCK
+
 #define ARCH_HAVE_INIT
 extern int tsc_reliable;
 static inline int arch_init(char *envp[])
@@ -38,6 +49,4 @@ static inline int arch_init(char *envp[])
        return 0;
 }
 
-#define ARCH_HAVE_CPU_CLOCK
-
 #endif
index 5ac365925fdd469a948643bd9ed14bc9759b3f94..d1d55718b32ecb76009c6adc3484decee2f3a626 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -182,7 +182,11 @@ static int __check_min_rate(struct thread_data *td, struct timeval *now,
                                                                ratemin);
                                return 1;
                        } else {
-                               rate = ((bytes - td->rate_bytes[ddir]) * 1000) / spent;
+                               if (spent)
+                                       rate = ((bytes - td->rate_bytes[ddir]) * 1000) / spent;
+                               else
+                                       rate = 0;
+
                                if (rate < ratemin ||
                                    bytes < td->rate_bytes[ddir]) {
                                        log_err("%s: min rate %u not met, got"
@@ -200,7 +204,11 @@ static int __check_min_rate(struct thread_data *td, struct timeval *now,
                                                td->o.name, rate_iops);
                                return 1;
                        } else {
-                               rate = ((iops - td->rate_blocks[ddir]) * 1000) / spent;
+                               if (spent)
+                                       rate = ((iops - td->rate_blocks[ddir]) * 1000) / spent;
+                               else
+                                       rate = 0;
+
                                if (rate < rate_iops_min ||
                                    iops < td->rate_blocks[ddir]) {
                                        log_err("%s: min iops rate %u not met,"
@@ -637,7 +645,7 @@ static unsigned int exceeds_number_ios(struct thread_data *td)
 
 static int io_bytes_exceeded(struct thread_data *td)
 {
-       unsigned long long bytes;
+       unsigned long long bytes, limit;
 
        if (td_rw(td))
                bytes = td->this_io_bytes[DDIR_READ] + td->this_io_bytes[DDIR_WRITE];
@@ -648,7 +656,12 @@ static int io_bytes_exceeded(struct thread_data *td)
        else
                bytes = td->this_io_bytes[DDIR_TRIM];
 
-       return bytes >= td->o.size || exceeds_number_ios(td);
+       if (td->o.io_limit)
+               limit = td->o.io_limit;
+       else
+               limit = td->o.size;
+
+       return bytes >= limit || exceeds_number_ios(td);
 }
 
 /*
@@ -767,16 +780,21 @@ static uint64_t do_io(struct thread_data *td)
                case FIO_Q_COMPLETED:
                        if (io_u->error) {
                                ret = -io_u->error;
+                               unlog_io_piece(td, io_u);
                                clear_io_u(td, io_u);
                        } else if (io_u->resid) {
                                int bytes = io_u->xfer_buflen - io_u->resid;
                                struct fio_file *f = io_u->file;
 
                                bytes_issued += bytes;
+
+                               trim_io_piece(td, io_u);
+
                                /*
                                 * zero read, fail
                                 */
                                if (!bytes) {
+                                       unlog_io_piece(td, io_u);
                                        td_verror(td, EIO, "full resid");
                                        put_io_u(td, io_u);
                                        break;
@@ -817,6 +835,7 @@ sync_done:
                        bytes_issued += io_u->xfer_buflen;
                        break;
                case FIO_Q_BUSY:
+                       unlog_io_piece(td, io_u);
                        requeue_io_u(td, &io_u);
                        ret2 = td_io_commit(td);
                        if (ret2 < 0)
@@ -1110,12 +1129,14 @@ static int switch_ioscheduler(struct thread_data *td)
        /*
         * Read back and check that the selected scheduler is now the default.
         */
-       ret = fread(tmp, 1, sizeof(tmp), f);
+       ret = fread(tmp, sizeof(tmp), 1, f);
        if (ferror(f) || ret < 0) {
                td_verror(td, errno, "fread");
                fclose(f);
                return 1;
        }
+       tmp[sizeof(tmp) - 1] = '\0';
+
 
        sprintf(tmp2, "[%s]", td->o.ioscheduler);
        if (!strstr(tmp, tmp2)) {
@@ -1131,6 +1152,8 @@ static int switch_ioscheduler(struct thread_data *td)
 
 static int keep_running(struct thread_data *td)
 {
+       unsigned long long limit;
+
        if (td->done)
                return 0;
        if (td->o.time_based)
@@ -1142,14 +1165,19 @@ static int keep_running(struct thread_data *td)
        if (exceeds_number_ios(td))
                return 0;
 
-       if (td->o.size != -1ULL && ddir_rw_sum(td->io_bytes) < td->o.size) {
+       if (td->o.io_limit)
+               limit = td->o.io_limit;
+       else
+               limit = td->o.size;
+
+       if (limit != -1ULL && ddir_rw_sum(td->io_bytes) < limit) {
                uint64_t diff;
 
                /*
                 * If the difference is less than the minimum IO size, we
                 * are done.
                 */
-               diff = td->o.size - ddir_rw_sum(td->io_bytes);
+               diff = limit - ddir_rw_sum(td->io_bytes);
                if (diff < td_max_bs(td))
                        return 0;
 
@@ -1317,6 +1345,7 @@ static void *thread_main(void *data)
 #ifdef CONFIG_LIBNUMA
        /* numa node setup */
        if (o->numa_cpumask_set || o->numa_memmask_set) {
+               struct bitmask *mask;
                int ret;
 
                if (numa_available() < 0) {
@@ -1325,7 +1354,9 @@ static void *thread_main(void *data)
                }
 
                if (o->numa_cpumask_set) {
-                       ret = numa_run_on_node_mask(o->numa_cpunodesmask);
+                       mask = numa_parse_nodestring(o->numa_cpunodes);
+                       ret = numa_run_on_node_mask(mask);
+                       numa_free_nodemask(mask);
                        if (ret == -1) {
                                td_verror(td, errno, \
                                        "numa_run_on_node_mask failed\n");
@@ -1335,12 +1366,16 @@ static void *thread_main(void *data)
 
                if (o->numa_memmask_set) {
 
+                       mask = NULL;
+                       if (o->numa_memnodes)
+                               mask = numa_parse_nodestring(o->numa_memnodes);
+
                        switch (o->numa_mem_mode) {
                        case MPOL_INTERLEAVE:
-                               numa_set_interleave_mask(o->numa_memnodesmask);
+                               numa_set_interleave_mask(mask);
                                break;
                        case MPOL_BIND:
-                               numa_set_membind(o->numa_memnodesmask);
+                               numa_set_membind(mask);
                                break;
                        case MPOL_LOCAL:
                                numa_set_localalloc();
@@ -1353,6 +1388,9 @@ static void *thread_main(void *data)
                                break;
                        }
 
+                       if (mask)
+                               numa_free_nodemask(mask);
+
                }
        }
 #endif
index 4b5567effe6ab2624079df36284df4ad524d0f19..29eed50c391c422da566eb063cb2bc4863bd19a1 100644 (file)
@@ -150,7 +150,7 @@ static int lookup_device(struct thread_data *td, char *path, unsigned int maj,
                 */
                if (td->o.replay_redirect) {
                        dprint(FD_BLKTRACE, "device lookup: %d/%d\n overridden"
-                                       " with: %s", maj, min,
+                                       " with: %s\n", maj, min,
                                        td->o.replay_redirect);
                        strcpy(path, td->o.replay_redirect);
                        found = 1;
@@ -217,6 +217,7 @@ static int trace_add_file(struct thread_data *td, __u32 device)
 
                dprint(FD_BLKTRACE, "add devices %s\n", dev);
                fileno = add_file_exclusive(td, dev);
+               td->o.open_files++;
                td->files[fileno]->major = maj;
                td->files[fileno]->minor = min;
                trace_add_open_close_event(td, fileno, FIO_LOG_OPEN_FILE);
@@ -373,6 +374,7 @@ int load_blktrace(struct thread_data *td, const char *filename, int need_swap)
        struct fifo *fifo;
        int fd, i, old_state;
        struct fio_file *f;
+       int this_depth, depth;
 
        fd = open(filename, O_RDONLY);
        if (fd < 0) {
@@ -391,6 +393,7 @@ int load_blktrace(struct thread_data *td, const char *filename, int need_swap)
        ios[0] = ios[1] = 0;
        rw_bs[0] = rw_bs[1] = 0;
        skipped_writes = 0;
+       this_depth = depth = 0;
        do {
                int ret = trace_fifo_get(td, fifo, fd, &t, sizeof(t));
 
@@ -425,6 +428,12 @@ int load_blktrace(struct thread_data *td, const char *filename, int need_swap)
                        goto err;
                }
                if ((t.action & BLK_TC_ACT(BLK_TC_NOTIFY)) == 0) {
+                       if ((t.action & 0xffff) == __BLK_TA_QUEUE)
+                               this_depth++;
+                       else if ((t.action & 0xffff) == __BLK_TA_COMPLETE) {
+                               depth = max(depth, this_depth);
+                               this_depth = 0;
+                       }
                        if (!ttime) {
                                ttime = t.time;
                                cpu = t.cpu;
@@ -469,6 +478,13 @@ int load_blktrace(struct thread_data *td, const char *filename, int need_swap)
                return 1;
        }
 
+       /*
+        * For stacked devices, we don't always get a COMPLETE event so
+        * the depth grows to insane values. Limit it to something sane(r).
+        */
+       if (!depth || depth > 1024)
+               depth = 1024;
+
        if (skipped_writes)
                log_err("fio: %s skips replay of %lu writes due to read-only\n",
                                                td->o.name, skipped_writes);
@@ -494,6 +510,13 @@ int load_blktrace(struct thread_data *td, const char *filename, int need_swap)
         */
        td->o.odirect = 1;
 
+       /*
+        * we don't know if this option was set or not. it defaults to 1,
+        * so we'll just guess that we should override it if it's still 1
+        */
+       if (td->o.iodepth != 1)
+               td->o.iodepth = depth;
+
        return 0;
 err:
        close(fd);
diff --git a/cconv.c b/cconv.c
index 5b9c3be2590c79b3b6ec50f664c3ed49bec3d88a..2f7177d9b1e6e4e23cbecc6c37706b4ce3ed2bfd 100644 (file)
--- a/cconv.c
+++ b/cconv.c
@@ -10,14 +10,17 @@ static void string_to_cpu(char **dst, const uint8_t *src)
                *dst = strdup(__src);
 }
 
-static void string_to_net(uint8_t *dst, const char *src)
+static void __string_to_net(uint8_t *dst, const char *src, size_t dst_size)
 {
-       if (src)
-               strcpy((char *) dst, src);
-       else
+       if (src) {
+               dst[dst_size - 1] = '\0';
+               strncpy((char *) dst, src, dst_size - 1);
+       } else
                dst[0] = '\0';
 }
 
+#define string_to_net(dst, src)        __string_to_net((dst), (src), sizeof(dst))
+
 static void free_thread_options_to_cpu(struct thread_options *o)
 {
        free(o->description);
@@ -77,6 +80,7 @@ void convert_thread_options_to_cpu(struct thread_options *o,
        o->iodepth_batch = le32_to_cpu(top->iodepth_batch);
        o->iodepth_batch_complete = le32_to_cpu(top->iodepth_batch_complete);
        o->size = le64_to_cpu(top->size);
+       o->io_limit = le64_to_cpu(top->io_limit);
        o->size_percent = le32_to_cpu(top->size_percent);
        o->fill_device = le32_to_cpu(top->fill_device);
        o->file_append = le32_to_cpu(top->file_append);
@@ -425,6 +429,7 @@ void convert_thread_options_to_net(struct thread_options_pack *top,
        memcpy(top->buffer_pattern, o->buffer_pattern, MAX_PATTERN_SIZE);
 
        top->size = __cpu_to_le64(o->size);
+       top->io_limit = __cpu_to_le64(o->io_limit);
        top->verify_backlog = __cpu_to_le64(o->verify_backlog);
        top->start_delay = __cpu_to_le64(o->start_delay);
        top->start_delay_high = __cpu_to_le64(o->start_delay_high);
index 467d093982c8ff1f6fdd2cb7d6781e8c76934c8b..af6621dc63d3e0ce7c196e1bd5daa0e747463a7d 100644 (file)
--- a/client.c
+++ b/client.c
@@ -388,7 +388,7 @@ static int fio_client_connect_sock(struct fio_client *client)
 
        memset(addr, 0, sizeof(*addr));
        addr->sun_family = AF_UNIX;
-       strcpy(addr->sun_path, client->hostname);
+       strncpy(addr->sun_path, client->hostname, sizeof(addr->sun_path) - 1);
 
        fd = socket(AF_UNIX, SOCK_STREAM, 0);
        if (fd < 0) {
@@ -907,15 +907,15 @@ static void convert_dus(struct disk_util_stat *dus)
        int i;
 
        for (i = 0; i < 2; i++) {
-               dus->ios[i]     = le32_to_cpu(dus->ios[i]);
-               dus->merges[i]  = le32_to_cpu(dus->merges[i]);
-               dus->sectors[i] = le64_to_cpu(dus->sectors[i]);
-               dus->ticks[i]   = le32_to_cpu(dus->ticks[i]);
+               dus->s.ios[i]           = le32_to_cpu(dus->s.ios[i]);
+               dus->s.merges[i]        = le32_to_cpu(dus->s.merges[i]);
+               dus->s.sectors[i]       = le64_to_cpu(dus->s.sectors[i]);
+               dus->s.ticks[i]         = le32_to_cpu(dus->s.ticks[i]);
        }
 
-       dus->io_ticks           = le32_to_cpu(dus->io_ticks);
-       dus->time_in_queue      = le32_to_cpu(dus->time_in_queue);
-       dus->msec               = le64_to_cpu(dus->msec);
+       dus->s.io_ticks         = le32_to_cpu(dus->s.io_ticks);
+       dus->s.time_in_queue    = le32_to_cpu(dus->s.time_in_queue);
+       dus->s.msec             = le64_to_cpu(dus->s.msec);
 }
 
 static void handle_du(struct fio_client *client, struct fio_net_cmd *cmd)
index 05f985b6634e5dc516d0ef98dfbf5b45294becae..d37e8b4bd505de82835702a21c39d0b0ea75349b 100755 (executable)
--- a/configure
+++ b/configure
@@ -651,22 +651,6 @@ fi
 echo "sched_setaffinity(3 arg)      $linux_3arg_affinity"
 echo "sched_setaffinity(2 arg)      $linux_2arg_affinity"
 
-##########################################
-# CPU_COUNT test
-cpu_count="no"
-cat > $TMPC << EOF
-#include <sched.h>
-int main(int argc, char **argv)
-{
-  cpu_set_t mask;
-  return CPU_COUNT(&mask);
-}
-EOF
-if compile_prog "" "" "cpu_count"; then
-  cpu_count="yes"
-fi
-echo "CPU_COUNT                     $cpu_count"
-
 ##########################################
 # clock_gettime probe
 clock_gettime="no"
@@ -1181,6 +1165,75 @@ if compile_prog "" "" "setvbuf"; then
 fi
 echo "setvbuf                       $setvbuf"
 
+# check for gfapi
+gfapi="no"
+cat > $TMPC << EOF
+#include <glusterfs/api/glfs.h>
+
+int main(int argc, char **argv)
+{
+
+  glfs_t *g = glfs_new("foo");
+
+  return 0;
+}
+EOF
+if compile_prog "" "-lgfapi -lglusterfs" "gfapi"; then
+  LIBS="-lgfapi -lglusterfs $LIBS"
+  gfapi="yes"
+fi
+ echo "Gluster API engine            $gfapi"
+
+##########################################
+# check for gfapi fadvise support
+gf_fadvise="no"
+cat > $TMPC << EOF
+#include <glusterfs/api/glfs.h>
+
+int main(int argc, char **argv)
+{
+  struct glfs_fd *fd;
+  int ret = glfs_fadvise(fd, 0, 0, 1);
+
+  return 0;
+}
+EOF
+
+if compile_prog "" "-lgfapi -lglusterfs" "gfapi"; then
+  gf_fadvise="yes"
+fi
+echo "Gluster API use fadvise       $gf_fadvise"
+
+##########################################
+# Check if we support stckf on s390
+s390_z196_facilities="no"
+cat > $TMPC << EOF
+#define STFLE_BITS_Z196 45 /* various z196 facilities ... */
+int main(int argc, char **argv)
+{
+    /* We want just 1 double word to be returned.  */
+    register unsigned long reg0 asm("0") = 0;
+    unsigned long stfle_bits;
+    asm volatile(".machine push"        "\n\t"
+                 ".machine \"z9-109\""  "\n\t"
+                 "stfle %0"             "\n\t"
+                 ".machine pop"         "\n"
+                 : "=QS" (stfle_bits), "+d" (reg0)
+                 : : "cc");
+
+    if ((stfle_bits & (1UL << (63 - STFLE_BITS_Z196))) != 0)
+      return 0;
+    else
+      return -1;
+}
+EOF
+if compile_prog "" "" "s390_z196_facilities"; then
+  $TMPE
+  if [[ $? -eq 0 ]]; then
+       s390_z196_facilities="yes"
+  fi
+fi
+echo "s390_z196_facilities          $s390_z196_facilities"
 #############################################################################
 
 if test "$wordsize" = "64" ; then
@@ -1305,12 +1358,19 @@ fi
 if test "$rbd" = "yes" ; then
   output_sym "CONFIG_RBD"
 fi
-if test "$cpu_count" = "yes" ; then
-  output_sym "CONFIG_CPU_COUNT"
-fi
 if test "$setvbuf" = "yes" ; then
   output_sym "CONFIG_SETVBUF"
 fi
+if test "$s390_z196_facilities" = "yes" ; then
+  output_sym "CONFIG_S390_Z196_FACILITIES"
+  CFLAGS="$CFLAGS -march=z9-109"
+fi
+if test "$gfapi" = "yes" ; then
+  output_sym "CONFIG_GFAPI"
+fi
+if test "$gf_fadvise" = "yes" ; then
+  output_sym "CONFIG_GF_FADVISE"
+fi
 
 echo "LIBS+=$LIBS" >> $config_host_mak
 echo "CFLAGS+=$CFLAGS" >> $config_host_mak
index 2cc7c0f5fbb28dcc49c88df146dbf3172240a883..3773b714782adf9e2eab1eb81fda731ba897a1bf 100644 (file)
@@ -4,7 +4,7 @@
 
 #include "../fio.h"
 #include "../gettime.h"
-#include "../time.h"
+#include "../fio_time.h"
 #include "../verify.h"
 
 #include "../crc/md5.h"
index 9aa1fa15acab9ed27d0925e2926816bd8478d90e..cb285cffb31d3137421518dbba6c5c42e14e1bbf 100644 (file)
@@ -6,6 +6,7 @@
 #include <dirent.h>
 #include <libgen.h>
 #include <math.h>
+#include <assert.h>
 
 #include "fio.h"
 #include "smalloc.h"
@@ -61,16 +62,18 @@ static int get_io_ticks(struct disk_util *du, struct disk_util_stat *dus)
 
        dprint(FD_DISKUTIL, "%s: %s", du->path, p);
 
-       ret = sscanf(p, "%u %u %llu %u %u %u %llu %u %u %u %u\n", &dus->ios[0],
-                                       &dus->merges[0], &sectors[0],
-                                       &dus->ticks[0], &dus->ios[1],
-                                       &dus->merges[1], &sectors[1],
-                                       &dus->ticks[1], &in_flight,
-                                       &dus->io_ticks, &dus->time_in_queue);
+       ret = sscanf(p, "%u %u %llu %u %u %u %llu %u %u %u %u\n",
+                                       &dus->s.ios[0],
+                                       &dus->s.merges[0], &sectors[0],
+                                       &dus->s.ticks[0], &dus->s.ios[1],
+                                       &dus->s.merges[1], &sectors[1],
+                                       &dus->s.ticks[1], &in_flight,
+                                       &dus->s.io_ticks,
+                                       &dus->s.time_in_queue);
        fclose(f);
        dprint(FD_DISKUTIL, "%s: stat read ok? %d\n", du->path, ret == 1);
-       dus->sectors[0] = sectors[0];
-       dus->sectors[1] = sectors[1];
+       dus->s.sectors[0] = sectors[0];
+       dus->s.sectors[1] = sectors[1];
        return ret != 11;
 }
 
@@ -87,21 +90,21 @@ static void update_io_tick_disk(struct disk_util *du)
        dus = &du->dus;
        ldus = &du->last_dus;
 
-       dus->sectors[0] += (__dus.sectors[0] - ldus->sectors[0]);
-       dus->sectors[1] += (__dus.sectors[1] - ldus->sectors[1]);
-       dus->ios[0] += (__dus.ios[0] - ldus->ios[0]);
-       dus->ios[1] += (__dus.ios[1] - ldus->ios[1]);
-       dus->merges[0] += (__dus.merges[0] - ldus->merges[0]);
-       dus->merges[1] += (__dus.merges[1] - ldus->merges[1]);
-       dus->ticks[0] += (__dus.ticks[0] - ldus->ticks[0]);
-       dus->ticks[1] += (__dus.ticks[1] - ldus->ticks[1]);
-       dus->io_ticks += (__dus.io_ticks - ldus->io_ticks);
-       dus->time_in_queue += (__dus.time_in_queue - ldus->time_in_queue);
+       dus->s.sectors[0] += (__dus.s.sectors[0] - ldus->s.sectors[0]);
+       dus->s.sectors[1] += (__dus.s.sectors[1] - ldus->s.sectors[1]);
+       dus->s.ios[0] += (__dus.s.ios[0] - ldus->s.ios[0]);
+       dus->s.ios[1] += (__dus.s.ios[1] - ldus->s.ios[1]);
+       dus->s.merges[0] += (__dus.s.merges[0] - ldus->s.merges[0]);
+       dus->s.merges[1] += (__dus.s.merges[1] - ldus->s.merges[1]);
+       dus->s.ticks[0] += (__dus.s.ticks[0] - ldus->s.ticks[0]);
+       dus->s.ticks[1] += (__dus.s.ticks[1] - ldus->s.ticks[1]);
+       dus->s.io_ticks += (__dus.s.io_ticks - ldus->s.io_ticks);
+       dus->s.time_in_queue += (__dus.s.time_in_queue - ldus->s.time_in_queue);
 
        fio_gettime(&t, NULL);
-       dus->msec += mtime_since(&du->time, &t);
+       dus->s.msec += mtime_since(&du->time, &t);
        memcpy(&du->time, &t, sizeof(t));
-       memcpy(ldus, &__dus, sizeof(__dus));
+       memcpy(&ldus->s, &__dus.s, sizeof(__dus.s));
 }
 
 int update_io_ticks(void)
@@ -236,9 +239,10 @@ static void find_add_disk_slaves(struct thread_data *td, char *path,
                 * are links to the real directories for the slave
                 * devices?
                 */
-               linklen = readlink(temppath, slavepath, PATH_MAX - 0);
+               linklen = readlink(temppath, slavepath, PATH_MAX - 1);
                if (linklen  < 0) {
                        perror("readlink() for slave device.");
+                       closedir(dirhandle);
                        return;
                }
                slavepath[linklen] = '\0';
@@ -246,6 +250,7 @@ static void find_add_disk_slaves(struct thread_data *td, char *path,
                sprintf(temppath, "%s/%s/dev", slavesdir, slavepath);
                if (read_block_dev_entry(temppath, &majdev, &mindev)) {
                        perror("Error getting slave device numbers.");
+                       closedir(dirhandle);
                        return;
                }
 
@@ -295,7 +300,7 @@ static struct disk_util *disk_util_add(struct thread_data *td, int majdev,
                sfree(du);
                return NULL;
        }
-       strncpy((char *) du->dus.name, basename(path), FIO_DU_NAME_SZ);
+       strncpy((char *) du->dus.name, basename(path), FIO_DU_NAME_SZ - 1);
        du->sysfs_root = path;
        du->major = majdev;
        du->minor = mindev;
@@ -526,18 +531,18 @@ static void aggregate_slaves_stats(struct disk_util *masterdu)
        flist_for_each(entry, &masterdu->slaves) {
                slavedu = flist_entry(entry, struct disk_util, slavelist);
                dus = &slavedu->dus;
-               agg->ios[0] += dus->ios[0];
-               agg->ios[1] += dus->ios[1];
-               agg->merges[0] += dus->merges[0];
-               agg->merges[1] += dus->merges[1];
-               agg->sectors[0] += dus->sectors[0];
-               agg->sectors[1] += dus->sectors[1];
-               agg->ticks[0] += dus->ticks[0];
-               agg->ticks[1] += dus->ticks[1];
-               agg->time_in_queue += dus->time_in_queue;
+               agg->ios[0] += dus->s.ios[0];
+               agg->ios[1] += dus->s.ios[1];
+               agg->merges[0] += dus->s.merges[0];
+               agg->merges[1] += dus->s.merges[1];
+               agg->sectors[0] += dus->s.sectors[0];
+               agg->sectors[1] += dus->s.sectors[1];
+               agg->ticks[0] += dus->s.ticks[0];
+               agg->ticks[1] += dus->s.ticks[1];
+               agg->time_in_queue += dus->s.time_in_queue;
                agg->slavecount++;
 
-               util = (double) (100 * dus->io_ticks / (double) slavedu->dus.msec);
+               util = (double) (100 * dus->s.io_ticks / (double) slavedu->dus.s.msec);
                /* System utilization is the utilization of the
                 * component with the highest utilization.
                 */
@@ -572,8 +577,8 @@ void print_disk_util(struct disk_util_stat *dus, struct disk_util_agg *agg,
 {
        double util = 0;
 
-       if (dus->msec)
-               util = (double) 100 * dus->io_ticks / (double) dus->msec;
+       if (dus->s.msec)
+               util = (double) 100 * dus->s.io_ticks / (double) dus->s.msec;
        if (util > 100.0)
                util = 100.0;
 
@@ -583,16 +588,17 @@ void print_disk_util(struct disk_util_stat *dus, struct disk_util_agg *agg,
 
                log_info("  %s: ios=%u/%u, merge=%u/%u, ticks=%u/%u, "
                         "in_queue=%u, util=%3.2f%%", dus->name,
-                                       dus->ios[0], dus->ios[1],
-                                       dus->merges[0], dus->merges[1],
-                                       dus->ticks[0], dus->ticks[1],
-                                       dus->time_in_queue, util);
+                                       dus->s.ios[0], dus->s.ios[1],
+                                       dus->s.merges[0], dus->s.merges[1],
+                                       dus->s.ticks[0], dus->s.ticks[1],
+                                       dus->s.time_in_queue, util);
        } else {
                log_info(";%s;%u;%u;%u;%u;%u;%u;%u;%3.2f%%",
-                                       dus->name, dus->ios[0], dus->ios[1],
-                                       dus->merges[0], dus->merges[1],
-                                       dus->ticks[0], dus->ticks[1],
-                                       dus->time_in_queue, util);
+                                       dus->name, dus->s.ios[0],
+                                       dus->s.ios[1], dus->s.merges[0],
+                                       dus->s.merges[1], dus->s.ticks[0],
+                                       dus->s.ticks[1],
+                                       dus->s.time_in_queue, util);
        }
 
        /*
@@ -611,8 +617,8 @@ void json_array_add_disk_util(struct disk_util_stat *dus,
        struct json_object *obj;
        double util = 0;
 
-       if (dus->msec)
-               util = (double) 100 * dus->io_ticks / (double) dus->msec;
+       if (dus->s.msec)
+               util = (double) 100 * dus->s.io_ticks / (double) dus->s.msec;
        if (util > 100.0)
                util = 100.0;
 
@@ -620,13 +626,13 @@ void json_array_add_disk_util(struct disk_util_stat *dus,
        json_array_add_value_object(array, obj);
 
        json_object_add_value_string(obj, "name", dus->name);
-       json_object_add_value_int(obj, "read_ios", dus->ios[0]);
-       json_object_add_value_int(obj, "write_ios", dus->ios[1]);
-       json_object_add_value_int(obj, "read_merges", dus->merges[0]);
-       json_object_add_value_int(obj, "write_merges", dus->merges[1]);
-       json_object_add_value_int(obj, "read_ticks", dus->ticks[0]);
-       json_object_add_value_int(obj, "write_ticks", dus->ticks[1]);
-       json_object_add_value_int(obj, "in_queue", dus->time_in_queue);
+       json_object_add_value_int(obj, "read_ios", dus->s.ios[0]);
+       json_object_add_value_int(obj, "write_ios", dus->s.ios[1]);
+       json_object_add_value_int(obj, "read_merges", dus->s.merges[0]);
+       json_object_add_value_int(obj, "write_merges", dus->s.merges[1]);
+       json_object_add_value_int(obj, "read_ticks", dus->s.ticks[0]);
+       json_object_add_value_int(obj, "write_ticks", dus->s.ticks[1]);
+       json_object_add_value_int(obj, "in_queue", dus->s.time_in_queue);
        json_object_add_value_float(obj, "util", util);
 
        /*
@@ -681,12 +687,15 @@ void show_disk_util(int terse, struct json_object *parent)
                return;
        }
 
-       if (!terse && !parent)
+       if (output_format == FIO_OUTPUT_JSON)
+               assert(parent);
+
+       if (!terse && output_format != FIO_OUTPUT_JSON)
                log_info("\nDisk stats (read/write):\n");
 
-       if (output_format == FIO_OUTPUT_JSON) {
+       if (output_format == FIO_OUTPUT_JSON)
                json_object_add_disk_utils(parent, &disk_list);
-       else
+       else
                flist_for_each(entry, &disk_list) {
                        du = flist_entry(entry, struct disk_util, list);
 
index 7207c731c9d4d2a6158be0577c0873556f388a5e..d86e4ec7e69b7b0b3b41cb36e22dd5aa61f79d79 100644 (file)
@@ -5,11 +5,7 @@
 
 extern volatile int disk_util_exit;
 
-/*
- * Disk utils as read in /sys/block/<dev>/stat
- */
-struct disk_util_stat {
-       uint8_t name[FIO_DU_NAME_SZ];
+struct disk_util_stats {
        uint32_t ios[2];
        uint32_t merges[2];
        uint64_t sectors[2];
@@ -19,6 +15,14 @@ struct disk_util_stat {
        uint64_t msec;
 };
 
+/*
+ * Disk utils as read in /sys/block/<dev>/stat
+ */
+struct disk_util_stat {
+       uint8_t name[FIO_DU_NAME_SZ];
+       struct disk_util_stats s;
+};
+
 struct disk_util_agg {
        uint32_t ios[2];
        uint32_t merges[2];
index fb1906206a039be8e13f5cc00118307b6febd1dd..43e316950be45a3f9c9a183c6e7619b60b980b98 100644 (file)
@@ -109,10 +109,11 @@ static int fio_binject_getevents(struct thread_data *td, unsigned int min,
                /*
                 * don't block for min events == 0
                 */
-               if (!min) {
-                       bd->fd_flags[i] = fcntl(bf->fd, F_GETFL);
-                       fcntl(bf->fd, F_SETFL, bd->fd_flags[i] | O_NONBLOCK);
-               }
+               if (!min)
+                       bd->fd_flags[i] = fio_set_fd_nonblocking(bf->fd, "binject");
+               else
+                       bd->fd_flags[i] = -1;
+
                bd->pfds[i].fd = bf->fd;
                bd->pfds[i].events = POLLIN;
        }
@@ -154,7 +155,12 @@ static int fio_binject_getevents(struct thread_data *td, unsigned int min,
        if (!min) {
                for_each_file(td, f, i) {
                        bf = (struct binject_file *) (uintptr_t) f->engine_data;
-                       fcntl(bf->fd, F_SETFL, bd->fd_flags[i]);
+
+                       if (bd->fd_flags[i] == -1)
+                               continue;
+
+                       if (fcntl(bf->fd, F_SETFL, bd->fd_flags[i]) < 0)
+                               log_err("fio: binject failed to restore fcntl flags: %s\n", strerror(errno));
                }
        }
 
index c798f1884e8dff8df9b079d87d61c8c4259ae10c..85598ef77fb9acd8d4868d6e15de1d9f64bee83f 100644 (file)
@@ -11,6 +11,7 @@ struct cpu_options {
        struct thread_data *td;
        unsigned int cpuload;
        unsigned int cpucycle;
+       unsigned int exit_io_done;
 };
 
 static struct fio_option options[] = {
@@ -35,6 +36,16 @@ static struct fio_option options[] = {
                .category = FIO_OPT_C_GENERAL,
                .group  = FIO_OPT_G_INVALID,
        },
+       {
+               .name   = "exit_on_io_done",
+               .lname  = "Exit when IO threads are done",
+               .type   = FIO_OPT_BOOL,
+               .off1   = offsetof(struct cpu_options, exit_io_done),
+               .help   = "Exit when IO threads finish",
+               .def    = "0",
+               .category = FIO_OPT_C_GENERAL,
+               .group  = FIO_OPT_G_INVALID,
+       },
        {
                .name   = NULL,
        },
@@ -45,6 +56,11 @@ static int fio_cpuio_queue(struct thread_data *td, struct io_u fio_unused *io_u)
 {
        struct cpu_options *co = td->eo;
 
+       if (co->exit_io_done && !fio_running_or_pending_io_threads()) {
+               td->done = 1;
+               return FIO_Q_BUSY;
+       }
+
        usec_spin(co->cpucycle);
        return FIO_Q_COMPLETED;
 }
index 4d87f676a128f1ab6cda8c826a9479098190d5b9..3599ab8a49ce708087c4ac88b18b74bd728bec95 100644 (file)
@@ -80,7 +80,7 @@ static int fio_e4defrag_init(struct thread_data *td)
 
        ed = malloc(sizeof(*ed));
        if (!ed) {
-               td_verror(td, -ENOMEM, "io_queue_init");
+               td_verror(td, ENOMEM, "io_queue_init");
                return 1;
        }
        memset(ed, 0 ,sizeof(*ed));
@@ -91,7 +91,7 @@ static int fio_e4defrag_init(struct thread_data *td)
 
        ed->donor_fd = open(donor_name, O_CREAT|O_WRONLY, 0644);
        if (ed->donor_fd < 0) {
-               td_verror(td, ed->donor_fd, "io_queue_init");
+               td_verror(td, errno, "io_queue_init");
                log_err("Can't open donor file %s err:%d", donor_name, ed->donor_fd);
                free(ed);
                return 1;
diff --git a/engines/gfapi.h b/engines/gfapi.h
new file mode 100644 (file)
index 0000000..d473815
--- /dev/null
@@ -0,0 +1,22 @@
+#include <glusterfs/api/glfs.h>
+#include <glusterfs/api/glfs-handles.h>
+#include "../fio.h"
+
+struct gf_options {
+    struct thread_data *td;
+    char *gf_vol;
+    char *gf_brick;
+};
+
+struct gf_data {
+    glfs_t *fs;
+    glfs_fd_t *fd;
+       struct io_u **aio_events;
+};
+
+extern struct fio_option gfapi_options[];
+extern int fio_gf_setup(struct thread_data *td);
+extern void fio_gf_cleanup(struct thread_data *td);
+extern int fio_gf_get_file_size(struct thread_data *td, struct fio_file *f);
+extern int fio_gf_open_file(struct thread_data *td, struct fio_file *f);
+extern int fio_gf_close_file(struct thread_data *td, struct fio_file *f);
diff --git a/engines/glusterfs.c b/engines/glusterfs.c
new file mode 100644 (file)
index 0000000..230274a
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * glusterfs engine
+ *
+ * common Glusterfs's gfapi interface
+ *
+ */
+
+#include "gfapi.h"
+
+struct fio_option gfapi_options[] = {
+    {
+        .name     = "volume",
+        .lname    = "Glusterfs volume",
+        .type     = FIO_OPT_STR_STORE,
+        .help     = "Name of the Glusterfs volume",
+        .off1     = offsetof(struct gf_options, gf_vol),
+        .category = FIO_OPT_C_ENGINE,
+        .group    = FIO_OPT_G_GFAPI,
+    },
+    {
+        .name     = "brick",
+        .lname    = "Glusterfs brick name",
+        .type     = FIO_OPT_STR_STORE,
+        .help     = "Name of the Glusterfs brick to connect",
+        .off1     = offsetof(struct gf_options, gf_brick),
+        .category = FIO_OPT_C_ENGINE,
+        .group    = FIO_OPT_G_GFAPI,
+    },
+    {
+        .name = NULL,
+    },
+};
+
+int fio_gf_setup(struct thread_data *td)
+{
+       int r = 0;
+       struct gf_data *g = NULL;
+       struct gf_options *opt = td->eo;
+    struct stat sb = {0, };
+
+       dprint(FD_IO, "fio setup\n");
+
+       if (td->io_ops->data)
+           return 0;
+
+       g = malloc(sizeof(struct gf_data));
+       if (!g){
+           log_err("malloc failed.\n");
+           return -ENOMEM;
+       }
+       g->fs = NULL; g->fd = NULL; g->aio_events = NULL;
+
+       g->fs = glfs_new (opt->gf_vol);
+       if (!g->fs){
+           log_err("glfs_new failed.\n");
+           goto cleanup;
+       }
+       glfs_set_logging (g->fs, "/tmp/fio_gfapi.log", 7);
+       /* default to tcp */
+       r = glfs_set_volfile_server(g->fs, "tcp", opt->gf_brick, 0);
+       if (r){
+           log_err("glfs_set_volfile_server failed.\n");
+           goto cleanup;
+       }
+       r = glfs_init(g->fs);
+       if (r){
+           log_err("glfs_init failed. Is glusterd running on brick?\n");
+           goto cleanup;
+       }
+       sleep(2);
+       r = glfs_lstat (g->fs, ".", &sb);
+       if (r){
+           log_err("glfs_lstat failed.\n");
+           goto cleanup;
+       }
+       dprint(FD_FILE, "fio setup %p\n", g->fs);
+       td->io_ops->data = g;
+cleanup:
+       if (r){
+           if (g){
+            if (g->fs){
+                glfs_fini(g->fs);
+            }
+            free(g);
+            td->io_ops->data = NULL;
+           }
+       }
+       return r;
+}
+
+void fio_gf_cleanup(struct thread_data *td)
+{
+       struct gf_data *g = td->io_ops->data;
+
+       if (g) {
+        if (g->aio_events)
+            free(g->aio_events);
+        if (g->fd)
+            glfs_close(g->fd);
+        if (g->fs)
+            glfs_fini(g->fs);
+        free(g);
+        td->io_ops->data = NULL;
+       }
+}
+
+int fio_gf_get_file_size(struct thread_data *td, struct fio_file *f)
+{
+    struct stat buf;
+    int ret;
+    struct gf_data *g = td->io_ops->data;
+
+    dprint(FD_FILE, "get file size %s\n", f->file_name);
+
+    if (!g || !g->fs)
+    {
+        return 0;
+    }
+    if (fio_file_size_known(f))
+        return 0;
+
+    ret = glfs_lstat (g->fs, f->file_name, &buf);
+    if (ret < 0){
+        log_err("glfs_lstat failed.\n");
+        return ret;
+    }
+
+    f->real_file_size = buf.st_size;
+    fio_file_set_size_known(f);
+
+    return 0;
+
+}
+
+int fio_gf_open_file(struct thread_data *td, struct fio_file *f)
+{
+
+    int flags = 0;
+    int ret = 0;
+    struct gf_data *g = td->io_ops->data;
+    struct stat sb = {0, };
+
+    if (td_write(td)) {
+        if (!read_only)
+            flags = O_RDWR;
+    } else if (td_read(td)) {
+        if (!read_only)
+            flags = O_RDWR;
+        else
+            flags = O_RDONLY;
+    }
+    dprint(FD_FILE, "fio file %s open mode %s td rw %s\n", f->file_name,
+           flags == O_RDONLY? "ro":"rw", td_read(td)? "read":"write");
+    g->fd = glfs_creat(g->fs, f->file_name, flags, 0644);    
+    if (!g->fd){
+        log_err("glfs_creat failed.\n");
+        ret = errno;
+    }
+    /* file for read doesn't exist or shorter than required, create/extend it */
+    if (td_read(td)){
+        if (glfs_lstat (g->fs, f->file_name, &sb) || sb.st_size < f->real_file_size){
+            dprint(FD_FILE, "fio extend file %s from %ld to %ld\n", f->file_name, sb.st_size, f->real_file_size);
+            ret = glfs_ftruncate (g->fd, f->real_file_size);
+            if (ret){
+                log_err("failed fio extend file %s to %ld\n", f->file_name, f->real_file_size);
+            }else{
+                unsigned long long left;
+                unsigned int bs;
+                char *b;
+                int r;
+
+                /* fill the file, copied from extend_file */
+                b = malloc(td->o.max_bs[DDIR_WRITE]);
+
+                left = f->real_file_size;
+                while (left && !td->terminate) {
+                    bs = td->o.max_bs[DDIR_WRITE];
+                    if (bs > left)
+                        bs = left;
+
+                    fill_io_buffer(td, b, bs, bs);
+
+                    r = glfs_write(g->fd, b, bs, 0);
+                    dprint(FD_IO, "fio write %d of %ld file %s\n", r, f->real_file_size, f->file_name);
+
+                    if (r > 0) {
+                        left -= r;
+                        continue;
+                    } else {
+                        if (r < 0) {
+                            int __e = errno;
+
+                            if (__e == ENOSPC) {
+                                if (td->o.fill_device)
+                                    break;
+                                log_info("fio: ENOSPC on laying out "
+                                         "file, stopping\n");
+                                break;
+                            }
+                            td_verror(td, errno, "write");
+                        } else
+                            td_verror(td, EIO, "write");
+
+                        break;
+                    }
+                }
+
+                if (b) free(b);
+                glfs_lseek(g->fd, 0, SEEK_SET);
+
+                if (td->terminate) {
+                    dprint(FD_FILE, "terminate unlink %s\n", f->file_name);
+                    unlink(f->file_name);
+                } else if (td->o.create_fsync) {
+                    if (glfs_fsync(g->fd) < 0) {
+                        dprint(FD_FILE, "failed to sync, close %s\n", f->file_name);
+                        td_verror(td, errno, "fsync");
+                        glfs_close(g->fd);
+                        g->fd = NULL;
+                        return 1;
+                    }
+                }
+            }
+        }
+    }
+#if defined(GFAPI_USE_FADVISE)
+    {
+        int r = 0; 
+        if (td_random(td)){
+            r = glfs_fadvise(g->fd, 0, f->real_file_size, POSIX_FADV_RANDOM);
+        }else{
+            r = glfs_fadvise(g->fd, 0, f->real_file_size, POSIX_FADV_SEQUENTIAL);
+        }
+        if (r){
+            dprint(FD_FILE, "fio %p fadvise %s status %d\n", g->fs, f->file_name, r);
+        }
+    }
+#endif
+    dprint(FD_FILE, "fio %p created %s\n", g->fs, f->file_name);
+    f->fd = -1;
+    f->shadow_fd = -1;    
+
+    return ret;
+}
+
+int fio_gf_close_file(struct thread_data *td, struct fio_file *f)
+{
+       int ret = 0;
+       struct gf_data *g = td->io_ops->data;
+
+       dprint(FD_FILE, "fd close %s\n", f->file_name);
+
+    if (g){
+        if (g->fd && glfs_close(g->fd) < 0)
+            ret = errno;
+
+        if (g->fs)
+            glfs_fini(g->fs);
+
+        g->fd = NULL;
+        free(g);
+    }
+       td->io_ops->data = NULL;
+       f->engine_data = 0;
+
+       return ret;
+}
+
diff --git a/engines/glusterfs_async.c b/engines/glusterfs_async.c
new file mode 100644 (file)
index 0000000..bea9549
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * glusterfs engine
+ *
+ * IO engine using Glusterfs's gfapi async interface
+ *
+ */
+#include "gfapi.h"
+#define NOT_YET 1
+struct fio_gf_iou {
+       struct io_u *io_u;
+       int io_complete;
+};
+static ulong cb_count = 0, issued = 0;
+
+static struct io_u *fio_gf_event(struct thread_data *td, int event)
+{
+       struct gf_data *gf_data = td->io_ops->data;
+       dprint(FD_IO, "%s\n", __FUNCTION__);
+       return gf_data->aio_events[event];
+}
+
+static int fio_gf_getevents(struct thread_data *td, unsigned int min,
+                            unsigned int max, struct timespec *t)
+{
+       struct gf_data *g = td->io_ops->data;
+       unsigned int events = 0;
+       struct io_u *io_u;
+       int i = 0;
+       struct fio_gf_iou *io = NULL;
+
+       dprint(FD_IO, "%s\n", __FUNCTION__);
+       do {
+               io_u_qiter(&td->io_u_all, io_u, i) {
+                       if (!(io_u->flags & IO_U_F_FLIGHT))
+                               continue;
+
+                       io = (struct fio_gf_iou *)io_u->engine_data;
+
+                       if (io && io->io_complete) {
+                               io->io_complete = 0;
+                               g->aio_events[events] = io_u;
+                               events++;
+
+                if (events >= max) 
+                    break;
+                       }
+
+               }
+               if (events < min)
+                       usleep(100);
+               else
+                       break;
+
+       } while (1);
+
+       return events;
+}
+
+static void fio_gf_io_u_free(struct thread_data *td, struct io_u *io_u)
+{
+       struct fio_gf_iou *io = io_u->engine_data;
+
+       if (io) {
+        if (io->io_complete){
+            log_err("incomplete IO found.\n");
+        }
+               io_u->engine_data = NULL;
+               free(io);
+       }
+    fprintf(stderr, "issued %lu finished %lu\n", issued, cb_count);
+}
+
+static int fio_gf_io_u_init(struct thread_data *td, struct io_u *io_u)
+{
+       struct fio_gf_iou *io = NULL;
+
+       dprint(FD_FILE, "%s\n", __FUNCTION__);
+
+    if (!io_u->engine_data){
+        io = malloc(sizeof(struct fio_gf_iou));
+        if (!io){
+            td_verror(td, errno, "malloc");
+            return 1;
+        }
+        io->io_complete = 0;
+        io->io_u = io_u;
+        io_u->engine_data = io;
+    }
+       return 0;
+}
+
+static void gf_async_cb(glfs_fd_t *fd, ssize_t ret, void *data) 
+{
+       struct io_u *io_u = (struct io_u *)data;
+       struct fio_gf_iou *iou =
+           (struct fio_gf_iou *)io_u->engine_data;
+
+    dprint(FD_IO, "%s ret %lu\n", __FUNCTION__, ret);    
+    iou->io_complete = 1;
+    cb_count ++;
+}
+
+static int fio_gf_async_queue(struct thread_data fio_unused *td, struct io_u *io_u)
+{
+       struct gf_data *g = td->io_ops->data;
+    int r = 0;
+
+    dprint(FD_IO, "%s op %s\n", __FUNCTION__,  
+           io_u->ddir == DDIR_READ? "read": io_u->ddir == DDIR_WRITE? "write":io_u->ddir == DDIR_SYNC? "sync":"unknown");    
+
+       fio_ro_check(td, io_u);
+
+       if (io_u->ddir == DDIR_READ)
+               r = glfs_pread_async(g->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset,
+                         0, gf_async_cb, (void *)io_u);
+       else if (io_u->ddir == DDIR_WRITE)
+               r = glfs_pwrite_async(g->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset,
+                         0, gf_async_cb, (void *)io_u);
+    else if (io_u->ddir == DDIR_SYNC) {
+        r = glfs_fsync_async(g->fd, gf_async_cb, (void *)io_u);
+    }else {        
+        log_err("unsupported operation.\n");
+        io_u->error = -EINVAL;
+        goto failed;
+    }
+    if (r){
+        log_err("glfs failed.\n");
+        io_u->error = r;
+        goto failed;
+    }
+    issued ++;
+       return FIO_Q_QUEUED;
+
+failed:
+       io_u->error = r;
+       td_verror(td, io_u->error, "xfer");
+       return FIO_Q_COMPLETED;
+}
+
+int fio_gf_async_setup(struct thread_data *td)
+{
+       int r = 0;
+       struct gf_data *g = NULL;
+#if defined(NOT_YET)
+    fprintf(stderr, "the async interface is still very experimental...\n");
+#endif
+    r = fio_gf_setup(td);
+    if (r){
+        return r;
+    }
+       td->o.use_thread = 1;
+    g = td->io_ops->data;
+    g->aio_events = malloc(td->o.iodepth * sizeof(struct io_u *));
+       if (!g->aio_events){
+        r = -ENOMEM;
+        fio_gf_cleanup(td);
+        return r;
+    }
+
+       memset(g->aio_events, 0, td->o.iodepth * sizeof(struct io_u *));
+
+    return r;
+
+}
+
+static int fio_gf_async_prep(struct thread_data *td, struct io_u *io_u)
+{
+       dprint(FD_FILE, "%s\n", __FUNCTION__);
+
+       if (!ddir_rw(io_u->ddir))
+               return 0;
+
+       return 0;
+}
+
+static struct ioengine_ops ioengine = {
+       .name               = "gfapi_async",
+       .version            = FIO_IOOPS_VERSION,
+       .init           = fio_gf_async_setup,
+       .cleanup        = fio_gf_cleanup,
+    .prep           = fio_gf_async_prep,
+       .queue              = fio_gf_async_queue,
+       .open_file          = fio_gf_open_file,
+       .close_file         = fio_gf_close_file,
+       .get_file_size  = fio_gf_get_file_size,
+       .getevents      = fio_gf_getevents,
+       .event          = fio_gf_event,
+       .io_u_init      = fio_gf_io_u_init,
+       .io_u_free      = fio_gf_io_u_free,
+       .options        = gfapi_options,
+       .option_struct_size = sizeof(struct gf_options),
+       .flags              = FIO_DISKLESSIO,
+};
+
+static void fio_init fio_gf_register(void)
+{
+    register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_gf_unregister(void)
+{
+    unregister_ioengine(&ioengine);
+}
diff --git a/engines/glusterfs_sync.c b/engines/glusterfs_sync.c
new file mode 100644 (file)
index 0000000..cff6427
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * glusterfs engine
+ *
+ * IO engine using Glusterfs's gfapi sync interface
+ *
+ */
+
+#include "gfapi.h"
+
+#define LAST_POS(f)    ((f)->engine_data)
+static int fio_gf_prep(struct thread_data *td, struct io_u *io_u)
+{
+       struct fio_file *f = io_u->file;
+       struct gf_data *g = td->io_ops->data;
+
+       dprint(FD_FILE, "fio prep\n");
+
+       if (!ddir_rw(io_u->ddir))
+               return 0;
+
+       if (LAST_POS(f) != -1ULL && LAST_POS(f) == io_u->offset)
+               return 0;
+
+       if (glfs_lseek(g->fd, io_u->offset, SEEK_SET) < 0) {
+               td_verror(td, errno, "lseek");
+               return 1;
+       }
+
+       return 0;
+}
+
+static int fio_gf_queue(struct thread_data *td, struct io_u *io_u)
+{
+    struct gf_data *g = td->io_ops->data;
+    int ret = 0;
+
+    dprint(FD_FILE, "fio queue len %lu\n", io_u->xfer_buflen);
+    fio_ro_check(td, io_u);
+
+    if (io_u->ddir == DDIR_READ)
+        ret = glfs_read(g->fd, io_u->xfer_buf, io_u->xfer_buflen, 0);
+    else if (io_u->ddir == DDIR_WRITE)
+        ret = glfs_write(g->fd, io_u->xfer_buf, io_u->xfer_buflen, 0);
+    else {         
+        log_err("unsupported operation.\n");
+        return -EINVAL;
+    }
+    dprint(FD_FILE, "fio len %lu ret %d\n", io_u->xfer_buflen, ret);
+    if (io_u->file && ret >= 0 && ddir_rw(io_u->ddir))
+        LAST_POS(io_u->file) = io_u->offset + ret;
+
+    if (ret != (int) io_u->xfer_buflen) {
+        if (ret >= 0) {
+            io_u->resid = io_u->xfer_buflen - ret;
+            io_u->error = 0;
+            return FIO_Q_COMPLETED;
+        } else
+            io_u->error = errno;
+    }
+
+    if (io_u->error){
+        log_err("IO failed.\n");
+        td_verror(td, io_u->error, "xfer");
+    }
+
+    return FIO_Q_COMPLETED;
+
+}
+
+static struct ioengine_ops ioengine = {
+       .name               = "gfapi",
+       .version            = FIO_IOOPS_VERSION,
+       .init           = fio_gf_setup,
+       .cleanup        = fio_gf_cleanup,
+       .prep               = fio_gf_prep,
+       .queue              = fio_gf_queue,
+       .open_file          = fio_gf_open_file,
+       .close_file         = fio_gf_close_file,
+       .get_file_size  = fio_gf_get_file_size,
+       .options        = gfapi_options,
+       .option_struct_size = sizeof(struct gf_options),
+       .flags              = FIO_SYNCIO | FIO_DISKLESSIO,
+};
+
+static void fio_init fio_gf_register(void)
+{
+    register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_gf_unregister(void)
+{
+    unregister_ioengine(&ioengine);
+}
index 110e158f114cbe210656476ff81af305d7d80248..8087207e505bc69ac67e0321aff922a35207d9dc 100644 (file)
@@ -945,7 +945,8 @@ static int fio_netio_setup_connect_unix(struct thread_data *td,
        struct sockaddr_un *soun = &nd->addr_un;
 
        soun->sun_family = AF_UNIX;
-       strcpy(soun->sun_path, path);
+       memset(soun->sun_path, 0, sizeof(soun->sun_path));
+       strncpy(soun->sun_path, path, sizeof(soun->sun_path) - 1);
        return 0;
 }
 
@@ -976,7 +977,7 @@ static int fio_netio_setup_listen_unix(struct thread_data *td, const char *path)
 
        memset(addr, 0, sizeof(*addr));
        addr->sun_family = AF_UNIX;
-       strcpy(addr->sun_path, path);
+       strncpy(addr->sun_path, path, sizeof(addr->sun_path) - 1);
        unlink(path);
 
        len = sizeof(addr->sun_family) + strlen(path) + 1;
@@ -998,13 +999,11 @@ static int fio_netio_setup_listen_inet(struct thread_data *td, short port)
        struct netio_options *o = td->eo;
        struct ip_mreq mr;
        struct sockaddr_in sin;
-       struct sockaddr_in6 sin6;
        struct sockaddr *saddr;
        int fd, opt, type, domain;
        socklen_t len;
 
        memset(&sin, 0, sizeof(sin));
-       memset(&sin6, 0, sizeof(sin6));
 
        if (o->proto == FIO_TYPE_TCP) {
                type = SOCK_STREAM;
@@ -1087,11 +1086,12 @@ static int fio_netio_setup_listen_inet(struct thread_data *td, short port)
                len = sizeof(nd->addr6);
 
                nd->addr6.sin6_family = AF_INET6;
-               nd->addr6.sin6_addr = sin6.sin6_addr.s6_addr ? sin6.sin6_addr : in6addr_any;
+               nd->addr6.sin6_addr = in6addr_any;
                nd->addr6.sin6_port = htons(port);
        }
 
        if (bind(fd, saddr, len) < 0) {
+               close(fd);
                td_verror(td, errno, "bind");
                return 1;
        }
@@ -1196,6 +1196,7 @@ static int fio_netio_setup(struct thread_data *td)
        if (!td->files_index) {
                add_file(td, td->o.filename ?: "net", 0, 0);
                td->o.nr_files = td->o.nr_files ?: 1;
+               td->o.open_files++;
        }
 
        if (!td->io_ops->data) {
index 9d64efd233cab1dfd4188f8ada16351d649c8f5e..dc6e7db674ba38c6252a61fde337f061938f0555 100644 (file)
@@ -131,8 +131,10 @@ static int _fio_rbd_connect(struct thread_data *td)
 
 failed_open:
        rados_ioctx_destroy(rbd_data->io_ctx);
+       rbd_data->io_ctx = NULL;
 failed_shutdown:
        rados_shutdown(rbd_data->cluster);
+       rbd_data->cluster = NULL;
 failed_early:
        return 1;
 }
@@ -379,6 +381,7 @@ static int fio_rbd_setup(struct thread_data *td)
        if (!td->files_index) {
                add_file(td, td->o.filename ? : "rbd", 0, 0);
                td->o.nr_files = td->o.nr_files ? : 1;
+               td->o.open_files++;
        }
        f = td->files[0];
        f->real_file_size = info.size;
index 88d91258d22c89e78298c6084e7dd277b51aa23e..1a027daeb353fca972da13cf8796983024364463 100644 (file)
@@ -77,10 +77,11 @@ static int fio_sgio_getevents(struct thread_data *td, unsigned int min,
                /*
                 * don't block for min events == 0
                 */
-               if (!min) {
-                       sd->fd_flags[i] = fcntl(f->fd, F_GETFL);
-                       fcntl(f->fd, F_SETFL, sd->fd_flags[i] | O_NONBLOCK);
-               }
+               if (!min)
+                       sd->fd_flags[i] = fio_set_fd_nonblocking(f->fd, "sg");
+               else
+                       sd->fd_flags[i] = -1;
+
                sd->pfds[i].fd = f->fd;
                sd->pfds[i].events = POLLIN;
        }
@@ -143,8 +144,13 @@ re_read:
        }
 
        if (!min) {
-               for_each_file(td, f, i)
-                       fcntl(f->fd, F_SETFL, sd->fd_flags[i]);
+               for_each_file(td, f, i) {
+                       if (sd->fd_flags[i] == -1)
+                               continue;
+
+                       if (fcntl(f->fd, F_SETFL, sd->fd_flags[i]) < 0)
+                               log_err("fio: sg failed to restore fcntl flags: %s\n", strerror(errno));
+               }
        }
 
        return r;
diff --git a/eta.c b/eta.c
index 42066e0d95c044136e96c381caa04e614b48c68d..7500082f4e2398da125b8a1a01cc7e981a021222 100644 (file)
--- a/eta.c
+++ b/eta.c
@@ -174,14 +174,26 @@ static int thread_eta(struct thread_data *td)
                double perc, perc_t;
 
                bytes_done = ddir_rw_sum(td->io_bytes);
-               perc = (double) bytes_done / (double) bytes_total;
-               if (perc > 1.0)
-                       perc = 1.0;
+
+               if (bytes_total) {
+                       perc = (double) bytes_done / (double) bytes_total;
+                       if (perc > 1.0)
+                               perc = 1.0;
+               } else
+                       perc = 0.0;
 
                if (td->o.time_based) {
-                       perc_t = (double) elapsed / (double) timeout;
-                       if (perc_t < perc)
-                               perc = perc_t;
+                       if (timeout) {
+                               perc_t = (double) elapsed / (double) timeout;
+                               if (perc_t < perc)
+                                       perc = perc_t;
+                       } else {
+                               /*
+                                * Will never hit, we can't have time_based
+                                * without a timeout set.
+                                */
+                               perc = 0.0;
+                       }
                }
 
                eta_sec = (unsigned long) (elapsed * (1.0 / perc)) - elapsed;
index fa09219f62a2e2b93f0e001b2e7254da72e04e99..ad7fb8551da7b87889e3e0ec5d087089e918b5fd 100644 (file)
@@ -38,7 +38,7 @@ static int extend_file(struct thread_data *td, struct fio_file *f)
        int r, new_layout = 0, unlink_file = 0, flags;
        unsigned long long left;
        unsigned int bs;
-       char *b;
+       char *b = NULL;
 
        if (read_only) {
                log_err("fio: refusing extend of file due to read-only\n");
@@ -69,6 +69,10 @@ static int extend_file(struct thread_data *td, struct fio_file *f)
        if (new_layout)
                flags |= O_TRUNC;
 
+#ifdef WIN32
+       flags |= _O_BINARY;
+#endif
+
        dprint(FD_FILE, "open file %s, flags %x\n", f->file_name, flags);
        f->fd = open(f->file_name, flags, 0644);
        if (f->fd < 0) {
@@ -189,6 +193,8 @@ done:
 err:
        close(f->fd);
        f->fd = -1;
+       if (b)
+               free(b);
        return 1;
 }
 
@@ -395,9 +401,6 @@ static int __file_invalidate_cache(struct thread_data *td, struct fio_file *f,
        dprint(FD_IO, "invalidate cache %s: %llu/%llu\n", f->file_name, off,
                                                                len);
 
-       /*
-        * FIXME: add blockdev flushing too
-        */
        if (f->mmap_ptr) {
                ret = posix_madvise(f->mmap_ptr, f->mmap_sz, POSIX_MADV_DONTNEED);
 #ifdef FIO_MADV_FREE
@@ -419,15 +422,18 @@ static int __file_invalidate_cache(struct thread_data *td, struct fio_file *f,
        } else if (f->filetype == FIO_TYPE_CHAR || f->filetype == FIO_TYPE_PIPE)
                ret = 0;
 
-       if (ret < 0) {
-               td_verror(td, errno, "invalidate_cache");
-               return 1;
-       } else if (ret > 0) {
-               td_verror(td, ret, "invalidate_cache");
-               return 1;
+       /*
+        * Cache flushing isn't a fatal condition, and we know it will
+        * happen on some platforms where we don't have the proper
+        * function to flush eg block device caches. So just warn and
+        * continue on our way.
+        */
+       if (ret) {
+               log_info("fio: cache invalidation of %s failed: %s\n", f->file_name, strerror(errno));
+               ret = 0;
        }
 
-       return ret;
+       return 0;
 
 }
 
@@ -479,6 +485,10 @@ int file_lookup_open(struct fio_file *f, int flags)
                from_hash = 0;
        }
 
+#ifdef WIN32
+       flags |= _O_BINARY;
+#endif
+
        f->fd = open(f->file_name, flags, 0600);
        return from_hash;
 }
@@ -686,7 +696,8 @@ static unsigned long long get_fs_free_counts(struct thread_data *td)
                } else if (f->filetype != FIO_TYPE_FILE)
                        continue;
 
-               strcpy(buf, f->file_name);
+               buf[255] = '\0';
+               strncpy(buf, f->file_name, 255);
 
                if (stat(buf, &sb) < 0) {
                        if (errno != ENOENT)
@@ -708,8 +719,8 @@ static unsigned long long get_fs_free_counts(struct thread_data *td)
                if (fm)
                        continue;
 
-               fm = malloc(sizeof(*fm));
-               strcpy(fm->__base, buf);
+               fm = calloc(1, sizeof(*fm));
+               strncpy(fm->__base, buf, sizeof(fm->__base) - 1);
                fm->base = basename(fm->__base);
                fm->key = sb.st_dev;
                flist_add(&fm->list, &list);
@@ -806,7 +817,7 @@ int setup_files(struct thread_data *td)
         * Calculate per-file size and potential extra size for the
         * first files, if needed.
         */
-       if (!o->file_size_low) {
+       if (!o->file_size_low && o->nr_files) {
                uint64_t all_fs;
 
                fs = o->size / o->nr_files;
@@ -882,6 +893,11 @@ int setup_files(struct thread_data *td)
        if (!o->size || o->size > total_size)
                o->size = total_size;
 
+       if (o->size < td_min_bs(td)) {
+               log_err("fio: blocksize too large for data set\n");
+               goto err_out;
+       }
+
        /*
         * See if we need to extend some files
         */
@@ -912,7 +928,13 @@ int setup_files(struct thread_data *td)
 
                        err = __file_invalidate_cache(td, f, old_len,
                                                                extend_len);
-                       close(f->fd);
+
+                       /*
+                        * Shut up static checker
+                        */
+                       if (f->fd != -1)
+                               close(f->fd);
+
                        f->fd = -1;
                        if (err)
                                break;
@@ -930,8 +952,12 @@ int setup_files(struct thread_data *td)
         * iolog already set the total io size, if we read back
         * stored entries.
         */
-       if (!o->read_iolog_file)
-               td->total_io_size = o->size * o->loops;
+       if (!o->read_iolog_file) {
+               if (o->io_limit)
+                       td->total_io_size = o->io_limit * o->loops;
+               else
+                       td->total_io_size = o->size * o->loops;
+       }
 
 done:
        if (o->create_only)
@@ -1022,7 +1048,7 @@ int init_random_map(struct thread_data *td)
                        unsigned long seed;
 
                        seed = td->rand_seeds[FIO_RAND_BLOCK_OFF];
-                       
+
                        if (!lfsr_init(&f->lfsr, blocks, seed, 0))
                                continue;
                } else if (!td->o.norandommap) {
@@ -1279,13 +1305,6 @@ int add_file(struct thread_data *td, const char *fname, int numjob, int inc)
 
        set_already_allocated(file_name);
 
-       /*
-        * For adding files after the fact - if openfiles= isn't
-        * given as an option, ensure we allow at least one file open
-        */
-       if (!td->o.open_files)
-               td->o.open_files = 1;
-
        if (inc)
                td->o.nr_files++;
 
@@ -1330,8 +1349,11 @@ int put_file(struct thread_data *td, struct fio_file *f)
        if (--f->references)
                return 0;
 
-       if (should_fsync(td) && td->o.fsync_on_close)
+       if (should_fsync(td) && td->o.fsync_on_close) {
                f_ret = fsync(f->fd);
+               if (f_ret < 0)
+                       f_ret = errno;
+       }
 
        if (td->io_ops->close_file)
                ret = td->io_ops->close_file(td, f);
@@ -1409,7 +1431,8 @@ static int recurse_dir(struct thread_data *td, const char *dirname)
                if (lstat(full_path, &sb) == -1) {
                        if (errno != ENOENT) {
                                td_verror(td, errno, "stat");
-                               return 1;
+                               ret = 1;
+                               break;
                        }
                }
 
diff --git a/fio.1 b/fio.1
index f080d460c1f1eeb041f3b445a3bc2cae82401bb0..62f40ea294d1695a926dcc420abce6f599c5dc2e 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -369,8 +369,16 @@ Unless \fBnrfiles\fR and \fBfilesize\fR options are given, this amount will be
 divided between the available files for the job. If not set, fio will use the
 full size of the given files or devices. If the files do not exist, size
 must be given. It is also possible to give size as a percentage between 1 and
-100. If size=20% is given, fio will use 20% of the full size of the given files
-or devices.
+100. If size=20% is given, fio will use 20% of the full size of the given
+files or devices.
+.TP
+.BI io_limit \fR=\fPint
+Normally fio operates within the region set by \fBsize\fR, which means that
+the \fBsize\fR option sets both the region and size of IO to be performed.
+Sometimes that is not what you want. With this option, it is possible to
+define just the amount of IO that fio should do. For instance, if \fBsize\fR
+is set to 20G and \fBio_limit\fR is set to 5G, fio will perform IO within
+the first 20G but exit when 5G have been done.
 .TP
 .BI fill_device \fR=\fPbool "\fR,\fB fill_fs" \fR=\fPbool
 Sets size to something really large and waits for ENOSPC (no space left on
@@ -594,6 +602,16 @@ request to DDIR_WRITE event
 IO engine supporting direct access to Ceph Rados Block Devices (RBD) via librbd 
 without the need to use the kernel rbd driver. This ioengine defines engine specific 
 options.
+.TP
+.B gfapi
+Using Glusterfs libgfapi sync interface to direct access to Glusterfs volumes without
+having to go through FUSE. This ioengine defines engine specific
+options.
+.TP
+.B gfapi_async
+Using Glusterfs libgfapi async interface to direct access to Glusterfs volumes without
+having to go through FUSE. This ioengine defines engine specific
+options.
 .RE
 .P
 .RE
@@ -1226,14 +1244,6 @@ Output is redirected in a file called \fBjobname.postrun.txt\fR
 .BI ioscheduler \fR=\fPstr
 Attempt to switch the device hosting the file to the specified I/O scheduler.
 .TP
-.BI cpuload \fR=\fPint
-If the job is a CPU cycle-eater, attempt to use the specified percentage of
-CPU cycles.
-.TP
-.BI cpuchunks \fR=\fPint
-If the job is a CPU cycle-eater, split the load into cycles of the
-given time in milliseconds.
-.TP
 .BI disk_util \fR=\fPbool
 Generate disk utilization statistics if the platform supports it. Default: true.
 .TP
@@ -1375,6 +1385,9 @@ Attempt to use the specified percentage of CPU cycles.
 .BI (cpu)cpuchunks \fR=\fPint
 Split the load into cycles of the given time. In microseconds.
 .TP
+.BI (cpu)exit_on_io_done \fR=\fPbool
+Detect when IO threads are done, then exit.
+.TP
 .BI (libaio)userspace_reap
 Normally, with the libaio engine in use, fio will use
 the io_getevents system call to reap newly returned events.
diff --git a/fio.h b/fio.h
index a539f21bee39961a53f297185f3e01fe2df2ee5c..4d4af0a7917f12b5b666ca38ea06a038659dc3b3 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -30,7 +30,7 @@
 #include "helpers.h"
 #include "options.h"
 #include "profile.h"
-#include "time.h"
+#include "fio_time.h"
 #include "gettime.h"
 #include "lib/getopt.h"
 #include "lib/rand.h"
@@ -72,6 +72,7 @@ enum {
        TD_F_VER_NONE           = 32,
        TD_F_PROFILE_OPS        = 64,
        TD_F_COMPRESS           = 128,
+       TD_F_NOIO               = 256,
 };
 
 enum {
@@ -350,7 +351,7 @@ enum {
 
 #define __td_verror(td, err, msg, func)                                        \
        do {                                                            \
-               int ____e = (err);                                              \
+               unsigned int ____e = (err);                             \
                if ((td)->error)                                        \
                        break;                                          \
                (td)->error = ____e;                                    \
@@ -439,6 +440,8 @@ extern void add_job_opts(const char **, int);
 extern char *num2str(unsigned long, int, int, int, int);
 extern int ioengine_load(struct thread_data *);
 extern int parse_dryrun(void);
+extern int fio_running_or_pending_io_threads(void);
+extern int fio_set_fd_nonblocking(int, const char *);
 
 extern uintptr_t page_mask;
 extern uintptr_t page_size;
@@ -585,7 +588,7 @@ static inline unsigned int td_min_bs(struct thread_data *td)
        return min(td->o.min_bs[DDIR_TRIM], min_bs);
 }
 
-static inline int is_power_of_2(unsigned int val)
+static inline int is_power_of_2(unsigned long val)
 {
        return (val != 0 && ((val & (val - 1)) == 0));
 }
@@ -615,7 +618,9 @@ static inline void td_io_u_free_notify(struct thread_data *td)
 extern const char *fio_get_arch_string(int);
 extern const char *fio_get_os_string(int);
 
+#ifdef FIO_INTERNAL
 #define ARRAY_SIZE(x) (sizeof((x)) / (sizeof((x)[0])))
+#endif
 
 enum {
        FIO_OUTPUT_TERSE        = 0,
diff --git a/fio_time.h b/fio_time.h
new file mode 100644 (file)
index 0000000..c550a55
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef FIO_TIME_H
+#define FIO_TIME_H
+
+extern uint64_t utime_since(struct timeval *, struct timeval *);
+extern uint64_t utime_since_now(struct timeval *);
+extern uint64_t mtime_since(struct timeval *, struct timeval *);
+extern uint64_t mtime_since_now(struct timeval *);
+extern uint64_t time_since_now(struct timeval *);
+extern uint64_t mtime_since_genesis(void);
+extern uint64_t utime_since_genesis(void);
+extern void usec_spin(unsigned int);
+extern void usec_sleep(struct thread_data *, unsigned long);
+extern void fill_start_time(struct timeval *);
+extern void set_genesis_time(void);
+extern int ramp_time_over(struct thread_data *);
+extern int in_ramp_time(struct thread_data *);
+extern void fio_time_init(void);
+
+#endif
index 4360aea89ecf7f0d89dd2f204e004968dd4ad388..d236f86667ffeb4624222c2d14de626438a59ce6 100644 (file)
--- a/gclient.c
+++ b/gclient.c
@@ -195,39 +195,39 @@ static int __gfio_disk_util_show(GtkWidget *res_notebook,
        vbox = gtk_hbox_new(TRUE, 3);
        gtk_container_add(GTK_CONTAINER(frame), vbox);
        entry = new_info_entry_in_frame(vbox, "IOs");
-       entry_set_int_value(entry, p->dus.ios[0]);
+       entry_set_int_value(entry, p->dus.s.ios[0]);
        entry = new_info_entry_in_frame(vbox, "Merges");
-       entry_set_int_value(entry, p->dus.merges[0]);
+       entry_set_int_value(entry, p->dus.s.merges[0]);
        entry = new_info_entry_in_frame(vbox, "Sectors");
-       entry_set_int_value(entry, p->dus.sectors[0]);
+       entry_set_int_value(entry, p->dus.s.sectors[0]);
        entry = new_info_entry_in_frame(vbox, "Ticks");
-       entry_set_int_value(entry, p->dus.ticks[0]);
+       entry_set_int_value(entry, p->dus.s.ticks[0]);
 
        frame = gtk_frame_new("Write");
        gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
        vbox = gtk_hbox_new(TRUE, 3);
        gtk_container_add(GTK_CONTAINER(frame), vbox);
        entry = new_info_entry_in_frame(vbox, "IOs");
-       entry_set_int_value(entry, p->dus.ios[1]);
+       entry_set_int_value(entry, p->dus.s.ios[1]);
        entry = new_info_entry_in_frame(vbox, "Merges");
-       entry_set_int_value(entry, p->dus.merges[1]);
+       entry_set_int_value(entry, p->dus.s.merges[1]);
        entry = new_info_entry_in_frame(vbox, "Sectors");
-       entry_set_int_value(entry, p->dus.sectors[1]);
+       entry_set_int_value(entry, p->dus.s.sectors[1]);
        entry = new_info_entry_in_frame(vbox, "Ticks");
-       entry_set_int_value(entry, p->dus.ticks[1]);
+       entry_set_int_value(entry, p->dus.s.ticks[1]);
 
        frame = gtk_frame_new("Shared");
        gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 2);
        vbox = gtk_hbox_new(TRUE, 3);
        gtk_container_add(GTK_CONTAINER(frame), vbox);
        entry = new_info_entry_in_frame(vbox, "IO ticks");
-       entry_set_int_value(entry, p->dus.io_ticks);
+       entry_set_int_value(entry, p->dus.s.io_ticks);
        entry = new_info_entry_in_frame(vbox, "Time in queue");
-       entry_set_int_value(entry, p->dus.time_in_queue);
+       entry_set_int_value(entry, p->dus.s.time_in_queue);
 
        util = 0.0;
-       if (p->dus.msec)
-               util = (double) 100 * p->dus.io_ticks / (double) p->dus.msec;
+       if (p->dus.s.msec)
+               util = (double) 100 * p->dus.s.io_ticks / (double) p->dus.s.msec;
        if (util > 100.0)
                util = 100.0;
 
index b89cd46fdd14e7cbe6290a424416b6268a6543d8..fa750ec85584716f7b6e37c5241130f8688dd6cb 100644 (file)
--- a/gettime.c
+++ b/gettime.c
@@ -13,7 +13,7 @@
 #include "hash.h"
 #include "os/os.h"
 
-#ifdef ARCH_HAVE_CPU_CLOCK
+#if defined(ARCH_HAVE_CPU_CLOCK) && !defined(ARCH_CPU_CLOCK_CYCLES_PER_USEC)
 static unsigned long cycles_per_usec;
 static unsigned long inv_cycles_per_usec;
 #endif
@@ -177,7 +177,11 @@ static void *__fio_gettime(struct timeval *tp)
                } else if (tv)
                        tv->last_cycles = t;
 
+#ifdef ARCH_CPU_CLOCK_CYCLES_PER_USEC
+               usecs = t / ARCH_CPU_CLOCK_CYCLES_PER_USEC;
+#else
                usecs = (t * inv_cycles_per_usec) / 16777216UL;
+#endif
                tp->tv_sec = usecs / 1000000;
                tp->tv_usec = usecs % 1000000;
                break;
@@ -229,7 +233,7 @@ void fio_gettime(struct timeval *tp, void fio_unused *caller)
        }
 }
 
-#ifdef ARCH_HAVE_CPU_CLOCK
+#if defined(ARCH_HAVE_CPU_CLOCK) && !defined(ARCH_CPU_CLOCK_CYCLES_PER_USEC)
 static unsigned long get_cycles_per_usec(void)
 {
        struct timeval s, e;
@@ -318,9 +322,13 @@ static int calibrate_cpu_clock(void)
 #else
 static int calibrate_cpu_clock(void)
 {
+#ifdef ARCH_CPU_CLOCK_CYCLES_PER_USEC
+       return 0;
+#else
        return 1;
-}
 #endif
+}
+#endif // ARCH_HAVE_CPU_CLOCK
 
 #ifndef CONFIG_TLS_THREAD
 void fio_local_clock_init(int is_thread)
@@ -526,10 +534,10 @@ int fio_monotonic_clocktest(void)
        struct clock_thread *threads;
        unsigned int nr_cpus = cpus_online();
        struct clock_entry *entries;
-       unsigned long tentries, failed;
+       unsigned long tentries, failed = 0;
        struct clock_entry *prev, *this;
        uint32_t seq = 0;
-       int i;
+       unsigned int i;
 
        log_info("cs: reliable_tsc: %s\n", tsc_reliable ? "yes" : "no");
 
@@ -552,7 +560,11 @@ int fio_monotonic_clocktest(void)
                pthread_mutex_init(&t->lock, NULL);
                pthread_mutex_init(&t->started, NULL);
                pthread_mutex_lock(&t->lock);
-               pthread_create(&t->thread, NULL, clock_thread_fn, t);
+               if (pthread_create(&t->thread, NULL, clock_thread_fn, t)) {
+                       failed++;
+                       nr_cpus = i;
+                       break;
+               }
        }
 
        for (i = 0; i < nr_cpus; i++) {
@@ -567,7 +579,7 @@ int fio_monotonic_clocktest(void)
                pthread_mutex_unlock(&t->lock);
        }
 
-       for (failed = i = 0; i < nr_cpus; i++) {
+       for (i = 0; i < nr_cpus; i++) {
                struct clock_thread *t = &threads[i];
                void *ret;
 
index c0bc0bfce19675e311fcbd7394540b02a7010eba..a366d2b16311bf6ec1b8e8d50fb84c44edc71eda 100644 (file)
@@ -73,8 +73,10 @@ static void *idle_prof_thread_fn(void *data)
        pthread_mutex_lock(&ipt->init_lock);
 
        /* exit if any other thread failed to start */
-       if (ipc.status == IDLE_PROF_STATUS_ABORT)
+       if (ipc.status == IDLE_PROF_STATUS_ABORT) {
+               pthread_mutex_unlock(&ipt->init_lock);
                return NULL;
+       }
 
        retval = set_cpu_affinity(ipt);
        if (retval == -1) {
@@ -109,12 +111,16 @@ static void *idle_prof_thread_fn(void *data)
        pthread_mutex_lock(&ipt->start_lock);
 
        /* exit if other threads failed to initialize */
-       if (ipc.status == IDLE_PROF_STATUS_ABORT)
+       if (ipc.status == IDLE_PROF_STATUS_ABORT) {
+               pthread_mutex_unlock(&ipt->start_lock);
                return NULL;
+       }
 
        /* exit if we are doing calibration only */
-       if (ipc.status == IDLE_PROF_STATUS_CALI_STOP)
+       if (ipc.status == IDLE_PROF_STATUS_CALI_STOP) {
+               pthread_mutex_unlock(&ipt->start_lock);
                return NULL;
+       }
 
        fio_gettime(&ipt->tps, NULL);
        ipt->state = TD_RUNNING;
@@ -336,7 +342,10 @@ void fio_idle_prof_stop(void)
                /* calculate idleness */
                if (ipc.cali_mean != 0.0) {
                        runt = utime_since(&ipt->tps, &ipt->tpe);
-                       ipt->idleness = ipt->loops * ipc.cali_mean / runt;
+                       if (runt)
+                               ipt->idleness = ipt->loops * ipc.cali_mean / runt;
+                       else
+                               ipt->idleness = 0.0;
                } else
                        ipt->idleness = 0.0;
        }
diff --git a/init.c b/init.c
index 910f2badbcfda054d8a6f300575093eabb572924..4c5a8dd8ebab33bd28bb6c1a6b12864910cb7aff 100644 (file)
--- a/init.c
+++ b/init.c
@@ -38,7 +38,7 @@ const char fio_version_string[] = FIO_VERSION;
 static char **ini_file;
 static int max_jobs = FIO_MAX_JOBS;
 static int dump_cmdline;
-static int def_timeout;
+static long long def_timeout;
 static int parse_only;
 
 static struct thread_data def_thread;
@@ -318,6 +318,14 @@ static int setup_thread_area(void)
        return 0;
 }
 
+static void set_cmd_options(struct thread_data *td)
+{
+       struct thread_options *o = &td->o;
+
+       if (!o->timeout)
+               o->timeout = def_timeout;
+}
+
 /*
  * Return a free job structure.
  */
@@ -326,8 +334,10 @@ static struct thread_data *get_new_job(int global, struct thread_data *parent,
 {
        struct thread_data *td;
 
-       if (global)
+       if (global) {
+               set_cmd_options(&def_thread);
                return &def_thread;
+       }
        if (setup_thread_area()) {
                log_err("error: failed to setup shm segment\n");
                return NULL;
@@ -354,9 +364,10 @@ static struct thread_data *get_new_job(int global, struct thread_data *parent,
 
        td->thread_number = thread_number;
 
-       if (!parent || !parent->o.group_reporting)
+       if (!parent->o.group_reporting)
                stat_number++;
 
+       set_cmd_options(td);
        return td;
 }
 
@@ -926,11 +937,12 @@ static struct fpre_keyword {
        { .keyword = NULL, },
        };
 
-static char *make_filename(char *buf, struct thread_options *o,
+static char *make_filename(char *buf, size_t buf_size,struct thread_options *o,
                           const char *jobname, int jobnum, int filenum)
 {
        struct fpre_keyword *f;
        char copy[PATH_MAX];
+       size_t dst_left = PATH_MAX - 1;
 
        if (!o->filename_format || !strlen(o->filename_format)) {
                sprintf(buf, "%s.%d.%d", jobname, jobnum, filenum);
@@ -940,7 +952,9 @@ static char *make_filename(char *buf, struct thread_options *o,
        for (f = &fpre_keywords[0]; f->keyword; f++)
                f->strlen = strlen(f->keyword);
 
-       strcpy(buf, o->filename_format);
+       buf[buf_size - 1] = '\0';
+       strncpy(buf, o->filename_format, buf_size - 1);
+
        memset(copy, 0, sizeof(copy));
        for (f = &fpre_keywords[0]; f->keyword; f++) {
                do {
@@ -958,27 +972,49 @@ static char *make_filename(char *buf, struct thread_options *o,
                        if (pre_len) {
                                strncpy(dst, buf, pre_len);
                                dst += pre_len;
+                               dst_left -= pre_len;
                        }
 
                        switch (f->key) {
-                       case FPRE_JOBNAME:
-                               dst += sprintf(dst, "%s", jobname);
+                       case FPRE_JOBNAME: {
+                               int ret;
+
+                               ret = snprintf(dst, dst_left, "%s", jobname);
+                               if (ret < 0)
+                                       break;
+                               dst += ret;
+                               dst_left -= ret;
                                break;
-                       case FPRE_JOBNUM:
-                               dst += sprintf(dst, "%d", jobnum);
+                               }
+                       case FPRE_JOBNUM: {
+                               int ret;
+
+                               ret = snprintf(dst, dst_left, "%d", jobnum);
+                               if (ret < 0)
+                                       break;
+                               dst += ret;
+                               dst_left -= ret;
                                break;
-                       case FPRE_FILENUM:
-                               dst += sprintf(dst, "%d", filenum);
+                               }
+                       case FPRE_FILENUM: {
+                               int ret;
+
+                               ret = snprintf(dst, dst_left, "%d", filenum);
+                               if (ret < 0)
+                                       break;
+                               dst += ret;
+                               dst_left -= ret;
                                break;
+                               }
                        default:
                                assert(0);
                                break;
                        }
 
                        if (post_start)
-                               strcpy(dst, buf + post_start);
+                               strncpy(dst, buf + post_start, dst_left);
 
-                       strcpy(buf, copy);
+                       strncpy(buf, copy, buf_size - 1);
                } while (1);
        }
 
@@ -1038,7 +1074,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                        add_file(td, jobname, job_add_num, 0);
                else {
                        for (i = 0; i < o->nr_files; i++)
-                               add_file(td, make_filename(fname, o, jobname, job_add_num, i), job_add_num, 0);
+                               add_file(td, make_filename(fname, sizeof(fname), o, jobname, job_add_num, i), job_add_num, 0);
                }
        }
 
@@ -1424,9 +1460,6 @@ int parse_jobs_ini(char *file, int is_buf, int stonewall_flag, int type)
                i++;
        }
 
-       for (i = 0; i < num_opts; i++)
-               free(opts[i]);
-
        free(string);
        free(name);
        free(opts);
@@ -1440,8 +1473,8 @@ static int fill_def_thread(void)
        memset(&def_thread, 0, sizeof(def_thread));
 
        fio_getaffinity(getpid(), &def_thread.o.cpumask);
-       def_thread.o.timeout = def_timeout;
        def_thread.o.error_dump = 1;
+
        /*
         * fill default options
         */
@@ -1683,8 +1716,6 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
        optind = 1;
 
        while ((c = getopt_long_only(argc, argv, ostr, l_opts, &lidx)) != -1) {
-               did_arg = 1;
-
                if ((c & FIO_CLIENT_FLAG) || client_flag_set(c)) {
                        parse_cmd_client(cur_client, argv[optind - 1]);
                        c &= ~FIO_CLIENT_FLAG;
@@ -1695,7 +1726,11 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        smalloc_pool_size = atoi(optarg);
                        break;
                case 't':
-                       def_timeout = atoi(optarg);
+                       if (check_str_time(optarg, &def_timeout, 1)) {
+                               log_err("fio: failed parsing time %s\n", optarg);
+                               do_exit++;
+                               exit_val = 1;
+                       }
                        break;
                case 'l':
                        write_lat_log = 1;
@@ -1704,6 +1739,9 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        write_bw_log = 1;
                        break;
                case 'o':
+                       if (f_out)
+                               fclose(f_out);
+
                        f_out = fopen(optarg, "w+");
                        if (!f_out) {
                                perror("fopen output");
@@ -1734,30 +1772,35 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        append_terse_output = 1;
                        break;
                case 'h':
+                       did_arg = 1;
                        if (!cur_client) {
                                usage(argv[0]);
                                do_exit++;
                        }
                        break;
                case 'c':
+                       did_arg = 1;
                        if (!cur_client) {
                                fio_show_option_help(optarg);
                                do_exit++;
                        }
                        break;
                case 'i':
+                       did_arg = 1;
                        if (!cur_client) {
                                fio_show_ioengine_help(optarg);
                                do_exit++;
                        }
                        break;
                case 's':
+                       did_arg = 1;
                        dump_cmdline = 1;
                        break;
                case 'r':
                        read_only = 1;
                        break;
                case 'v':
+                       did_arg = 1;
                        if (!cur_client) {
                                log_info("%s\n", fio_version_string);
                                do_exit++;
@@ -1794,6 +1837,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                                do_exit++;
                        break;
                case 'P':
+                       did_arg = 1;
                        parse_only = 1;
                        break;
                case 'x': {
@@ -1813,6 +1857,9 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        break;
                        }
                case 'p':
+                       did_arg = 1;
+                       if (exec_profile)
+                               free(exec_profile);
                        exec_profile = strdup(optarg);
                        break;
                case FIO_GETOPT_JOB: {
@@ -1822,8 +1869,9 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        if (!strncmp(opt, "name", 4) && td) {
                                ret = add_job(td, td->o.name ?: "fio", 0, 0, client_type);
                                if (ret)
-                                       return 0;
+                                       goto out_free;
                                td = NULL;
+                               did_arg = 1;
                        }
                        if (!td) {
                                int is_section = !strncmp(opt, "name", 4);
@@ -1837,7 +1885,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
 
                                td = get_new_job(global, &def_thread, 1);
                                if (!td || ioengine_load(td))
-                                       return 0;
+                                       goto out_free;
                                fio_options_set_ioengine_opts(l_opts, td);
                        }
 
@@ -1859,7 +1907,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        if (!ret && !strcmp(opt, "ioengine")) {
                                free_ioengine(td);
                                if (ioengine_load(td))
-                                       return 0;
+                                       goto out_free;
                                fio_options_set_ioengine_opts(l_opts, td);
                        }
                        break;
@@ -1867,6 +1915,10 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                case FIO_GETOPT_IOENGINE: {
                        const char *opt = l_opts[lidx].name;
                        char *val = optarg;
+
+                       if (!td)
+                               break;
+
                        ret = fio_cmd_ioengine_option_parse(td, opt, val);
                        break;
                }
@@ -1882,6 +1934,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        }
                        break;
                case 'S':
+                       did_arg = 1;
                        if (nr_clients) {
                                log_err("fio: can't be both client and server\n");
                                do_exit++;
@@ -1894,17 +1947,21 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        backend = 1;
                        break;
                case 'D':
+                       if (pid_file)
+                               free(pid_file);
                        pid_file = strdup(optarg);
                        break;
                case 'I':
                        if ((ret = fio_idle_prof_parse_opt(optarg))) {
                                /* exit on error and calibration only */
+                               did_arg = 1;
                                do_exit++;
-                               if (ret == -1) 
+                               if (ret == -1)
                                        exit_val = 1;
                        }
                        break;
                case 'C':
+                       did_arg = 1;
                        if (is_backend) {
                                log_err("fio: can't be both client and server\n");
                                do_exit++;
@@ -1931,10 +1988,12 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        }
                        break;
                case 'T':
+                       did_arg = 1;
                        do_exit++;
                        exit_val = fio_monotonic_clocktest();
                        break;
                case 'G':
+                       did_arg = 1;
                        do_exit++;
                        exit_val = fio_crctest(optarg);
                        break;
@@ -1970,10 +2029,15 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
 
        if (is_backend && backend)
                return fio_start_server(pid_file);
+       else if (pid_file)
+               free(pid_file);
 
        if (td) {
-               if (!ret)
+               if (!ret) {
                        ret = add_job(td, td->o.name ?: "fio", 0, 0, client_type);
+                       if (ret)
+                               did_arg = 1;
+               }
        }
 
        while (!ret && optind < argc) {
@@ -1983,6 +2047,10 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                optind++;
        }
 
+out_free:
+       if (pid_file)
+               free(pid_file);
+
        return ini_idx;
 }
 
@@ -2018,7 +2086,7 @@ int parse_options(int argc, char *argv[])
 
        if (job_files > 0) {
                for (i = 0; i < job_files; i++) {
-                       if (fill_def_thread())
+                       if (i && fill_def_thread())
                                return 1;
                        if (nr_clients) {
                                if (fio_clients_send_ini(ini_file[i]))
diff --git a/io_u.c b/io_u.c
index 411da3249796987d698e475380824022dca6d12d..e132fd9d2d98bab78eae9af8c8706a1e30b07c98 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -678,7 +678,7 @@ static void set_rw_ddir(struct thread_data *td, struct io_u *io_u)
 
 void put_file_log(struct thread_data *td, struct fio_file *f)
 {
-       int ret = put_file(td, f);
+       unsigned int ret = put_file(td, f);
 
        if (ret)
                td_verror(td, ret, "file close");
@@ -1622,8 +1622,15 @@ static void io_completed(struct thread_data *td, struct io_u *io_u,
         * Mark IO ok to verify
         */
        if (io_u->ipo) {
-               io_u->ipo->flags &= ~IP_F_IN_FLIGHT;
-               write_barrier();
+               /*
+                * Remove errored entry from the verification list
+                */
+               if (io_u->error)
+                       unlog_io_piece(td, io_u);
+               else {
+                       io_u->ipo->flags &= ~IP_F_IN_FLIGHT;
+                       write_barrier();
+               }
        }
 
        td_io_u_unlock(td);
index 3c75fa6bfed6812e9027e832ff0d26505034b7d9..0f94d0d9513da64337bbb23284ebb09001b2ebd9 100644 (file)
@@ -375,6 +375,9 @@ int td_io_init(struct thread_data *td)
                        td->error = ret;
        }
 
+       if (!ret && (td->io_ops->flags & FIO_NOIO))
+               td->flags |= TD_F_NOIO;
+
        return ret;
 }
 
diff --git a/iolog.c b/iolog.c
index e805eaef9a94595cb5327becf0eb931362179b8a..cac1aba21e8bb5b2b53a4e957ebebfd0a13eaf1a 100644 (file)
--- a/iolog.c
+++ b/iolog.c
@@ -58,6 +58,7 @@ void log_file(struct thread_data *td, struct fio_file *f,
 static void iolog_delay(struct thread_data *td, unsigned long delay)
 {
        unsigned long usec = utime_since_now(&td->last_issue);
+       unsigned long this_delay;
 
        if (delay < usec)
                return;
@@ -70,7 +71,14 @@ static void iolog_delay(struct thread_data *td, unsigned long delay)
        if (delay < 100)
                return;
 
-       usec_sleep(td, delay);
+       while (delay && !td->terminate) {
+               this_delay = delay;
+               if (this_delay > 500000)
+                       this_delay = 500000;
+
+               usec_sleep(td, this_delay);
+               delay -= this_delay;
+       }
 }
 
 static int ipo_special(struct thread_data *td, struct io_piece *ipo)
@@ -260,6 +268,33 @@ restart:
        td->io_hist_len++;
 }
 
+void unlog_io_piece(struct thread_data *td, struct io_u *io_u)
+{
+       struct io_piece *ipo = io_u->ipo;
+
+       if (!ipo)
+               return;
+
+       if (ipo->flags & IP_F_ONRB)
+               rb_erase(&ipo->rb_node, &td->io_hist_tree);
+       else if (ipo->flags & IP_F_ONLIST)
+               flist_del(&ipo->list);
+
+       free(ipo);
+       io_u->ipo = NULL;
+       td->io_hist_len--;
+}
+
+void trim_io_piece(struct thread_data *td, struct io_u *io_u)
+{
+       struct io_piece *ipo = io_u->ipo;
+
+       if (!ipo)
+               return;
+
+       ipo->len = io_u->xfer_buflen - io_u->resid;
+}
+
 void write_iolog_close(struct thread_data *td)
 {
        fflush(td->iolog_f);
@@ -371,7 +406,7 @@ static int read_iolog2(struct thread_data *td, FILE *f)
                } else {
                        ipo->offset = offset;
                        ipo->len = bytes;
-                       if (bytes > td->o.max_bs[rw])
+                       if (rw != DDIR_INVAL && bytes > td->o.max_bs[rw])
                                td->o.max_bs[rw] = bytes;
                        ipo->fileno = fileno;
                        ipo->file_action = file_action;
diff --git a/iolog.h b/iolog.h
index 50d09e26bfbe3a3abe49d1b56c414a38854b5417..3af56682c64eaeecbd35e19c753cb315ecabec80 100644 (file)
--- a/iolog.h
+++ b/iolog.h
@@ -110,6 +110,8 @@ extern void log_io_u(struct thread_data *, struct io_u *);
 extern void log_file(struct thread_data *, struct fio_file *, enum file_log_act);
 extern int __must_check init_iolog(struct thread_data *td);
 extern void log_io_piece(struct thread_data *, struct io_u *);
+extern void unlog_io_piece(struct thread_data *, struct io_u *);
+extern void trim_io_piece(struct thread_data *, struct io_u *);
 extern void queue_io_piece(struct thread_data *, struct io_piece *);
 extern void prune_io_piece_log(struct thread_data *);
 extern void write_iolog_close(struct thread_data *);
index 12d6f39aa5dbca892e9d03af9150aa28a3a47861..896186888716424f13ecf0dc174a416cffeb7bd6 100644 (file)
@@ -4,6 +4,8 @@
 
 #include "../fio.h"
 
+#define ARRAY_LENGTH(arr)      sizeof(arr) / sizeof((arr)[0])
+
 /*
  * Cheesy number->string conversion, complete with carry rounding error.
  */
@@ -46,6 +48,9 @@ char *num2str(unsigned long num, int maxlen, int base, int pow2, int unit_base)
 
        if (modulo == -1U) {
 done:
+               if (post_index >= ARRAY_LENGTH(postfix))
+                       post_index = 0;
+
                sprintf(buf, "%lu%s%s", num, postfix[post_index],
                        byte_postfix[byte_post_index]);
                return buf;
index 1fd77e40770065f6c6dfcc0b8c7e80600f188b2e..8af11297e17c5eed31bd3e23df72ed40c1bfab25 100644 (file)
--- a/libfio.c
+++ b/libfio.c
@@ -27,6 +27,7 @@
 #include <signal.h>
 #include <stdint.h>
 #include <locale.h>
+#include <fcntl.h>
 
 #include "fio.h"
 #include "smalloc.h"
@@ -218,6 +219,39 @@ void fio_terminate_threads(int group_id)
        }
 }
 
+int fio_running_or_pending_io_threads(void)
+{
+       struct thread_data *td;
+       int i;
+
+       for_each_td(td, i) {
+               if (td->flags & TD_F_NOIO)
+                       continue;
+               if (td->runstate < TD_EXITED)
+                       return 1;
+       }
+
+       return 0;
+}
+
+int fio_set_fd_nonblocking(int fd, const char *who)
+{
+       int flags;
+
+       flags = fcntl(fd, F_GETFL);
+       if (flags < 0)
+               log_err("fio: %s failed to get file flags: %s\n", who, strerror(errno));
+       else {
+               int new_flags = flags | O_NONBLOCK;
+
+               new_flags = fcntl(fd, F_SETFL, new_flags);
+               if (new_flags < 0)
+                       log_err("fio: %s failed to get file flags: %s\n", who, strerror(errno));
+       }
+
+       return flags;
+}
+
 static int endian_check(void)
 {
        union {
index b208320c5d88cc619f7167626e3b7502ded07799..8c06d94d85e7a48ecfb5d8681a8780658f567f6c 100644 (file)
--- a/memory.c
+++ b/memory.c
@@ -158,9 +158,10 @@ static int alloc_mem_mmap(struct thread_data *td, size_t total_mem)
        if (td->orig_buffer == MAP_FAILED) {
                td_verror(td, errno, "mmap");
                td->orig_buffer = NULL;
-               if (td->mmapfd) {
+               if (td->mmapfd != 1) {
                        close(td->mmapfd);
-                       unlink(td->o.mmapfile);
+                       if (td->o.mmapfile)
+                               unlink(td->o.mmapfile);
                }
 
                return 1;
diff --git a/mutex.c b/mutex.c
index 466e20ed1111ea0cad675165b8eea9ab298a7ef2..9d10c2ce2fe056fefd300ebf16274f85701fa7c6 100644 (file)
--- a/mutex.c
+++ b/mutex.c
@@ -15,7 +15,7 @@
 #include "arch/arch.h"
 #include "os/os.h"
 #include "helpers.h"
-#include "time.h"
+#include "fio_time.h"
 #include "gettime.h"
 
 void fio_mutex_remove(struct fio_mutex *mutex)
index 4a54c98c15045864931ea503d3f7920bab4ae431..d5bf00c38fbbccd00b394f1219bb0d0b63d84f6f 100644 (file)
--- a/options.c
+++ b/options.c
@@ -269,7 +269,7 @@ static int ignore_error_type(struct thread_data *td, int etype, char *str)
                } else {
                        error[i] = atoi(fname);
                        if (error[i] < 0)
-                               error[i] = error[i];
+                               error[i] = -error[i];
                }
                if (!error[i]) {
                        log_err("Unknown error %s, please use number value \n",
@@ -283,7 +283,9 @@ static int ignore_error_type(struct thread_data *td, int etype, char *str)
                td->o.continue_on_error |= 1 << etype;
                td->o.ignore_error_nr[etype] = i;
                td->o.ignore_error[etype] = error;
-       }
+       } else
+               free(error);
+
        return 0;
 
 }
@@ -320,7 +322,7 @@ static int str_rw_cb(void *data, const char *str)
 {
        struct thread_data *td = data;
        struct thread_options *o = &td->o;
-       char *nr = get_opt_postfix(str);
+       char *nr;
 
        if (parse_dryrun())
                return 0;
@@ -328,6 +330,7 @@ static int str_rw_cb(void *data, const char *str)
        o->ddir_seq_nr = 1;
        o->ddir_seq_add = 0;
 
+       nr = get_opt_postfix(str);
        if (!nr)
                return 0;
 
@@ -551,6 +554,7 @@ static int str_verify_cpus_allowed_cb(void *data, const char *input)
 static int str_numa_cpunodes_cb(void *data, char *input)
 {
        struct thread_data *td = data;
+       struct bitmask *verify_bitmask;
 
        if (parse_dryrun())
                return 0;
@@ -560,13 +564,15 @@ static int str_numa_cpunodes_cb(void *data, char *input)
         * numa_allocate_nodemask(), so it should be freed by
         * numa_free_nodemask().
         */
-       td->o.numa_cpunodesmask = numa_parse_nodestring(input);
-       if (td->o.numa_cpunodesmask == NULL) {
+       verify_bitmask = numa_parse_nodestring(input);
+       if (verify_bitmask == NULL) {
                log_err("fio: numa_parse_nodestring failed\n");
                td_verror(td, 1, "str_numa_cpunodes_cb");
                return 1;
        }
+       numa_free_nodemask(verify_bitmask);
 
+       td->o.numa_cpunodes = strdup(input);
        td->o.numa_cpumask_set = 1;
        return 0;
 }
@@ -578,6 +584,7 @@ static int str_numa_mpol_cb(void *data, char *input)
                { "default", "prefer", "bind", "interleave", "local", NULL };
        int i;
        char *nodelist;
+       struct bitmask *verify_bitmask;
 
        if (parse_dryrun())
                return 0;
@@ -657,12 +664,15 @@ static int str_numa_mpol_cb(void *data, char *input)
                break;
        case MPOL_INTERLEAVE:
        case MPOL_BIND:
-               td->o.numa_memnodesmask = numa_parse_nodestring(nodelist);
-               if (td->o.numa_memnodesmask == NULL) {
+               verify_bitmask = numa_parse_nodestring(nodelist);
+               if (verify_bitmask == NULL) {
                        log_err("fio: numa_parse_nodestring failed\n");
                        td_verror(td, 1, "str_numa_memnodes_cb");
                        return 1;
                }
+               td->o.numa_memnodes = strdup(nodelist);
+               numa_free_nodemask(verify_bitmask);
+                
                break;
        case MPOL_LOCAL:
        case MPOL_DEFAULT:
@@ -1523,6 +1533,15 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                            .help = "fallocate() file based engine",
                          },
 #endif
+#ifdef CONFIG_GFAPI
+                         { .ival = "gfapi",
+                           .help = "Glusterfs libgfapi(sync) based engine"
+                         },
+                         { .ival = "gfapi_async",
+                           .help = "Glusterfs libgfapi(async) based engine"
+                         },
+#endif
+
                          { .ival = "external",
                            .help = "Load external engine (append name)",
                          },
@@ -1591,6 +1610,15 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_INVALID,
        },
+       {
+               .name   = "io_limit",
+               .lname  = "IO Limit",
+               .type   = FIO_OPT_STR_VAL,
+               .off1   = td_var_offset(io_limit),
+               .interval = 1024 * 1024,
+               .category = FIO_OPT_C_IO,
+               .group  = FIO_OPT_G_INVALID,
+       },
        {
                .name   = "fill_device",
                .lname  = "Fill device",
@@ -3653,8 +3681,10 @@ static char *bc_calc(char *str)
                return NULL;
 
        ret = fread(&buf[tmp - str], 1, 128 - (tmp - str), f);
-       if (ret <= 0)
+       if (ret <= 0) {
+               pclose(f);
                return NULL;
+       }
 
        pclose(f);
        buf[(tmp - str) + ret - 1] = '\0';
index de9f6109fa1b474e72a1b60df667f99f7455735d..b2e2c0c8fed232f9213a8647d81f266a82cae3dd 100644 (file)
--- a/options.h
+++ b/options.h
@@ -98,6 +98,7 @@ enum opt_category_group {
        __FIO_OPT_G_ACT,
        __FIO_OPT_G_LATPROF,
         __FIO_OPT_G_RBD,
+        __FIO_OPT_G_GFAPI,
        __FIO_OPT_G_NR,
 
        FIO_OPT_G_RATE          = (1U << __FIO_OPT_G_RATE),
@@ -128,6 +129,7 @@ enum opt_category_group {
        FIO_OPT_G_ACT           = (1U << __FIO_OPT_G_ACT),
        FIO_OPT_G_LATPROF       = (1U << __FIO_OPT_G_LATPROF),
        FIO_OPT_G_RBD           = (1U << __FIO_OPT_G_RBD),
+       FIO_OPT_G_GFAPI         = (1U << __FIO_OPT_G_GFAPI),
        FIO_OPT_G_INVALID       = (1U << __FIO_OPT_G_NR),
 };
 
diff --git a/os/os.h b/os/os.h
index 2f2d06981bdb0cbbdba24e52771551b2ed8a9fbc..b8eee66a14501fd2d083dda2920684940b7cb815 100644 (file)
--- a/os/os.h
+++ b/os/os.h
@@ -200,6 +200,7 @@ static inline uint64_t fio_swap64(uint64_t val)
 #endif
 #endif /* FIO_HAVE_BYTEORDER_FUNCS */
 
+#ifdef FIO_INTERNAL
 #define le16_to_cpu(val) ({                    \
        __le16_to_cpu(val);                     \
 })
@@ -209,6 +210,8 @@ static inline uint64_t fio_swap64(uint64_t val)
 #define le64_to_cpu(val) ({                    \
        __le64_to_cpu(val);                             \
 })
+#endif
+
 #define cpu_to_le16(val) ({                    \
        __cpu_to_le16(val);                     \
 })
@@ -321,7 +324,7 @@ static inline unsigned int cpus_online(void)
 }
 #endif
 
-#ifndef CONFIG_CPU_COUNT
+#ifndef CPU_COUNT
 #ifdef FIO_HAVE_CPU_AFFINITY
 static inline int CPU_COUNT(os_cpu_mask_t *mask)
 {
index 78204499bd70ba4186475af2a15c1d1d644ca11e..bd89a7bf1850001894f681e253fe8229582753ed 100755 (executable)
@@ -10,7 +10,7 @@
        <Product Id="*"
          Codepage="1252" Language="1033"
          Manufacturer="fio" Name="fio"
-         UpgradeCode="2338A332-5511-43CF-B9BD-5C60496CCFCC" Version="2.1.7">
+         UpgradeCode="2338A332-5511-43CF-B9BD-5C60496CCFCC" Version="2.1.9">
                <Package
                  Description="Flexible IO Tester"
                  InstallerVersion="301" Keywords="Installer,MSI,Database"
index b9ea63016c2ac73c18670d222628e171458777f4..e418c6dd9d14eff5fc08f3a3ad7a71154bf0f4e8 100644 (file)
@@ -7,7 +7,7 @@ typedef int in_port_t;
  struct sockaddr_un
  {
        sa_family_t     sun_family; /* Address family */
-       char            sun_path[]; /* Socket pathname */
+       char            sun_path[260]; /* Socket pathname */
 };
 
 #endif /* SYS_UN_H */
diff --git a/parse.c b/parse.c
index 83c59f7026ca7e06b5371d59adfb2b0bd2d39b35..188f72826185d2a1c3dba8f48bca01ccfa2a1e56 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -624,7 +624,7 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data,
                        ret = 1;
                        for (i = 0; i < PARSE_MAX_VP; i++) {
                                vp = &posval[i];
-                               if (!vp->ival || vp->ival[0] == '\0')
+                               if (!vp->ival || vp->ival[0] == '\0' || !cp)
                                        continue;
                                all_skipped = 0;
                                if (!strncmp(vp->ival, ptr, str_match_len(vp, ptr))) {
index d72835b72690148fc78662fb99599465e2836a55..077dce5c349f67efec5c76a6371e89e2a2a4724f 100644 (file)
--- a/server.c
+++ b/server.c
@@ -4,7 +4,6 @@
 #include <unistd.h>
 #include <limits.h>
 #include <errno.h>
-#include <fcntl.h>
 #include <sys/poll.h>
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -68,7 +67,7 @@ static const char *fio_server_ops[FIO_NET_CMD_NR] = {
        "DISK_UTIL",
        "SERVER_START",
        "ADD_JOB",
-       "CMD_RUN"
+       "CMD_RUN",
        "CMD_IOLOG",
 };
 
@@ -209,7 +208,7 @@ static int verify_convert_cmd(struct fio_net_cmd *cmd)
  */
 struct fio_net_cmd *fio_net_recv_cmd(int sk)
 {
-       struct fio_net_cmd cmd, *cmdret = NULL;
+       struct fio_net_cmd cmd, *tmp, *cmdret = NULL;
        size_t cmd_size = 0, pdu_offset = 0;
        uint16_t crc;
        int ret, first = 1;
@@ -232,7 +231,19 @@ struct fio_net_cmd *fio_net_recv_cmd(int sk)
                } else
                        cmd_size += cmd.pdu_len;
 
-               cmdret = realloc(cmdret, cmd_size);
+               if (cmd_size / 1024 > FIO_SERVER_MAX_CMD_MB * 1024) {
+                       log_err("fio: cmd+pdu too large (%llu)\n", (unsigned long long) cmd_size);
+                       ret = 1;
+                       break;
+               }
+
+               tmp = realloc(cmdret, cmd_size);
+               if (!tmp) {
+                       log_err("fio: server failed allocating cmd\n");
+                       ret = 1;
+                       break;
+               }
+               cmdret = tmp;
 
                if (first)
                        memcpy(cmdret, &cmd, sizeof(cmd));
@@ -843,14 +854,12 @@ static int accept_loop(int listen_sk)
        struct sockaddr_in6 addr6;
        socklen_t len = use_ipv6 ? sizeof(addr6) : sizeof(addr);
        struct pollfd pfd;
-       int ret = 0, sk, flags, exitval = 0;
+       int ret = 0, sk, exitval = 0;
        FLIST_HEAD(conn_list);
 
        dprint(FD_NET, "server enter accept loop\n");
 
-       flags = fcntl(listen_sk, F_GETFL);
-       flags |= O_NONBLOCK;
-       fcntl(listen_sk, F_SETFL, flags);
+       fio_set_fd_nonblocking(listen_sk, "server");
 
        while (!exit_backend) {
                const char *from;
@@ -1095,18 +1104,19 @@ static void convert_dus(struct disk_util_stat *dst, struct disk_util_stat *src)
 {
        int i;
 
-       strcpy((char *) dst->name, (char *) src->name);
+       dst->name[FIO_DU_NAME_SZ - 1] = '\0';
+       strncpy((char *) dst->name, (char *) src->name, FIO_DU_NAME_SZ - 1);
 
        for (i = 0; i < 2; i++) {
-               dst->ios[i]     = cpu_to_le32(src->ios[i]);
-               dst->merges[i]  = cpu_to_le32(src->merges[i]);
-               dst->sectors[i] = cpu_to_le64(src->sectors[i]);
-               dst->ticks[i]   = cpu_to_le32(src->ticks[i]);
+               dst->s.ios[i]           = cpu_to_le32(src->s.ios[i]);
+               dst->s.merges[i]        = cpu_to_le32(src->s.merges[i]);
+               dst->s.sectors[i]       = cpu_to_le64(src->s.sectors[i]);
+               dst->s.ticks[i]         = cpu_to_le32(src->s.ticks[i]);
        }
 
-       dst->io_ticks           = cpu_to_le32(src->io_ticks);
-       dst->time_in_queue      = cpu_to_le32(src->time_in_queue);
-       dst->msec               = cpu_to_le64(src->msec);
+       dst->s.io_ticks         = cpu_to_le32(src->s.io_ticks);
+       dst->s.time_in_queue    = cpu_to_le32(src->s.time_in_queue);
+       dst->s.msec             = cpu_to_le64(src->s.msec);
 }
 
 void fio_server_send_du(void)
@@ -1215,7 +1225,9 @@ int fio_send_iolog(struct thread_data *td, struct io_log *log, const char *name)
        pdu.nr_samples = __cpu_to_le32(log->nr_samples);
        pdu.log_type = cpu_to_le32(log->log_type);
        pdu.compressed = cpu_to_le32(use_zlib);
-       strcpy((char *) pdu.name, name);
+
+       strncpy((char *) pdu.name, name, FIO_NET_NAME_MAX);
+       pdu.name[FIO_NET_NAME_MAX - 1] = '\0';
 
        for (i = 0; i < log->nr_samples; i++) {
                struct io_sample *s = &log->log[i];
@@ -1338,7 +1350,7 @@ static int fio_init_server_sock(void)
 
        memset(&addr, 0, sizeof(addr));
        addr.sun_family = AF_UNIX;
-       strcpy(addr.sun_path, bind_sock);
+       strncpy(addr.sun_path, bind_sock, sizeof(addr.sun_path) - 1);
 
        len = sizeof(addr.sun_family) + strlen(bind_sock) + 1;
 
@@ -1367,6 +1379,8 @@ static int fio_init_server_connection(void)
        if (sk < 0)
                return sk;
 
+       memset(bind_str, 0, sizeof(bind_str));
+
        if (!bind_sock) {
                char *p, port[16];
                const void *src;
@@ -1386,14 +1400,15 @@ static int fio_init_server_connection(void)
                if (p)
                        strcat(p, port);
                else
-                       strcpy(bind_str, port);
+                       strncpy(bind_str, port, sizeof(bind_str) - 1);
        } else
-               strcpy(bind_str, bind_sock);
+               strncpy(bind_str, bind_sock, sizeof(bind_str) - 1);
 
        log_info("fio: server listening on %s\n", bind_str);
 
        if (listen(sk, 0) < 0) {
                log_err("fio: listen: %s\n", strerror(errno));
+               close(sk);
                return -1;
        }
 
@@ -1682,6 +1697,7 @@ int fio_start_server(char *pidfile)
        if (check_existing_pidfile(pidfile)) {
                log_err("fio: pidfile %s exists and server appears alive\n",
                                                                pidfile);
+               free(pidfile);
                return -1;
        }
 
@@ -1693,6 +1709,7 @@ int fio_start_server(char *pidfile)
        } else if (pid) {
                int ret = write_pid(pid, pidfile);
 
+               free(pidfile);
                exit(ret);
        }
 
index 3a279f0b1095c33b6e2a6f9fc7155f7a7ad3da35..4f09f2848b93acd426d7e7a48a9898edd9099799 100644 (file)
--- a/server.h
+++ b/server.h
@@ -38,9 +38,10 @@ struct fio_net_cmd_reply {
 };
 
 enum {
-       FIO_SERVER_VER                  = 33,
+       FIO_SERVER_VER                  = 34,
 
        FIO_SERVER_MAX_FRAGMENT_PDU     = 1024,
+       FIO_SERVER_MAX_CMD_MB           = 2048,
 
        FIO_NET_CMD_QUIT                = 1,
        FIO_NET_CMD_EXIT                = 2,
diff --git a/stat.c b/stat.c
index 509c6f02875aee1c648f9e9a432b108a6aa768c8..3adb46eab8087cc53ae0fd2b7c15ad048596c040 100644 (file)
--- a/stat.c
+++ b/stat.c
@@ -831,7 +831,7 @@ static void show_thread_status_terse_v2(struct thread_stat *ts,
        log_info("\n");
 
        /* Additional output if description is set */
-       if (ts->description)
+       if (strlen(ts->description))
                log_info(";%s", ts->description);
 
        log_info("\n");
@@ -1272,10 +1272,12 @@ static void __show_run_stats(void)
                        if (!td->error && td->o.continue_on_error &&
                            td->first_error) {
                                ts->error = td->first_error;
-                               strcpy(ts->verror, td->verror);
+                               ts->verror[sizeof(ts->verror) - 1] = '\0';
+                               strncpy(ts->verror, td->verror, sizeof(ts->verror) - 1);
                        } else  if (td->error) {
                                ts->error = td->error;
-                               strcpy(ts->verror, td->verror);
+                               ts->verror[sizeof(ts->verror) - 1] = '\0';
+                               strncpy(ts->verror, td->verror, sizeof(ts->verror) - 1);
                        }
                }
 
@@ -1471,7 +1473,12 @@ void show_running_run_stats(void)
        fio_mutex_down(stat_mutex);
 
        if (!pthread_create(&thread, NULL, __show_running_run_stats, NULL)) {
-               pthread_detach(thread);
+               int err;
+
+               err = pthread_detach(thread);
+               if (err)
+                       log_err("fio: DU thread detach failed: %s\n", strerror(err));
+
                return;
        }
 
@@ -1494,8 +1501,11 @@ static int check_status_file(void)
                return 0;
 
        temp_dir = getenv("TMPDIR");
-       if (temp_dir == NULL)
+       if (temp_dir == NULL) {
                temp_dir = getenv("TEMP");
+               if (temp_dir && strlen(temp_dir) >= PATH_MAX)
+                       temp_dir = NULL;
+       }
        if (temp_dir == NULL)
                temp_dir = "/tmp";
 
@@ -1800,7 +1810,11 @@ void add_bw_sample(struct thread_data *td, enum fio_ddir ddir, unsigned int bs,
                if (!delta)
                        continue; /* No entries for interval */
 
-               rate = delta * 1000 / spent / 1024;
+               if (spent)
+                       rate = delta * 1000 / spent / 1024;
+               else
+                       rate = 0;
+
                add_stat_sample(&ts->bw_stat[ddir], rate);
 
                if (td->bw_log)
@@ -1835,7 +1849,11 @@ void add_iops_sample(struct thread_data *td, enum fio_ddir ddir, unsigned int bs
                if (!delta)
                        continue; /* No entries for interval */
 
-               iops = (delta * 1000) / spent;
+               if (spent)
+                       iops = (delta * 1000) / spent;
+               else
+                       iops = 0;
+
                add_stat_sample(&ts->iops_stat[ddir], iops);
 
                if (td->iops_log)
index 46421205cdf9f1ba5fb0c3da997adcc98055bda4..57d84dbba3defda3df5ae44fa0880954a3c28a93 100644 (file)
@@ -52,6 +52,7 @@ struct thread_options {
        unsigned int iodepth_batch_complete;
 
        unsigned long long size;
+       unsigned long long io_limit;
        unsigned int size_percent;
        unsigned int fill_device;
        unsigned int file_append;
@@ -157,14 +158,12 @@ struct thread_options {
        os_cpu_mask_t verify_cpumask;
        unsigned int verify_cpumask_set;
        unsigned int cpus_allowed_policy;
-#ifdef CONFIG_LIBNUMA
-       struct bitmask *numa_cpunodesmask;
+       char *numa_cpunodes;
        unsigned int numa_cpumask_set;
        unsigned short numa_mem_mode;
        unsigned int numa_mem_prefer_node;
-       struct bitmask *numa_memnodesmask;
+       char *numa_memnodes;
        unsigned int numa_memmask_set;
-#endif
        unsigned int iolog;
        unsigned int rwmixcycle;
        unsigned int rwmix[DDIR_RWDIR_CNT];
@@ -280,6 +279,7 @@ struct thread_options_pack {
        uint32_t iodepth_batch_complete;
 
        uint64_t size;
+       uint64_t io_limit;
        uint32_t size_percent;
        uint32_t fill_device;
        uint32_t file_append;
diff --git a/time.h b/time.h
deleted file mode 100644 (file)
index c550a55..0000000
--- a/time.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef FIO_TIME_H
-#define FIO_TIME_H
-
-extern uint64_t utime_since(struct timeval *, struct timeval *);
-extern uint64_t utime_since_now(struct timeval *);
-extern uint64_t mtime_since(struct timeval *, struct timeval *);
-extern uint64_t mtime_since_now(struct timeval *);
-extern uint64_t time_since_now(struct timeval *);
-extern uint64_t mtime_since_genesis(void);
-extern uint64_t utime_since_genesis(void);
-extern void usec_spin(unsigned int);
-extern void usec_sleep(struct thread_data *, unsigned long);
-extern void fill_start_time(struct timeval *);
-extern void set_genesis_time(void);
-extern int ramp_time_over(struct thread_data *);
-extern int in_ramp_time(struct thread_data *);
-extern void fio_time_init(void);
-
-#endif
index 9eb532a28e080a66a2483943f09fed16efd9ecfa..282a8cf9558caf704db256692787dfbb887dd4f3 100644 (file)
--- a/verify.c
+++ b/verify.c
@@ -226,16 +226,32 @@ struct vcont {
        unsigned int crc_len;
 };
 
+#define DUMP_BUF_SZ    255
+static int dump_buf_warned;
+
 static void dump_buf(char *buf, unsigned int len, unsigned long long offset,
                     const char *type, struct fio_file *f)
 {
-       char *ptr, fname[256];
+       char *ptr, fname[DUMP_BUF_SZ];
+       size_t buf_left = DUMP_BUF_SZ;
        int ret, fd;
 
        ptr = strdup(f->file_name);
-       strcpy(fname, basename(ptr));
 
-       sprintf(fname + strlen(fname), ".%llu.%s", offset, type);
+       fname[DUMP_BUF_SZ - 1] = '\0';
+       strncpy(fname, basename(ptr), DUMP_BUF_SZ - 1);
+
+       buf_left -= strlen(fname);
+       if (buf_left <= 0) {
+               if (!dump_buf_warned) {
+                       log_err("fio: verify failure dump buffer too small\n");
+                       dump_buf_warned = 1;
+               }
+               free(ptr);
+               return;
+       }
+
+       snprintf(fname + strlen(fname), buf_left, ".%llu.%s", offset, type);
 
        fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, 0644);
        if (fd < 0) {