Merge branch 'patch-1' of https://github.com/avlasov-mos-de/fio
authorJens Axboe <axboe@kernel.dk>
Sat, 18 Jul 2020 14:39:04 +0000 (08:39 -0600)
committerJens Axboe <axboe@kernel.dk>
Sat, 18 Jul 2020 14:39:04 +0000 (08:39 -0600)
* 'patch-1' of https://github.com/avlasov-mos-de/fio:
  Fix scale on gnuplot graphs

50 files changed:
.appveyor.yml
.gitignore
HOWTO
Makefile
arch/arch.h
backend.c
compiler/compiler-gcc4.h [deleted file]
compiler/compiler.h
configure
engines/dev-dax.c
engines/guasi.c
engines/http.c
engines/io_uring.c
engines/libaio.c
engines/libhdfs.c
engines/libiscsi.c
engines/libpmem.c
engines/libzbc.c
engines/nbd.c
engines/pmemblk.c
engines/rados.c
engines/rbd.c
engines/rdma.c
fio.1
fio_sem.c
gettime-thread.c
gettime.h
init.c
io_u.c
ioengines.c
ioengines.h
lib/num2str.c
lib/rand.h
lib/seqlock.h
os/os-linux.h
os/windows/posix.c
oslib/linux-blkzoned.c
rate-submit.c
t/debug.c
t/io_uring.c
t/jobs/t0012.fio [new file with mode: 0644]
t/jobs/t0013.fio [new file with mode: 0644]
t/run-fio-tests.py
t/zbd/test-zbd-support
unittests/lib/num2str.c [new file with mode: 0644]
unittests/unittest.c
unittests/unittest.h
verify.c
workqueue.c
zbd.c

index 70c337f8465cc3a10e9ac0c085d33a234a4ed282..5f4a33e24c20fb0c354f1b21f367d7e5ec8a03a9 100644 (file)
@@ -1,5 +1,8 @@
 clone_depth: 1 # NB: this stops FIO-VERSION-GEN making tag based versions
 
+image:
+  - Visual Studio 2019
+
 environment:
   CYG_MIRROR: http://cygwin.mirror.constant.com
   CYG_ROOT: C:\cygwin64
index b84b0fda0aa71750c28a316322761af6d1aca0f6..0aa4a3611c031024f631418fee0fad1ba94d0cae 100644 (file)
@@ -1,5 +1,6 @@
 *.d
 *.o
+*.so
 *.exe
 /.depend
 /FIO-VERSION-FILE
diff --git a/HOWTO b/HOWTO
index 9e339bb8d0a608a2f83b141197bd1bbbb503804b..8cf8d6506b219e0f9933813616a7d682218adb24 100644 (file)
--- a/HOWTO
+++ b/HOWTO
@@ -4165,7 +4165,7 @@ Fio supports a variety of log file formats, for logging latencies, bandwidth,
 and IOPS. The logs share a common format, which looks like this:
 
     *time* (`msec`), *value*, *data direction*, *block size* (`bytes`),
-    *offset* (`bytes`)
+    *offset* (`bytes`), *command priority*
 
 *Time* for the log entry is always in milliseconds. The *value* logged depends
 on the type of log, it will be one of the following:
@@ -4190,6 +4190,9 @@ The entry's *block size* is always in bytes. The *offset* is the position in byt
 from the start of the file for that particular I/O. The logging of the offset can be
 toggled with :option:`log_offset`.
 
+*Command priority* is 0 for normal priority and 1 for high priority. This is controlled
+by the ioengine specific :option:`cmdprio_percentage`.
+
 Fio defaults to logging every individual I/O but when windowed logging is set
 through :option:`log_avg_msec`, either the average (by default) or the maximum
 (:option:`log_max_value` is set) *value* seen over the specified period of time
index 7eb5e899df994ee822ac1043737404e18c79026a..f374ac841b9af43afb23975c5a18fcd30a468c36 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -60,15 +60,17 @@ ifdef CONFIG_LIBHDFS
 endif
 
 ifdef CONFIG_LIBISCSI
-  CFLAGS := $(LIBISCSI_CFLAGS) $(CFLAGS)
-  LIBS += $(LIBISCSI_LIBS)
-  SOURCE += engines/libiscsi.c
+  iscsi_SRCS = engines/libiscsi.c
+  iscsi_LIBS = $(LIBISCSI_LIBS)
+  iscsi_CFLAGS = $(LIBISCSI_LIBS)
+  ENGINES += iscsi
 endif
 
 ifdef CONFIG_LIBNBD
-  CFLAGS := $(LIBNBD_CFLAGS) $(CFLAGS)
-  LIBS += $(LIBNBD_LIBS)
-  SOURCE += engines/nbd.c
+  nbd_SRCS = engines/nbd.c
+  nbd_LIBS = $(LIBNBD_LIBS)
+  nbd_CFLAGS = $(LIBNBD_CFLAGS)
+  ENGINES += nbd
 endif
 
 ifdef CONFIG_64BIT
@@ -78,10 +80,19 @@ ifdef CONFIG_32BIT
   CFLAGS := -DBITS_PER_LONG=32 $(CFLAGS)
 endif
 ifdef CONFIG_LIBAIO
-  SOURCE += engines/libaio.c
+  aio_SRCS = engines/libaio.c
+  aio_LIBS = -laio
+  ifdef CONFIG_LIBAIO_URING
+    aio_LIBS = -luring
+  else
+    aio_LIBS = -laio
+  endif
+  ENGINES += aio
 endif
 ifdef CONFIG_RDMA
-  SOURCE += engines/rdma.c
+  rdma_SRCS = engines/rdma.c
+  rdma_LIBS = -libverbs -lrdmacm
+  ENGINES += rdma
 endif
 ifdef CONFIG_POSIXAIO
   SOURCE += engines/posixaio.c
@@ -96,7 +107,8 @@ ifdef CONFIG_LINUX_SPLICE
   SOURCE += engines/splice.c
 endif
 ifdef CONFIG_GUASI
-  SOURCE += engines/guasi.c
+  guasi_SRCS = engines/guasi.c
+  ENGINES += guasi
 endif
 ifdef CONFIG_SOLARISAIO
   SOURCE += engines/solarisaio.c
@@ -105,13 +117,19 @@ ifdef CONFIG_WINDOWSAIO
   SOURCE += engines/windowsaio.c
 endif
 ifdef CONFIG_RADOS
-  SOURCE += engines/rados.c
+  rados_SRCS = engines/rados.c
+  rados_LIBS = -lrados
+  ENGINES += rados
 endif
 ifdef CONFIG_RBD
-  SOURCE += engines/rbd.c
+  rbd_SRCS = engines/rbd.c
+  rbd_LIBS = -lrbd -lrados
+  ENGINES += rbd
 endif
 ifdef CONFIG_HTTP
-  SOURCE += engines/http.c
+  http_SRCS = engines/http.c
+  http_LIBS = -lcurl -lssl -lcrypto
+  ENGINES += http
 endif
 SOURCE += oslib/asprintf.c
 ifndef CONFIG_STRSEP
@@ -139,6 +157,7 @@ ifdef CONFIG_GFAPI
   SOURCE += engines/glusterfs.c
   SOURCE += engines/glusterfs_sync.c
   SOURCE += engines/glusterfs_async.c
+  LIBS += -lgfapi -lglusterfs
   ifdef CONFIG_GF_FADVISE
     CFLAGS := "-DGFAPI_USE_FADVISE" $(CFLAGS)
   endif
@@ -149,19 +168,27 @@ ifdef CONFIG_MTD
   SOURCE += oslib/libmtd_legacy.c
 endif
 ifdef CONFIG_PMEMBLK
-  SOURCE += engines/pmemblk.c
+  pmemblk_SRCS = engines/pmemblk.c
+  pmemblk_LIBS = -lpmemblk
+  ENGINES += pmemblk
 endif
 ifdef CONFIG_LINUX_DEVDAX
-  SOURCE += engines/dev-dax.c
+  dev-dax_SRCS = engines/dev-dax.c
+  dev-dax_LIBS = -lpmem
+  ENGINES += dev-dax
 endif
 ifdef CONFIG_LIBPMEM
-  SOURCE += engines/libpmem.c
+  pmem_SRCS = engines/libpmem.c
+  pmem_LIBS = -lpmem
+  ENGINES += pmem
 endif
 ifdef CONFIG_IME
   SOURCE += engines/ime.c
 endif
 ifdef CONFIG_LIBZBC
-  SOURCE += engines/libzbc.c
+  zbc_SRCS = engines/libzbc.c
+  zbc_LIBS = -lzbc
+  ENGINES += zbc
 endif
 
 ifeq ($(CONFIG_TARGET_OS), Linux)
@@ -223,6 +250,26 @@ ifneq (,$(findstring CYGWIN,$(CONFIG_TARGET_OS)))
   CFLAGS := -DPSAPI_VERSION=1 -Ios/windows/posix/include -Wno-format $(CFLAGS)
 endif
 
+ifdef CONFIG_DYNAMIC_ENGINES
+ DYNAMIC_ENGS := $(ENGINES)
+define engine_template =
+$(1)_OBJS := $$($(1)_SRCS:.c=.o)
+$$($(1)_OBJS): CFLAGS := -fPIC $$($(1)_CFLAGS) $(CFLAGS)
+engines/lib$(1).so: $$($(1)_OBJS)
+       $$(QUIET_LINK)$(CC) -shared -rdynamic -fPIC -Wl,-soname,lib$(1).so.1 $$($(1)_LIBS) -o $$@ $$<
+ENGS_OBJS += engines/lib$(1).so
+all install: $(ENGS_OBJS)
+endef
+else # !CONFIG_DYNAMIC_ENGINES
+define engine_template =
+SOURCE += $$($(1)_SRCS)
+LIBS += $$($(1)_LIBS)
+CFLAGS := $$($(1)_CFLAGS) $(CFLAGS)
+endef
+endif
+
+$(foreach eng,$(ENGINES),$(eval $(call engine_template,$(eng))))
+
 OBJS := $(SOURCE:.c=.o)
 
 FIO_OBJS = $(OBJS) fio.o
@@ -337,12 +384,14 @@ PROGS += $(T_PROGS)
 ifdef CONFIG_HAVE_CUNIT
 UT_OBJS = unittests/unittest.o
 UT_OBJS += unittests/lib/memalign.o
+UT_OBJS += unittests/lib/num2str.o
 UT_OBJS += unittests/lib/strntol.o
 UT_OBJS += unittests/oslib/strlcat.o
 UT_OBJS += unittests/oslib/strndup.o
 UT_OBJS += unittests/oslib/strcasestr.o
 UT_OBJS += unittests/oslib/strsep.o
 UT_TARGET_OBJS = lib/memalign.o
+UT_TARGET_OBJS += lib/num2str.o
 UT_TARGET_OBJS += lib/strntol.o
 UT_TARGET_OBJS += oslib/strlcat.o
 UT_TARGET_OBJS += oslib/strndup.o
@@ -372,6 +421,7 @@ else
 endif
 prefix = $(INSTALL_PREFIX)
 bindir = $(prefix)/bin
+libdir = $(prefix)/lib/fio
 
 ifeq ($(CONFIG_TARGET_OS), Darwin)
 mandir = /usr/share/man
@@ -520,7 +570,7 @@ unittests/unittest: $(UT_OBJS) $(UT_TARGET_OBJS)
 endif
 
 clean: FORCE
-       @rm -f .depend $(FIO_OBJS) $(GFIO_OBJS) $(OBJS) $(T_OBJS) $(UT_OBJS) $(PROGS) $(T_PROGS) $(T_TEST_PROGS) core.* core gfio unittests/unittest FIO-VERSION-FILE *.[do] lib/*.d oslib/*.[do] crc/*.d engines/*.[do] profiles/*.[do] t/*.[do] unittests/*.[do] unittests/*/*.[do] config-host.mak config-host.h y.tab.[ch] lex.yy.c exp/*.[do] lexer.h
+       @rm -f .depend $(FIO_OBJS) $(GFIO_OBJS) $(OBJS) $(T_OBJS) $(UT_OBJS) $(PROGS) $(T_PROGS) $(T_TEST_PROGS) core.* core gfio unittests/unittest FIO-VERSION-FILE *.[do] lib/*.d oslib/*.[do] crc/*.d engines/*.[do] engines/*.so profiles/*.[do] t/*.[do] unittests/*.[do] unittests/*/*.[do] config-host.mak config-host.h y.tab.[ch] lex.yy.c exp/*.[do] lexer.h
        @rm -f t/fio-btrace2fio t/io_uring t/read-to-pipe-async
        @rm -rf  doc/output
 
@@ -560,6 +610,10 @@ fulltest:
 install: $(PROGS) $(SCRIPTS) tools/plot/fio2gnuplot.1 FORCE
        $(INSTALL) -m 755 -d $(DESTDIR)$(bindir)
        $(INSTALL) $(PROGS) $(SCRIPTS) $(DESTDIR)$(bindir)
+ifdef CONFIG_DYNAMIC_ENGINES
+       $(INSTALL) -m 755 -d $(DESTDIR)$(libdir)
+       $(INSTALL) -m 755 $(SRCDIR)/engines/*.so $(DESTDIR)$(libdir)
+endif
        $(INSTALL) -m 755 -d $(DESTDIR)$(mandir)/man1
        $(INSTALL) -m 644 $(SRCDIR)/fio.1 $(DESTDIR)$(mandir)/man1
        $(INSTALL) -m 644 $(SRCDIR)/tools/fio_generate_plots.1 $(DESTDIR)$(mandir)/man1
index 30c0d2056d3eaa7abcffd5cd703f698d99790edd..08c3d7033d3037f854649b861cc81415469d7096 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef ARCH_H
 #define ARCH_H
 
+#include <stdatomic.h>
+
 #include "../lib/types.h"
 
 enum {
@@ -34,6 +36,13 @@ extern unsigned long arch_flags;
 
 #define ARCH_CPU_CLOCK_WRAPS
 
+#define atomic_load_acquire(p)                                 \
+       atomic_load_explicit((_Atomic typeof(*(p)) *)(p),       \
+                            memory_order_acquire)
+#define atomic_store_release(p, v)                             \
+       atomic_store_explicit((_Atomic typeof(*(p)) *)(p), (v), \
+                             memory_order_release)
+
 /* IWYU pragma: begin_exports */
 #if defined(__i386__)
 #include "arch-x86.h"
index 0075a733ffca7b2c5fd727f53d56d95e69592c17..0e454cdd1e9a4f2979320e7b913cc5f242d4b362 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -66,7 +66,11 @@ unsigned int stat_number = 0;
 int shm_id = 0;
 int temp_stall_ts;
 unsigned long done_secs = 0;
+#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
+pthread_mutex_t overlap_check = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
+#else
 pthread_mutex_t overlap_check = PTHREAD_MUTEX_INITIALIZER;
+#endif
 
 #define JOB_START_TIMEOUT      (5 * 1000)
 
@@ -1535,7 +1539,7 @@ static void *thread_main(void *data)
        uint64_t bytes_done[DDIR_RWDIR_CNT];
        int deadlock_loop_cnt;
        bool clear_state;
-       int ret;
+       int res, ret;
 
        sk_out_assign(sk_out);
        free(fd);
@@ -1860,11 +1864,15 @@ static void *thread_main(void *data)
         * offload mode so that we don't clean up this job while
         * another thread is checking its io_u's for overlap
         */
-       if (td_offload_overlap(td))
-               pthread_mutex_lock(&overlap_check);
+       if (td_offload_overlap(td)) {
+               int res = pthread_mutex_lock(&overlap_check);
+               assert(res == 0);
+       }
        td_set_runstate(td, TD_FINISHING);
-       if (td_offload_overlap(td))
-               pthread_mutex_unlock(&overlap_check);
+       if (td_offload_overlap(td)) {
+               res = pthread_mutex_unlock(&overlap_check);
+               assert(res == 0);
+       }
 
        update_rusage_stat(td);
        td->ts.total_run_time = mtime_since_now(&td->epoch);
diff --git a/compiler/compiler-gcc4.h b/compiler/compiler-gcc4.h
deleted file mode 100644 (file)
index e8701cf..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef FIO_COMPILER_GCC4_H
-#define FIO_COMPILER_GCC4_H
-
-#ifndef __must_check
-#define __must_check           __attribute__((warn_unused_result))
-#endif
-
-#define GCC_VERSION (__GNUC__ * 10000          \
-                       + __GNUC_MINOR__ * 100  \
-                       + __GNUC_PATCHLEVEL__)
-
-#if GCC_VERSION >= 40300
-#define __compiletime_warning(message) __attribute__((warning(message)))
-#define __compiletime_error(message)   __attribute__((error(message)))
-#endif
-
-#endif
index ddfbcc124e77ac2b1a5d7aea1640ccbc4577a331..8c0eb9d10d210c5f6e92be3e062ca9ddf8076558 100644 (file)
@@ -2,16 +2,16 @@
 #define FIO_COMPILER_H
 
 /* IWYU pragma: begin_exports */
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
-#include "compiler-gcc4.h"
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) || __clang_major__ >= 6
 #else
-#error Compiler too old, need at least gcc 4.1.0
+#error Compiler too old, need at least gcc 4.9
 #endif
 /* IWYU pragma: end_exports */
 
-#ifndef __must_check
-#define __must_check
-#endif
+#define __must_check           __attribute__((warn_unused_result))
+
+#define __compiletime_warning(message) __attribute__((warning(message)))
+#define __compiletime_error(message)   __attribute__((error(message)))
 
 /*
  * Mark unused variables passed to ops functions as unused, to silence gcc
index 3ee8aaf2b8205617fa154cf3f8f8431965a6ae58..6991393bbf74bb7c8f36ca396845d58ef334107e 100755 (executable)
--- a/configure
+++ b/configure
@@ -151,6 +151,7 @@ march_set="no"
 libiscsi="no"
 libnbd="no"
 libaio_uring="no"
+dynamic_engines="no"
 prefix=/usr/local
 
 # parse options
@@ -215,6 +216,8 @@ for opt do
   ;;
   --enable-libaio-uring) libaio_uring="yes"
   ;;
+  --dynamic-libengines) dynamic_engines="yes"
+  ;;
   --help)
     show_help="yes"
     ;;
@@ -254,6 +257,7 @@ if test "$show_help" = "yes" ; then
   echo "--enable-libnbd         Enable libnbd (NBD engine) support"
   echo "--disable-tcmalloc     Disable tcmalloc support"
   echo "--enable-libaio-uring   Enable libaio emulated over io_uring"
+  echo "--dynamic-libengines   Lib-based ioengines as dynamic libraries"
   exit $exit_val
 fi
 
@@ -605,11 +609,9 @@ int main(void)
 EOF
   if test "$libaio_uring" = "yes" && compile_prog "" "-luring" "libaio io_uring" ; then
     libaio=yes
-    LIBS="-luring $LIBS"
   elif compile_prog "" "-laio" "libaio" ; then
     libaio=yes
     libaio_uring=no
-    LIBS="-laio $LIBS"
   else
     if test "$libaio" = "yes" ; then
       feature_not_found "linux AIO" "libaio-dev or libaio-devel"
@@ -859,7 +861,6 @@ int main(int argc, char **argv)
 EOF
 if test "$disable_rdma" != "yes" && compile_prog "" "-libverbs" "libverbs" ; then
     libverbs="yes"
-    LIBS="-libverbs $LIBS"
 fi
 print_config "libverbs" "$libverbs"
 
@@ -879,7 +880,6 @@ int main(int argc, char **argv)
 EOF
 if test "$disable_rdma" != "yes" && compile_prog "" "-lrdmacm" "rdma"; then
     rdmacm="yes"
-    LIBS="-lrdmacm $LIBS"
 fi
 print_config "rdmacm" "$rdmacm"
 
@@ -1770,10 +1770,8 @@ if test "$disable_http" != "yes"; then
   if compile_prog "" "$HTTP_LIBS" "curl-new-ssl"; then
     output_sym "CONFIG_HAVE_OPAQUE_HMAC_CTX"
     http="yes"
-    LIBS="$HTTP_LIBS $LIBS"
   elif mv $TMPC2 $TMPC && compile_prog "" "$HTTP_LIBS" "curl-old-ssl"; then
     http="yes"
-    LIBS="$HTTP_LIBS $LIBS"
   fi
 fi
 print_config "http engine" "$http"
@@ -1802,7 +1800,6 @@ int main(int argc, char **argv)
 }
 EOF
 if test "$disable_rados" != "yes"  && compile_prog "" "-lrados" "rados"; then
-  LIBS="-lrados $LIBS"
   rados="yes"
 fi
 print_config "Rados engine" "$rados"
@@ -1833,7 +1830,6 @@ int main(int argc, char **argv)
 }
 EOF
 if test "$disable_rbd" != "yes"  && compile_prog "" "-lrbd -lrados" "rbd"; then
-  LIBS="-lrbd -lrados $LIBS"
   rbd="yes"
 fi
 print_config "Rados Block Device engine" "$rbd"
@@ -1924,7 +1920,6 @@ int main(int argc, char **argv)
 }
 EOF
 if test "$disable_gfapi" != "yes"  && compile_prog "" "-lgfapi -lglusterfs" "gfapi"; then
-  LIBS="-lgfapi -lglusterfs $LIBS"
   gfapi="yes"
 fi
 print_config "Gluster API engine" "$gfapi"
@@ -2086,7 +2081,6 @@ int main(int argc, char **argv)
 EOF
 if compile_prog "" "-lpmem" "libpmem"; then
   libpmem="yes"
-  LIBS="-lpmem $LIBS"
 fi
 print_config "libpmem" "$libpmem"
 
@@ -2108,7 +2102,6 @@ int main(int argc, char **argv)
 EOF
   if compile_prog "" "-lpmemblk" "libpmemblk"; then
     libpmemblk="yes"
-    LIBS="-lpmemblk $LIBS"
   fi
 fi
 print_config "libpmemblk" "$libpmemblk"
@@ -2432,7 +2425,6 @@ if compile_prog "" "-lzbc" "libzbc"; then
   libzbcvermaj=$(pkg-config --modversion libzbc | sed 's/\.[0-9]*\.[0-9]*//')
   if test "$libzbcvermaj" -ge "5" ; then
     libzbc="yes"
-    LIBS="-lzbc $LIBS"
   else
     print_config "libzbc engine" "Unsupported libzbc version (version 5 or above required)"
     libzbc="no"
@@ -2548,7 +2540,7 @@ fi
 print_config "__kernel_rwf_t" "$__kernel_rwf_t"
 
 ##########################################
-# check if gcc has -Wimplicit-fallthrough
+# check if gcc has -Wimplicit-fallthrough=2
 fallthrough="no"
 cat > $TMPC << EOF
 int main(int argc, char **argv)
@@ -2556,10 +2548,10 @@ int main(int argc, char **argv)
   return 0;
 }
 EOF
-if compile_prog "-Wimplicit-fallthrough" "" "-Wimplicit-fallthrough"; then
+if compile_prog "-Wimplicit-fallthrough=2" "" "-Wimplicit-fallthrough=2"; then
   fallthrough="yes"
 fi
-print_config "-Wimplicit-fallthrough" "$fallthrough"
+print_config "-Wimplicit-fallthrough=2" "$fallthrough"
 
 ##########################################
 # check for MADV_HUGEPAGE support
@@ -2966,6 +2958,10 @@ if test "$libnbd" = "yes" ; then
   echo "LIBNBD_CFLAGS=$libnbd_cflags" >> $config_host_mak
   echo "LIBNBD_LIBS=$libnbd_libs" >> $config_host_mak
 fi
+if test "$dynamic_engines" = "yes" ; then
+  output_sym "CONFIG_DYNAMIC_ENGINES"
+fi
+print_config "Lib-based ioengines dynamic" "$dynamic_engines"
 cat > $TMPC << EOF
 int main(int argc, char **argv)
 {
index 422ea634ff1d2530b6dae4ba40747417281ee27c..1d0f66cb1aba7ad57069cd742f93fb3783da567f 100644 (file)
@@ -328,7 +328,7 @@ fio_devdax_get_file_size(struct thread_data *td, struct fio_file *f)
        return 0;
 }
 
-static struct ioengine_ops ioengine = {
+FIO_STATIC struct ioengine_ops ioengine = {
        .name           = "dev-dax",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_devdax_init,
index cb26802cce8b8f8acbbb510d715262f9b48fa2a9..d4121757e61975be59ebb1549241ab35aa8ab4fd 100644 (file)
@@ -242,7 +242,7 @@ static int fio_guasi_init(struct thread_data *td)
        return 0;
 }
 
-static struct ioengine_ops ioengine = {
+FIO_STATIC struct ioengine_ops ioengine = {
        .name           = "guasi",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_guasi_init,
index 275fcab561048f9e81908863cbda3366c28b73b1..7a61b132b92bd72b94ebdc9915e311235b53fc56 100644 (file)
@@ -639,7 +639,7 @@ static int fio_http_invalidate(struct thread_data *td, struct fio_file *f)
        return 0;
 }
 
-static struct ioengine_ops ioengine = {
+FIO_STATIC struct ioengine_ops ioengine = {
        .name = "http",
        .version                = FIO_IOOPS_VERSION,
        .flags                  = FIO_DISKLESSIO | FIO_SYNCIO,
index cab7ecaf1ac08a503ee0aa349892f6343dad69e4..ecff0657ed51e60af19bce99a0be1d803c63dd82 100644 (file)
@@ -301,15 +301,15 @@ static int fio_ioring_cqring_reap(struct thread_data *td, unsigned int events,
 
        head = *ring->head;
        do {
-               read_barrier();
-               if (head == *ring->tail)
+               if (head == atomic_load_acquire(ring->tail))
                        break;
                reaped++;
                head++;
        } while (reaped + events < max);
 
-       *ring->head = head;
-       write_barrier();
+       if (reaped)
+               atomic_store_release(ring->head, head);
+
        return reaped;
 }
 
@@ -384,15 +384,13 @@ static enum fio_q_status fio_ioring_queue(struct thread_data *td,
 
        tail = *ring->tail;
        next_tail = tail + 1;
-       read_barrier();
-       if (next_tail == *ring->head)
+       if (next_tail == atomic_load_acquire(ring->head))
                return FIO_Q_BUSY;
 
        if (o->cmdprio_percentage)
                fio_ioring_prio_prep(td, io_u);
        ring->array[tail & ld->sq_ring_mask] = io_u->index;
-       *ring->tail = next_tail;
-       write_barrier();
+       atomic_store_release(ring->tail, next_tail);
 
        ld->queued++;
        return FIO_Q_QUEUED;
index daa576dad3e64b97f4af427633921f0ab9c61e6c..b909b79e9c7169f7898e2aa32be37f895cafe4a0 100644 (file)
@@ -195,8 +195,8 @@ static int user_io_getevents(io_context_t aio_ctx, unsigned int max,
                } else {
                        /* There is another completion to reap */
                        events[i] = ring->events[head];
-                       read_barrier();
-                       ring->head = (head + 1) % ring->nr;
+                       atomic_store_release(&ring->head,
+                                            (head + 1) % ring->nr);
                        i++;
                }
        }
@@ -445,7 +445,7 @@ static int fio_libaio_init(struct thread_data *td)
        return 0;
 }
 
-static struct ioengine_ops ioengine = {
+FIO_STATIC struct ioengine_ops ioengine = {
        .name                   = "libaio",
        .version                = FIO_IOOPS_VERSION,
        .flags                  = FIO_ASYNCIO_SYNC_TRIM,
index c57fcea6353821dbdd90db055561f0424f9cbcf0..9ca82f78cb067469190b2e393f7bc0dd7215df7c 100644 (file)
@@ -393,7 +393,7 @@ static void fio_hdfsio_io_u_free(struct thread_data *td, struct io_u *io_u)
        }
 }
 
-static struct ioengine_ops ioengine_hdfs = {
+FIO_STATIC struct ioengine_ops ioengine = {
        .name = "libhdfs",
        .version = FIO_IOOPS_VERSION,
        .flags = FIO_SYNCIO | FIO_DISKLESSIO | FIO_NODISKUTIL,
@@ -412,10 +412,10 @@ static struct ioengine_ops ioengine_hdfs = {
 
 static void fio_init fio_hdfsio_register(void)
 {
-       register_ioengine(&ioengine_hdfs);
+       register_ioengine(&ioengine);
 }
 
 static void fio_exit fio_hdfsio_unregister(void)
 {
-       unregister_ioengine(&ioengine_hdfs);
+       unregister_ioengine(&ioengine);
 }
index 35761a619f89099520d4f0b37730ed7f7324a42a..c97b5709ae779eda9af451c0418d352ad365e772 100644 (file)
@@ -383,7 +383,7 @@ static struct io_u *fio_iscsi_event(struct thread_data *td, int event)
        return io_u;
 }
 
-static struct ioengine_ops ioengine_iscsi = {
+FIO_STATIC struct ioengine_ops ioengine = {
        .name               = "libiscsi",
        .version            = FIO_IOOPS_VERSION,
        .flags              = FIO_SYNCIO | FIO_DISKLESSIO | FIO_NODISKUTIL,
@@ -402,10 +402,10 @@ static struct ioengine_ops ioengine_iscsi = {
 
 static void fio_init fio_iscsi_register(void)
 {
-       register_ioengine(&ioengine_iscsi);
+       register_ioengine(&ioengine);
 }
 
 static void fio_exit fio_iscsi_unregister(void)
 {
-       unregister_ioengine(&ioengine_iscsi);
+       unregister_ioengine(&ioengine);
 }
index 99c7b50ddc23a1f188d1a30e0fb249a38afbdfae..3f63055c1d9759675d8db844dc77ed005b4cf476 100644 (file)
@@ -558,7 +558,7 @@ static int fio_libpmem_close_file(struct thread_data *td, struct fio_file *f)
        return generic_close_file(td, f);
 }
 
-static struct ioengine_ops ioengine = {
+FIO_STATIC struct ioengine_ops ioengine = {
        .name           = "libpmem",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_libpmem_init,
index 9e5683349fb1c60d99c782d085de23cb60bafbb5..fdde8ca65fff242ac7f405aba8a91536db89a5d7 100644 (file)
@@ -397,7 +397,7 @@ static enum fio_q_status libzbc_queue(struct thread_data *td, struct io_u *io_u)
        return FIO_Q_COMPLETED;
 }
 
-static struct ioengine_ops ioengine = {
+FIO_STATIC struct ioengine_ops ioengine = {
        .name                   = "libzbc",
        .version                = FIO_IOOPS_VERSION,
        .open_file              = libzbc_open_file,
index 5323792907a9d3e505a5e27a970fd0cdaf327da6..b0ba75e69428f63324a764cc702f679bf6c1e5da 100644 (file)
@@ -328,7 +328,7 @@ static int nbd_invalidate(struct thread_data *td, struct fio_file *f)
        return 0;
 }
 
-static struct ioengine_ops ioengine = {
+FIO_STATIC struct ioengine_ops ioengine = {
        .name                   = "nbd",
        .version                = FIO_IOOPS_VERSION,
        .options                = options,
index 730f4d776f1eb46d8bbfc792ed87b103c078641b..fc6358e8e11f3730fc6163127830aaf5bc1ebf7a 100644 (file)
@@ -220,14 +220,14 @@ static fio_pmemblk_file_t pmb_open(const char *pathspec, int flags)
                pmb->pmb_nblocks = pmemblk_nblock(pmb->pmb_pool);
 
                fio_pmemblk_cache_insert(pmb);
+       } else {
+               free(path);
        }
 
        pmb->pmb_refcnt += 1;
 
        pthread_mutex_unlock(&CacheLock);
 
-       free(path);
-
        return pmb;
 
 error:
@@ -426,7 +426,7 @@ static int fio_pmemblk_unlink_file(struct thread_data *td, struct fio_file *f)
        return 0;
 }
 
-static struct ioengine_ops ioengine = {
+FIO_STATIC struct ioengine_ops ioengine = {
        .name = "pmemblk",
        .version = FIO_IOOPS_VERSION,
        .queue = fio_pmemblk_queue,
index d44134276b471010f9a96f5a0c75c547f38990ea..42ee48ff02b3f6371027ab4cbcbc304aefbbea10 100644 (file)
@@ -444,7 +444,7 @@ static int fio_rados_io_u_init(struct thread_data *td, struct io_u *io_u)
 }
 
 /* ioengine_ops for get_ioengine() */
-static struct ioengine_ops ioengine = {
+FIO_STATIC struct ioengine_ops ioengine = {
        .name = "rados",
        .version                = FIO_IOOPS_VERSION,
        .flags                  = FIO_DISKLESSIO,
index a08f47757acdfbe03e18f009d251cb7846272d4d..268b6ebdffad2b71e4da565ed90867e76f90947a 100644 (file)
@@ -668,7 +668,7 @@ static int fio_rbd_io_u_init(struct thread_data *td, struct io_u *io_u)
        return 0;
 }
 
-static struct ioengine_ops ioengine = {
+FIO_STATIC struct ioengine_ops ioengine = {
        .name                   = "rbd",
        .version                = FIO_IOOPS_VERSION,
        .setup                  = fio_rbd_setup,
index f192f432738da6e8fa448766348ae6e4578fee5d..f4471869813693eb140bec7d87a31123b539ea89 100644 (file)
@@ -226,7 +226,8 @@ static int client_recv(struct thread_data *td, struct ibv_wc *wc)
                rd->rmt_nr = ntohl(rd->recv_buf.nr);
 
                for (i = 0; i < rd->rmt_nr; i++) {
-                       rd->rmt_us[i].buf = be64_to_cpu(rd->recv_buf.rmt_us[i].buf);
+                       rd->rmt_us[i].buf = __be64_to_cpu(
+                                               rd->recv_buf.rmt_us[i].buf);
                        rd->rmt_us[i].rkey = ntohl(rd->recv_buf.rmt_us[i].rkey);
                        rd->rmt_us[i].size = ntohl(rd->recv_buf.rmt_us[i].size);
 
@@ -1389,7 +1390,7 @@ static int fio_rdmaio_setup(struct thread_data *td)
        return 0;
 }
 
-static struct ioengine_ops ioengine_rw = {
+FIO_STATIC struct ioengine_ops ioengine = {
        .name                   = "rdma",
        .version                = FIO_IOOPS_VERSION,
        .setup                  = fio_rdmaio_setup,
@@ -1410,10 +1411,10 @@ static struct ioengine_ops ioengine_rw = {
 
 static void fio_init fio_rdmaio_register(void)
 {
-       register_ioengine(&ioengine_rw);
+       register_ioengine(&ioengine);
 }
 
 static void fio_exit fio_rdmaio_unregister(void)
 {
-       unregister_ioengine(&ioengine_rw);
+       unregister_ioengine(&ioengine);
 }
diff --git a/fio.1 b/fio.1
index f469c46ed798f8521e6747e461a0625853a0c3e4..f134e0bf88ca9f958f1e8bdec594f3551e1ceb9d 100644 (file)
--- a/fio.1
+++ b/fio.1
@@ -3863,7 +3863,8 @@ Fio supports a variety of log file formats, for logging latencies, bandwidth,
 and IOPS. The logs share a common format, which looks like this:
 .RS
 .P
-time (msec), value, data direction, block size (bytes), offset (bytes)
+time (msec), value, data direction, block size (bytes), offset (bytes),
+command priority
 .RE
 .P
 `Time' for the log entry is always in milliseconds. The `value' logged depends
@@ -3897,6 +3898,9 @@ The entry's `block size' is always in bytes. The `offset' is the position in byt
 from the start of the file for that particular I/O. The logging of the offset can be
 toggled with \fBlog_offset\fR.
 .P
+`Command priority` is 0 for normal priority and 1 for high priority. This is controlled
+by the ioengine specific \fBcmdprio_percentage\fR.
+.P
 Fio defaults to logging every individual I/O but when windowed logging is set
 through \fBlog_avg_msec\fR, either the average (by default) or the maximum
 (\fBlog_max_value\fR is set) `value' seen over the specified period of time
index c34d8bf76565ab7f93be9b9d2f6bbf41808f3950..c7806acb26ae3ea51211e5488819ce24add451db 100644 (file)
--- a/fio_sem.c
+++ b/fio_sem.c
@@ -169,7 +169,6 @@ void fio_sem_up(struct fio_sem *sem)
        assert(sem->magic == FIO_SEM_MAGIC);
 
        pthread_mutex_lock(&sem->lock);
-       read_barrier();
        if (!sem->value && sem->waiters)
                do_wake = 1;
        sem->value++;
index 0a2cc6c451d533d1a5c56ce2ce857c85a7b31de2..953e4e67e36db81e39aae9bb073b332f8bd373ab 100644 (file)
@@ -2,9 +2,10 @@
 #include <time.h>
 
 #include "fio.h"
+#include "lib/seqlock.h"
 #include "smalloc.h"
 
-struct timespec *fio_ts = NULL;
+struct fio_ts *fio_ts;
 int fio_gtod_offload = 0;
 static pthread_t gtod_thread;
 static os_cpu_mask_t fio_gtod_cpumask;
@@ -19,15 +20,17 @@ void fio_gtod_init(void)
 
 static void fio_gtod_update(void)
 {
-       if (fio_ts) {
-               struct timeval __tv;
-
-               gettimeofday(&__tv, NULL);
-               fio_ts->tv_sec = __tv.tv_sec;
-               write_barrier();
-               fio_ts->tv_nsec = __tv.tv_usec * 1000;
-               write_barrier();
-       }
+       struct timeval __tv;
+
+       if (!fio_ts)
+               return;
+
+       gettimeofday(&__tv, NULL);
+
+       write_seqlock_begin(&fio_ts->seqlock);
+       fio_ts->ts.tv_sec = __tv.tv_sec;
+       fio_ts->ts.tv_nsec = __tv.tv_usec * 1000;
+       write_seqlock_end(&fio_ts->seqlock);
 }
 
 struct gtod_cpu_data {
index f92ee8c430c8d9cdb48f31effabd885af07c9257..c55f5cba779f5269e6fbc6b96c1e85e419d40683 100644 (file)
--- a/gettime.h
+++ b/gettime.h
@@ -4,6 +4,7 @@
 #include <sys/time.h>
 
 #include "arch/arch.h"
+#include "lib/seqlock.h"
 
 /*
  * Clock sources
@@ -22,20 +23,22 @@ extern int fio_start_gtod_thread(void);
 extern int fio_monotonic_clocktest(int debug);
 extern void fio_local_clock_init(void);
 
-extern struct timespec *fio_ts;
+extern struct fio_ts {
+       struct seqlock seqlock;
+       struct timespec ts;
+} *fio_ts;
 
 static inline int fio_gettime_offload(struct timespec *ts)
 {
-       time_t last_sec;
+       unsigned int seq;
 
        if (!fio_ts)
                return 0;
 
        do {
-               read_barrier();
-               last_sec = ts->tv_sec = fio_ts->tv_sec;
-               ts->tv_nsec = fio_ts->tv_nsec;
-       } while (fio_ts->tv_sec != last_sec);
+               seq = read_seqlock_begin(&fio_ts->seqlock);
+               *ts = fio_ts->ts;
+       } while (read_seqlock_retry(&fio_ts->seqlock, seq));
 
        return 1;
 }
diff --git a/init.c b/init.c
index e53be35a7bed07ab0ff4ed06e2e7d564585793f8..3710e3d404acf84599076098cbe6569282b448a8 100644 (file)
--- a/init.c
+++ b/init.c
@@ -1099,6 +1099,9 @@ int ioengine_load(struct thread_data *td)
                 */
                dlhandle = td->io_ops_dlhandle;
                ops = load_ioengine(td);
+               if (!ops)
+                       goto fail;
+
                if (ops == td->io_ops && dlhandle == td->io_ops_dlhandle) {
                        if (dlhandle)
                                dlclose(dlhandle);
@@ -1113,10 +1116,8 @@ int ioengine_load(struct thread_data *td)
        }
 
        td->io_ops = load_ioengine(td);
-       if (!td->io_ops) {
-               log_err("fio: failed to load engine\n");
-               return 1;
-       }
+       if (!td->io_ops)
+               goto fail;
 
        if (td->io_ops->option_struct_size && td->io_ops->options) {
                /*
@@ -1155,6 +1156,11 @@ int ioengine_load(struct thread_data *td)
 
        td_set_ioengine_flags(td);
        return 0;
+
+fail:
+       log_err("fio: failed to load engine\n");
+       return 1;
+
 }
 
 static void init_flags(struct thread_data *td)
diff --git a/io_u.c b/io_u.c
index ae1438fd665673e3077cc41c8dae0e4ace1b01c4..7f50906ba3f9792eb34755274bf5b2efab9464f1 100644 (file)
--- a/io_u.c
+++ b/io_u.c
@@ -1934,8 +1934,8 @@ static void io_completed(struct thread_data *td, struct io_u **io_u_ptr,
                if (io_u->error)
                        unlog_io_piece(td, io_u);
                else {
-                       io_u->ipo->flags &= ~IP_F_IN_FLIGHT;
-                       write_barrier();
+                       atomic_store_release(&io_u->ipo->flags,
+                                       io_u->ipo->flags & ~IP_F_IN_FLIGHT);
                }
        }
 
index 2c7a0df9ed39fa02da08691c4fb85cdf6eadbb90..1c5970a4b5a188e5f4aa5f924b483c976a04142f 100644 (file)
@@ -75,6 +75,25 @@ static struct ioengine_ops *find_ioengine(const char *name)
        return NULL;
 }
 
+#ifdef CONFIG_DYNAMIC_ENGINES
+static void *dlopen_external(struct thread_data *td, const char *engine)
+{
+       char engine_path[PATH_MAX];
+       void *dlhandle;
+
+       sprintf(engine_path, "%s/lib%s.so", FIO_EXT_ENG_DIR, engine);
+
+       dlhandle = dlopen(engine_path, RTLD_LAZY);
+       if (!dlhandle)
+               log_info("Engine %s not found; Either name is invalid, was not built, or fio-engine-%s package is missing.\n",
+                        engine, engine);
+
+       return dlhandle;
+}
+#else
+#define dlopen_external(td, engine) (NULL)
+#endif
+
 static struct ioengine_ops *dlopen_ioengine(struct thread_data *td,
                                            const char *engine_lib)
 {
@@ -86,8 +105,11 @@ static struct ioengine_ops *dlopen_ioengine(struct thread_data *td,
        dlerror();
        dlhandle = dlopen(engine_lib, RTLD_LAZY);
        if (!dlhandle) {
-               td_vmsg(td, -1, dlerror(), "dlopen");
-               return NULL;
+               dlhandle = dlopen_external(td, engine_lib);
+               if (!dlhandle) {
+                       td_vmsg(td, -1, dlerror(), "dlopen");
+                       return NULL;
+               }
        }
 
        /*
@@ -291,8 +313,10 @@ enum fio_q_status td_io_queue(struct thread_data *td, struct io_u *io_u)
         * started the overlap check because the IO_U_F_FLIGHT
         * flag is now set
         */
-       if (td_offload_overlap(td))
-               pthread_mutex_unlock(&overlap_check);
+       if (td_offload_overlap(td)) {
+               int res = pthread_mutex_unlock(&overlap_check);
+               assert(res == 0);
+       }
 
        assert(fio_file_open(io_u->file));
 
index f48b4db934851fd944eba8e66f462858aed183a5..54dadba2cbce34921d6d46b05c233b4aeb8c4a8a 100644 (file)
 
 #define FIO_IOOPS_VERSION      26
 
+#ifndef CONFIG_DYNAMIC_ENGINES
+#define FIO_STATIC     static
+#else
+#define FIO_STATIC
+#endif
+
 /*
  * io_ops->queue() return values
  */
index 1abe22f33794c0ccf6b724e74aef7a1f62271166..726f1c44159fd8a16379777411030b262eeb6cb1 100644 (file)
@@ -4,6 +4,7 @@
 #include <string.h>
 
 #include "../compiler/compiler.h"
+#include "../oslib/asprintf.h"
 #include "num2str.h"
 
 #define ARRAY_SIZE(x)    (sizeof((x)) / (sizeof((x)[0])))
@@ -19,8 +20,8 @@
  */
 char *num2str(uint64_t num, int maxlen, int base, int pow2, enum n2s_unit units)
 {
-       const char *sistr[] = { "", "k", "M", "G", "T", "P" };
-       const char *iecstr[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi" };
+       const char *sistr[] = { "", "k", "M", "G", "T", "P", "E" };
+       const char *iecstr[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" };
        const char **unitprefix;
        static const char *const unitstr[] = {
                [N2S_NONE]      = "",
@@ -33,16 +34,12 @@ char *num2str(uint64_t num, int maxlen, int base, int pow2, enum n2s_unit units)
        const unsigned int thousand = pow2 ? 1024 : 1000;
        unsigned int modulo;
        int post_index, carry = 0;
-       char tmp[32], fmt[32];
+       char tmp[32];
        char *buf;
 
        compiletime_assert(sizeof(sistr) == sizeof(iecstr), "unit prefix arrays must be identical sizes");
        assert(units < ARRAY_SIZE(unitstr));
 
-       buf = malloc(128);
-       if (!buf)
-               return NULL;
-
        if (pow2)
                unitprefix = iecstr;
        else
@@ -83,16 +80,17 @@ char *num2str(uint64_t num, int maxlen, int base, int pow2, enum n2s_unit units)
                post_index++;
        }
 
+       if (post_index >= ARRAY_SIZE(sistr))
+               post_index = 0;
+
        /*
         * If no modulo, then we're done.
         */
        if (modulo == -1U) {
 done:
-               if (post_index >= ARRAY_SIZE(sistr))
-                       post_index = 0;
-
-               sprintf(buf, "%llu%s%s", (unsigned long long) num,
-                       unitprefix[post_index], unitstr[units]);
+               if (asprintf(&buf, "%llu%s%s", (unsigned long long) num,
+                            unitprefix[post_index], unitstr[units]) < 0)
+                       buf = NULL;
                return buf;
        }
 
@@ -111,10 +109,11 @@ done:
         */
        assert(maxlen - strlen(tmp) - 1 > 0);
        assert(modulo < thousand);
-       sprintf(fmt, "%%.%df", (int)(maxlen - strlen(tmp) - 1));
-       sprintf(tmp, fmt, (double)modulo / (double)thousand);
+       sprintf(tmp, "%.*f", (int)(maxlen - strlen(tmp) - 1),
+               (double)modulo / (double)thousand);
 
-       sprintf(buf, "%llu.%s%s%s", (unsigned long long) num, &tmp[2],
-                       unitprefix[post_index], unitstr[units]);
+       if (asprintf(&buf, "%llu.%s%s%s", (unsigned long long) num, &tmp[2],
+                    unitprefix[post_index], unitstr[units]) < 0)
+               buf = NULL;
        return buf;
 }
index 2ccc1b3723c42f4f90ab821bf2824611037d24dc..46c1c5e023a132513ded05d885bd5769dbf7ceb9 100644 (file)
@@ -6,7 +6,9 @@
 #include "types.h"
 
 #define FRAND32_MAX    (-1U)
+#define FRAND32_MAX_PLUS_ONE   (1.0 * (1ULL << 32))
 #define FRAND64_MAX    (-1ULL)
+#define FRAND64_MAX_PLUS_ONE   (1.0 * (1ULL << 32) * (1ULL << 32))
 
 struct taus88_state {
        unsigned int s1, s2, s3;
@@ -106,11 +108,11 @@ static inline double __rand_0_1(struct frand_state *state)
        if (state->use64) {
                uint64_t val = __rand64(&state->state64);
 
-               return (val + 1.0) / (FRAND64_MAX + 1.0);
+               return (val + 1.0) / FRAND64_MAX_PLUS_ONE;
        } else {
                uint32_t val = __rand32(&state->state32);
 
-               return (val + 1.0) / (FRAND32_MAX + 1.0);
+               return (val + 1.0) / FRAND32_MAX_PLUS_ONE;
        }
 }
 
@@ -122,7 +124,7 @@ static inline uint32_t rand32_upto(struct frand_state *state, uint32_t end)
 
        r = __rand32(&state->state32);
        end++;
-       return (int) ((double)end * (r / (FRAND32_MAX + 1.0)));
+       return (int) ((double)end * (r / FRAND32_MAX_PLUS_ONE));
 }
 
 static inline uint64_t rand64_upto(struct frand_state *state, uint64_t end)
@@ -133,7 +135,7 @@ static inline uint64_t rand64_upto(struct frand_state *state, uint64_t end)
 
        r = __rand64(&state->state64);
        end++;
-       return (uint64_t) ((double)end * (r / (FRAND64_MAX + 1.0)));
+       return (uint64_t) ((double)end * (r / FRAND64_MAX_PLUS_ONE));
 }
 
 /*
index 762b6ec1d2dc7fa7ba5df9fe75d4e28da9a1c53b..56f3e37dab5b35750a390714c3af2d9579de5628 100644 (file)
@@ -5,7 +5,7 @@
 #include "../arch/arch.h"
 
 struct seqlock {
-       volatile int sequence;
+       volatile unsigned int sequence;
 };
 
 static inline void seqlock_init(struct seqlock *s)
@@ -18,13 +18,12 @@ static inline unsigned int read_seqlock_begin(struct seqlock *s)
        unsigned int seq;
 
        do {
-               seq = s->sequence;
+               seq = atomic_load_acquire(&s->sequence);
                if (!(seq & 1))
                        break;
                nop;
        } while (1);
 
-       read_barrier();
        return seq;
 }
 
@@ -36,14 +35,12 @@ static inline bool read_seqlock_retry(struct seqlock *s, unsigned int seq)
 
 static inline void write_seqlock_begin(struct seqlock *s)
 {
-       s->sequence++;
-       write_barrier();
+       s->sequence = atomic_load_acquire(&s->sequence) + 1;
 }
 
 static inline void write_seqlock_end(struct seqlock *s)
 {
-       write_barrier();
-       s->sequence++;
+       atomic_store_release(&s->sequence, s->sequence + 1);
 }
 
 #endif
index 6ec7243d49a3fc62166ea4723d855d7d2c3a9f28..65d3b429a87f408786c5569bf2c3884e9ea4474c 100644 (file)
@@ -58,6 +58,8 @@
 
 #define OS_MAP_ANON            MAP_ANONYMOUS
 
+#define FIO_EXT_ENG_DIR        "/usr/lib/fio"
+
 typedef cpu_set_t os_cpu_mask_t;
 
 #ifdef CONFIG_3ARG_AFFINITY
index e36453e9e8c77d129e760fe31424cb8af88c57e6..31271de049133b8728c26f47f6d4e34a13208cc6 100644 (file)
@@ -750,7 +750,7 @@ int setgid(gid_t gid)
 int nice(int incr)
 {
        DWORD prioclass = NORMAL_PRIORITY_CLASS;
-       
+
        if (incr < -15)
                prioclass = HIGH_PRIORITY_CLASS;
        else if (incr < 0)
@@ -759,7 +759,7 @@ int nice(int incr)
                prioclass = IDLE_PRIORITY_CLASS;
        else if (incr > 0)
                prioclass = BELOW_NORMAL_PRIORITY_CLASS;
-       
+
        if (!SetPriorityClass(GetCurrentProcess(), prioclass))
                log_err("fio: SetPriorityClass failed\n");
 
@@ -883,7 +883,7 @@ int poll(struct pollfd fds[], nfds_t nfds, int timeout)
        FD_ZERO(&exceptfds);
 
        for (i = 0; i < nfds; i++) {
-               if (fds[i].fd < 0) {
+               if (fds[i].fd == INVALID_SOCKET) {
                        fds[i].revents = 0;
                        continue;
                }
@@ -900,7 +900,7 @@ int poll(struct pollfd fds[], nfds_t nfds, int timeout)
 
        if (rc != SOCKET_ERROR) {
                for (i = 0; i < nfds; i++) {
-                       if (fds[i].fd < 0)
+                       if (fds[i].fd == INVALID_SOCKET)
                                continue;
 
                        if ((fds[i].events & POLLIN) && FD_ISSET(fds[i].fd, &readfds))
index 61ea3a53d6d5ce1b029db3bef33a18ece1baa4ac..1cf06363d1a2b2b9a8dc9220878b00b64439a44a 100644 (file)
@@ -143,7 +143,7 @@ int blkzoned_report_zones(struct thread_data *td, struct fio_file *f,
        }
 
        nr_zones = hdr->nr_zones;
-       blkz = &hdr->zones[0];
+       blkz = (void *) hdr + sizeof(*hdr);
        z = &zones[0];
        for (i = 0; i < nr_zones; i++, z++, blkz++) {
                z->start = blkz->start << 9;
index cf00d9bc75c56f057b41a337ae8bdc740aebaa66..b7b703722bbb102c84e0dbfd1fed7be0b35727e5 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2015 Jens Axboe <axboe@kernel.dk>
  *
  */
+#include <assert.h>
 #include "fio.h"
 #include "ioengines.h"
 #include "lib/getrusage.h"
 
 static void check_overlap(struct io_u *io_u)
 {
-       int i;
+       int i, res;
        struct thread_data *td;
-       bool overlap = false;
 
-       do {
-               /*
-                * Allow only one thread to check for overlap at a
-                * time to prevent two threads from thinking the coast
-                * is clear and then submitting IOs that overlap with
-                * each other
-                *
-                * If an overlap is found, release the lock and
-                * re-acquire it before checking again to give other
-                * threads a chance to make progress
-                *
-                * If an overlap is not found, release the lock when the
-                * io_u's IO_U_F_FLIGHT flag is set so that this io_u
-                * can be checked by other threads as they assess overlap
-                */
-               pthread_mutex_lock(&overlap_check);
-               for_each_td(td, i) {
-                       if (td->runstate <= TD_SETTING_UP ||
-                               td->runstate >= TD_FINISHING ||
-                               !td->o.serialize_overlap ||
-                               td->o.io_submit_mode != IO_MODE_OFFLOAD)
-                               continue;
-
-                       overlap = in_flight_overlap(&td->io_u_all, io_u);
-                       if (overlap) {
-                               pthread_mutex_unlock(&overlap_check);
-                               break;
-                       }
-               }
-       } while (overlap);
+       /*
+        * Allow only one thread to check for overlap at a time to prevent two
+        * threads from thinking the coast is clear and then submitting IOs
+        * that overlap with each other.
+        *
+        * If an overlap is found, release the lock and re-acquire it before
+        * checking again to give other threads a chance to make progress.
+        *
+        * If no overlap is found, release the lock when the io_u's
+        * IO_U_F_FLIGHT flag is set so that this io_u can be checked by other
+        * threads as they assess overlap.
+        */
+       res = pthread_mutex_lock(&overlap_check);
+       assert(res == 0);
+
+retry:
+       for_each_td(td, i) {
+               if (td->runstate <= TD_SETTING_UP ||
+                   td->runstate >= TD_FINISHING ||
+                   !td->o.serialize_overlap ||
+                   td->o.io_submit_mode != IO_MODE_OFFLOAD)
+                       continue;
+
+               if (!in_flight_overlap(&td->io_u_all, io_u))
+                       continue;
+
+               res = pthread_mutex_unlock(&overlap_check);
+               assert(res == 0);
+               res = pthread_mutex_lock(&overlap_check);
+               assert(res == 0);
+               goto retry;
+       }
 }
 
 static int io_workqueue_fn(struct submit_worker *sw,
index 8965cfbc4547241b5a6af4b66c03339d3f943696..0c913368262a709c3e13ed51c049d5284659c0c5 100644 (file)
--- a/t/debug.c
+++ b/t/debug.c
@@ -1,7 +1,7 @@
 #include <stdio.h>
 
 FILE *f_err;
-struct timespec *fio_ts = NULL;
+void *fio_ts;
 unsigned long fio_debug = 0;
 
 void __dprint(int type, const char *str, ...)
index d48db1e95d5ab5a94a7d529c293e95a2f37dd02d..7fa84f99075bb8fb2f7c9ad0120edba911889a72 100644 (file)
@@ -46,7 +46,6 @@ struct io_cq_ring {
 #define DEPTH                  128
 #define BATCH_SUBMIT           32
 #define BATCH_COMPLETE         32
-
 #define BS                     4096
 
 #define MAX_FDS                        16
@@ -86,6 +85,7 @@ static volatile int finish;
 static int depth = DEPTH;
 static int batch_submit = BATCH_SUBMIT;
 static int batch_complete = BATCH_COMPLETE;
+static int bs = BS;
 static int polled = 1;         /* use IO polling */
 static int fixedbufs = 1;      /* use fixed user buffers */
 static int register_files = 1; /* use fixed files */
@@ -170,7 +170,7 @@ static void init_io(struct submitter *s, unsigned index)
        f->pending_ios++;
 
        r = lrand48();
-       offset = (r % (f->max_blocks - 1)) * BS;
+       offset = (r % (f->max_blocks - 1)) * bs;
 
        if (register_files) {
                sqe->flags = IOSQE_FIXED_FILE;
@@ -182,7 +182,7 @@ static void init_io(struct submitter *s, unsigned index)
        if (fixedbufs) {
                sqe->opcode = IORING_OP_READ_FIXED;
                sqe->addr = (unsigned long) s->iovecs[index].iov_base;
-               sqe->len = BS;
+               sqe->len = bs;
                sqe->buf_index = index;
        } else {
                sqe->opcode = IORING_OP_READV;
@@ -233,10 +233,10 @@ static int get_file_size(struct file *f)
                if (ioctl(f->real_fd, BLKGETSIZE64, &bytes) != 0)
                        return -1;
 
-               f->max_blocks = bytes / BS;
+               f->max_blocks = bytes / bs;
                return 0;
        } else if (S_ISREG(st.st_mode)) {
-               f->max_blocks = st.st_size / BS;
+               f->max_blocks = st.st_size / bs;
                return 0;
        }
 
@@ -260,7 +260,7 @@ static int reap_events(struct submitter *s)
                if (!do_nop) {
                        f = (struct file *) (uintptr_t) cqe->user_data;
                        f->pending_ios--;
-                       if (cqe->res != BS) {
+                       if (cqe->res != bs) {
                                printf("io: unexpected ret=%d\n", cqe->res);
                                if (polled && cqe->res == -EOPNOTSUPP)
                                        printf("Your filesystem/driver/kernel doesn't support polled IO\n");
@@ -483,8 +483,10 @@ static void usage(char *argv)
        printf("%s [options] -- [filenames]\n"
                " -d <int> : IO Depth, default %d\n"
                " -s <int> : Batch submit, default %d\n"
-               " -c <int> : Batch complete, default %d\n",
-               argv, DEPTH, BATCH_SUBMIT, BATCH_COMPLETE);
+               " -c <int> : Batch complete, default %d\n"
+               " -b <int> : Block size, default %d\n"
+               " -p <bool> : Polled IO, default %d\n",
+               argv, DEPTH, BATCH_SUBMIT, BATCH_COMPLETE, BS, polled);
        exit(0);
 }
 
@@ -501,7 +503,7 @@ int main(int argc, char *argv[])
                return 1;
        }
 
-       while ((opt = getopt(argc, argv, "d:s:c:h?")) != -1) {
+       while ((opt = getopt(argc, argv, "d:s:c:b:p:h?")) != -1) {
                switch (opt) {
                case 'd':
                        depth = atoi(optarg);
@@ -512,6 +514,12 @@ int main(int argc, char *argv[])
                case 'c':
                        batch_complete = atoi(optarg);
                        break;
+               case 'b':
+                       bs = atoi(optarg);
+                       break;
+               case 'p':
+                       polled = !!atoi(optarg);
+                       break;
                case 'h':
                case '?':
                default:
@@ -575,12 +583,12 @@ int main(int argc, char *argv[])
        for (i = 0; i < depth; i++) {
                void *buf;
 
-               if (posix_memalign(&buf, BS, BS)) {
+               if (posix_memalign(&buf, bs, bs)) {
                        printf("failed alloc\n");
                        return 1;
                }
                s->iovecs[i].iov_base = buf;
-               s->iovecs[i].iov_len = BS;
+               s->iovecs[i].iov_len = bs;
        }
 
        err = setup_ring(s);
diff --git a/t/jobs/t0012.fio b/t/jobs/t0012.fio
new file mode 100644 (file)
index 0000000..985eb16
--- /dev/null
@@ -0,0 +1,20 @@
+# Expected results: no parse warnings, runs and with roughly 1/8 iops between
+#                      the two jobs.
+# Buggy result: parse warning on flow value overflow, no 1/8 division between
+#                      jobs.
+#
+
+[global]
+bs=4k
+ioengine=null
+size=100g
+runtime=3
+flow_id=1
+gtod_cpu=1
+
+[flow1]
+flow=-8
+rate_iops=1000
+
+[flow2]
+flow=1
diff --git a/t/jobs/t0013.fio b/t/jobs/t0013.fio
new file mode 100644 (file)
index 0000000..b4ec1b4
--- /dev/null
@@ -0,0 +1,14 @@
+# Trigger the fio code that serializes overlapping I/O. The job size is very
+# small to make overlapping I/O more likely.
+
+[test]
+ioengine=null
+thread=1
+size=4K
+blocksize=4K
+io_submit_mode=offload
+iodepth=1
+serialize_overlap=1
+numjobs=8
+loops=1000000
+runtime=10
index c2352d80c2bf5ab339672ecc19768510971686e9..c116bf5a913e1045ac797ff5028d5cbb7b637efc 100755 (executable)
@@ -420,14 +420,14 @@ class FioJobTest_t0009(FioJobTest):
             self.passed = False
 
 
-class FioJobTest_t0011(FioJobTest):
+class FioJobTest_iops_rate(FioJobTest):
     """Test consists of fio test job t0009
     Confirm that job0 iops == 1000
     and that job1_iops / job0_iops ~ 8
     With two runs of fio-3.16 I observed a ratio of 8.3"""
 
     def check_result(self):
-        super(FioJobTest_t0011, self).check_result()
+        super(FioJobTest_iops_rate, self).check_result()
 
         if not self.passed:
             return
@@ -438,7 +438,7 @@ class FioJobTest_t0011(FioJobTest):
         logging.debug("Test %d: iops1: %f", self.testnum, iops1)
         logging.debug("Test %d: ratio: %f", self.testnum, ratio)
 
-        if iops1 < 997 or iops1 > 1003:
+        if iops1 < 950 or iops1 > 1050:
             self.failure_reason = "{0} iops value mismatch,".format(self.failure_reason)
             self.passed = False
 
@@ -447,6 +447,13 @@ class FioJobTest_t0011(FioJobTest):
             self.passed = False
 
 
+class FioJobTest_t0013(FioJobTest):
+    """Runs fio test job t0013"""
+
+    def check_result(self):
+        super(FioJobTest_t0013, self).check_result()
+
+
 class Requirements(object):
     """Requirements consists of multiple run environment characteristics.
     These are to determine if a particular test can be run"""
@@ -667,7 +674,7 @@ TEST_LIST = [
     },
     {
         'test_id':          11,
-        'test_class':       FioJobTest_t0011,
+        'test_class':       FioJobTest_iops_rate,
         'job':              't0011-5d2788d5.fio',
         'success':          SUCCESS_DEFAULT,
         'pre_job':          None,
@@ -675,6 +682,28 @@ TEST_LIST = [
         'output_format':    'json',
         'requirements':     [],
     },
+    {
+        'test_id':          12,
+        'test_class':       FioJobTest_iops_rate,
+        'job':              't0012.fio',
+        'success':          SUCCESS_DEFAULT,
+        'pre_job':          None,
+        'pre_success':      None,
+        'output_format':    'json',
+        'requirements':     [],
+        'requirements':     [Requirements.not_macos],
+        # mac os does not support CPU affinity
+    },
+    {
+        'test_id':          13,
+        'test_class':       FioJobTest_t0013,
+        'job':              't0013.fio',
+        'success':          SUCCESS_DEFAULT,
+        'pre_job':          None,
+        'pre_success':      None,
+        'output_format':    'json',
+        'requirements':     [],
+    },
     {
         'test_id':          1000,
         'test_class':       FioExeTest,
index 4001be3b6c3f0d1615aaf076729b6a6aaba72195..80dc3f30b2442f04abc99b94e451829e6d31b805 100755 (executable)
@@ -109,6 +109,20 @@ run_one_fio_job() {
            --thread=1 --direct=1
 }
 
+write_and_run_one_fio_job() {
+    local r
+    local write_offset="${1}"
+    local write_size="${2}"
+
+    shift 2
+    r=$(((RANDOM << 16) | RANDOM))
+    run_fio --filename="$dev" --randseed="$r"  --name="write_job" --rw=write \
+           "$(ioengine "psync")" --bs="${logical_block_size}" \
+           --zonemode=zbd --zonesize="${zone_size}" --thread=1 --direct=1 \
+           --offset="${write_offset}" --size="${write_size}" \
+           --name="$dev" --wait_for="write_job" "$@" --thread=1 --direct=1
+}
+
 # Run fio on the first four sequential zones of the disk.
 run_fio_on_seq() {
     local opts=()
@@ -170,13 +184,7 @@ test3() {
        opts+=("--zonesize=${zone_size}")
     fi
     run_fio "${opts[@]}" >> "${logfile}.${test_number}" 2>&1 || return $?
-    grep -q 'READ:' "${logfile}.${test_number}"
-    rc=$?
-    if [ -n "$is_zbd" ]; then
-       [ $rc != 0 ]
-    else
-       [ $rc = 0 ]
-    fi
+    ! grep -q 'READ:' "${logfile}.${test_number}"
 }
 
 # Run fio with --read_beyond_wp=1 against an empty zone.
@@ -207,14 +215,18 @@ test5() {
     check_read $size || return $?
 }
 
-# Sequential read from sequential zones. Must be run after test5.
+# Sequential read from sequential zones.
 test6() {
     local size
 
     size=$((4 * zone_size))
-    run_fio_on_seq "$(ioengine "psync")" --iodepth=1 --rw=read \
-                  --bs="$(max $((zone_size / 64)) "$logical_block_size")"\
-                  >>"${logfile}.${test_number}" 2>&1 || return $?
+    write_and_run_one_fio_job \
+           $((first_sequential_zone_sector * 512)) "${size}" \
+           --offset=$((first_sequential_zone_sector * 512)) \
+           --size="${size}" --zonemode=zbd --zonesize="${zone_size}" \
+           "$(ioengine "psync")" --iodepth=1 --rw=read \
+           --bs="$(max $((zone_size / 64)) "$logical_block_size")" \
+           >>"${logfile}.${test_number}" 2>&1 || return $?
     check_read $size || return $?
 }
 
@@ -337,41 +349,45 @@ test14() {
 # Sequential read on a mix of empty and full zones.
 test15() {
     local i off size
+    local w_off w_size
 
     for ((i=0;i<4;i++)); do
        [ -n "$is_zbd" ] &&
            reset_zone "$dev" $((first_sequential_zone_sector +
                                 i*sectors_per_zone))
     done
-    off=$(((first_sequential_zone_sector + 2 * sectors_per_zone) * 512))
-    size=$((2 * zone_size))
-    run_one_fio_job "$(ioengine "psync")" --rw=write --bs=$((zone_size / 16))\
-                   --zonemode=zbd --zonesize="${zone_size}" --offset=$off \
-                   --size=$size >>"${logfile}.${test_number}" 2>&1 ||
-       return $?
-    check_written $size || return $?
+    w_off=$(((first_sequential_zone_sector + 2 * sectors_per_zone) * 512))
+    w_size=$((2 * zone_size))
     off=$((first_sequential_zone_sector * 512))
     size=$((4 * zone_size))
-    run_one_fio_job "$(ioengine "psync")" --rw=read --bs=$((zone_size / 16)) \
+    write_and_run_one_fio_job "${w_off}" "${w_size}" \
+                   "$(ioengine "psync")" --rw=read --bs=$((zone_size / 16)) \
                    --zonemode=zbd --zonesize="${zone_size}" --offset=$off \
                    --size=$((size)) >>"${logfile}.${test_number}" 2>&1 ||
        return $?
-    if [ -n "$is_zbd" ]; then
-       check_read $((size / 2))
-    else
-       check_read $size
-    fi
+    check_written $((w_size)) || return $?
+    check_read $((size / 2))
 }
 
-# Random read on a mix of empty and full zones. Must be run after test15.
+# Random read on a mix of empty and full zones.
 test16() {
     local off size
+    local i w_off w_size
 
+    for ((i=0;i<4;i++)); do
+       [ -n "$is_zbd" ] &&
+           reset_zone "$dev" $((first_sequential_zone_sector +
+                                i*sectors_per_zone))
+    done
+    w_off=$(((first_sequential_zone_sector + 2 * sectors_per_zone) * 512))
+    w_size=$((2 * zone_size))
     off=$((first_sequential_zone_sector * 512))
     size=$((4 * zone_size))
-    run_one_fio_job "$(ioengine "libaio")" --iodepth=64 --rw=randread --bs=16K \
+    write_and_run_one_fio_job "${w_off}" "${w_size}" \
+                   "$(ioengine "libaio")" --iodepth=64 --rw=randread --bs=16K \
                    --zonemode=zbd --zonesize="${zone_size}" --offset=$off \
                    --size=$size >>"${logfile}.${test_number}" 2>&1 || return $?
+    check_written $w_size || return $?
     check_read $size || return $?
 }
 
@@ -381,15 +397,9 @@ test17() {
 
     off=$(((disk_size / zone_size - 1) * zone_size))
     size=$((disk_size - off))
-    # Overwrite the last zone to avoid that reading from that zone fails.
     if [ -n "$is_zbd" ]; then
        reset_zone "$dev" $((off / 512)) || return $?
     fi
-    run_one_fio_job "$(ioengine "psync")" --rw=write --offset="$off"   \
-                   --zonemode=zbd --zonesize="${zone_size}"            \
-                   --bs="$zone_size" --size="$zone_size"               \
-                   >>"${logfile}.${test_number}" 2>&1 || return $?
-    check_written "$zone_size" || return $?
     run_one_fio_job "$(ioengine "libaio")" --iodepth=8 --rw=randrw --bs=4K \
                    --zonemode=zbd --zonesize="${zone_size}"            \
                    --offset=$off --loops=2 --norandommap=1\
@@ -763,10 +773,8 @@ test46() {
 test47() {
     local bs
 
-    [ -z "$is_zbd" ] && return 0
     bs=$((logical_block_size))
-    run_one_fio_job "$(ioengine "psync")" --rw=write --bs=$bs \
-                   --zonemode=zbd --zoneskip=1          \
+    run_fio_on_seq "$(ioengine "psync")" --rw=write --bs=$bs --zoneskip=1 \
                    >> "${logfile}.${test_number}" 2>&1 && return 1
     grep -q 'zoneskip 1 is not a multiple of the device zone size' "${logfile}.${test_number}"
 }
diff --git a/unittests/lib/num2str.c b/unittests/lib/num2str.c
new file mode 100644 (file)
index 0000000..a3492a8
--- /dev/null
@@ -0,0 +1,53 @@
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include "../../compiler/compiler.h"
+#include "../../lib/num2str.h"
+#include "../unittest.h"
+
+struct testcase {
+       uint64_t num;
+       int maxlen;
+       int base;
+       int pow2;
+       enum n2s_unit unit;
+       const char *expected;
+};
+
+static const struct testcase testcases[] = {
+       { 1, 1, 1, 0, N2S_NONE, "1" },
+       { UINT64_MAX, 99, 1, 0, N2S_NONE, "18446744073709551615" },
+       { 18446744073709551, 2, 1, 0, N2S_NONE, "18P" },
+       { 18446744073709551, 4, 1, 0, N2S_NONE, "18.4P" },
+       { UINT64_MAX, 2, 1, 0, N2S_NONE, "18E" },
+       { UINT64_MAX, 4, 1, 0, N2S_NONE, "18.4E" },
+};
+
+static void test_num2str(void)
+{
+       const struct testcase *p;
+       char *str;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(testcases); ++i) {
+               p = &testcases[i];
+               str = num2str(p->num, p->maxlen, p->base, p->pow2, p->unit);
+               CU_ASSERT_STRING_EQUAL(str, p->expected);
+               free(str);
+       }
+}
+
+static struct fio_unittest_entry tests[] = {
+       {
+               .name   = "num2str/1",
+               .fn     = test_num2str,
+       },
+       {
+               .name   = NULL,
+       },
+};
+
+CU_ErrorCode fio_unittest_lib_num2str(void)
+{
+       return fio_unittest_add_suite("lib/num2str.c", NULL, NULL, tests);
+}
index c37e1971a0518544c2cdc136b5e276f387b16d4e..f490b4852b2f0a0a5e7ebbb62be33f2039573fcc 100644 (file)
@@ -48,6 +48,7 @@ int main(void)
        }
 
        fio_unittest_register(fio_unittest_lib_memalign);
+       fio_unittest_register(fio_unittest_lib_num2str);
        fio_unittest_register(fio_unittest_lib_strntol);
        fio_unittest_register(fio_unittest_oslib_strlcat);
        fio_unittest_register(fio_unittest_oslib_strndup);
index 786c1c97ec8f149b8b43c4cd7b6dbe017966230c..ecb7d12415209464da4a6d13b488233108eb25d6 100644 (file)
@@ -15,6 +15,7 @@ CU_ErrorCode fio_unittest_add_suite(const char*, CU_InitializeFunc,
        CU_CleanupFunc, struct fio_unittest_entry*);
 
 CU_ErrorCode fio_unittest_lib_memalign(void);
+CU_ErrorCode fio_unittest_lib_num2str(void);
 CU_ErrorCode fio_unittest_lib_strntol(void);
 CU_ErrorCode fio_unittest_oslib_strlcat(void);
 CU_ErrorCode fio_unittest_oslib_strndup(void);
index b7fa6693068d851f2ffb4c48a3044cfe4eb11f34..5ee0029d130e2f891d48cbd6c1ee01203085a6c3 100644 (file)
--- a/verify.c
+++ b/verify.c
@@ -8,6 +8,7 @@
 #include <pthread.h>
 #include <libgen.h>
 
+#include "arch/arch.h"
 #include "fio.h"
 #include "verify.h"
 #include "trim.h"
@@ -1309,8 +1310,7 @@ int get_next_verify(struct thread_data *td, struct io_u *io_u)
                /*
                 * Ensure that the associated IO has completed
                 */
-               read_barrier();
-               if (ipo->flags & IP_F_IN_FLIGHT)
+               if (atomic_load_acquire(&ipo->flags) & IP_F_IN_FLIGHT)
                        goto nothing;
 
                rb_erase(n, &td->io_hist_tree);
@@ -1322,8 +1322,7 @@ int get_next_verify(struct thread_data *td, struct io_u *io_u)
                /*
                 * Ensure that the associated IO has completed
                 */
-               read_barrier();
-               if (ipo->flags & IP_F_IN_FLIGHT)
+               if (atomic_load_acquire(&ipo->flags) & IP_F_IN_FLIGHT)
                        goto nothing;
 
                flist_del(&ipo->list);
index b59595124913338bc59dc20fb6a036c895b4f1f1..9e6c41ff2f399172703b6e438061236670962df8 100644 (file)
@@ -85,15 +85,14 @@ static bool all_sw_idle(struct workqueue *wq)
  */
 void workqueue_flush(struct workqueue *wq)
 {
+       pthread_mutex_lock(&wq->flush_lock);
        wq->wake_idle = 1;
 
-       while (!all_sw_idle(wq)) {
-               pthread_mutex_lock(&wq->flush_lock);
+       while (!all_sw_idle(wq))
                pthread_cond_wait(&wq->flush_cond, &wq->flush_lock);
-               pthread_mutex_unlock(&wq->flush_lock);
-       }
 
        wq->wake_idle = 0;
+       pthread_mutex_unlock(&wq->flush_lock);
 }
 
 /*
@@ -159,12 +158,10 @@ static void *worker_thread(void *data)
        if (sw->flags & SW_F_ERROR)
                goto done;
 
+       pthread_mutex_lock(&sw->lock);
        while (1) {
-               pthread_mutex_lock(&sw->lock);
-
                if (flist_empty(&sw->work_list)) {
                        if (sw->flags & SW_F_EXIT) {
-                               pthread_mutex_unlock(&sw->lock);
                                break;
                        }
 
@@ -173,34 +170,41 @@ static void *worker_thread(void *data)
                                workqueue_pre_sleep(sw);
                                pthread_mutex_lock(&sw->lock);
                        }
-
-                       /*
-                        * We dropped and reaquired the lock, check
-                        * state again.
-                        */
-                       if (!flist_empty(&sw->work_list))
-                               goto handle_work;
-
+               }
+               /*
+                * We may have dropped and reaquired the lock, check state
+                * again.
+                */
+               if (flist_empty(&sw->work_list)) {
                        if (sw->flags & SW_F_EXIT) {
-                               pthread_mutex_unlock(&sw->lock);
                                break;
-                       } else if (!(sw->flags & SW_F_IDLE)) {
+                       }
+                       if (!(sw->flags & SW_F_IDLE)) {
                                sw->flags |= SW_F_IDLE;
                                wq->next_free_worker = sw->index;
+                               pthread_mutex_unlock(&sw->lock);
+                               pthread_mutex_lock(&wq->flush_lock);
                                if (wq->wake_idle)
                                        pthread_cond_signal(&wq->flush_cond);
+                               pthread_mutex_unlock(&wq->flush_lock);
+                               pthread_mutex_lock(&sw->lock);
+                       }
+               }
+               if (flist_empty(&sw->work_list)) {
+                       if (sw->flags & SW_F_EXIT) {
+                               break;
                        }
-
                        pthread_cond_wait(&sw->cond, &sw->lock);
                } else {
-handle_work:
                        flist_splice_init(&sw->work_list, &local_list);
                }
                pthread_mutex_unlock(&sw->lock);
                handle_list(sw, &local_list);
                if (wq->ops.update_acct_fn)
                        wq->ops.update_acct_fn(sw);
+               pthread_mutex_lock(&sw->lock);
        }
+       pthread_mutex_unlock(&sw->lock);
 
 done:
        sk_out_drop();
@@ -336,11 +340,11 @@ int workqueue_init(struct thread_data *td, struct workqueue *wq,
         * Wait for them all to be started and initialized
         */
        error = 0;
+       pthread_mutex_lock(&wq->flush_lock);
        do {
                struct submit_worker *sw;
 
                running = 0;
-               pthread_mutex_lock(&wq->flush_lock);
                for (i = 0; i < wq->max_workers; i++) {
                        sw = &wq->workers[i];
                        pthread_mutex_lock(&sw->lock);
@@ -351,14 +355,12 @@ int workqueue_init(struct thread_data *td, struct workqueue *wq,
                        pthread_mutex_unlock(&sw->lock);
                }
 
-               if (error || running == wq->max_workers) {
-                       pthread_mutex_unlock(&wq->flush_lock);
+               if (error || running == wq->max_workers)
                        break;
-               }
 
                pthread_cond_wait(&wq->flush_cond, &wq->flush_lock);
-               pthread_mutex_unlock(&wq->flush_lock);
        } while (1);
+       pthread_mutex_unlock(&wq->flush_lock);
 
        if (!error)
                return 0;
diff --git a/zbd.c b/zbd.c
index 8cf8f81213ebfcd8083a2f3602932deec9c276cc..cf2cded93cff4371263106d3e7c0c9c02a6640c0 100644 (file)
--- a/zbd.c
+++ b/zbd.c
@@ -381,7 +381,7 @@ static int init_zone_info(struct thread_data *td, struct fio_file *f)
                mutex_init_pshared_with_type(&p->mutex,
                                             PTHREAD_MUTEX_RECURSIVE);
                p->start = i * zone_size;
-               p->wp = p->start + zone_size;
+               p->wp = p->start;
                p->type = ZBD_ZONE_TYPE_SWR;
                p->cond = ZBD_ZONE_COND_EMPTY;
        }