Recent changes (master)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The following changes since commit a504a3902e00b6db0183872b0ff62e35abae7119:

  configure: fix bad indentation (2020-07-03 08:34:56 -0600)

are available in the Git repository at:

  git://git.kernel.dk/fio.git master

for you to fetch changes up to 430083bf2a3db52bcb374919140d3a978391fbf0:

  Merge branch 'windows' of https://github.com/bvanassche/fio (2020-07-04 17:29:32 -0600)

----------------------------------------------------------------
Bart Van Assche (9):
      .appveyor.yml: Select the latest software image
      t/run-fio-tests.py: Increase IOPS tolerance further
      Fix a potentially infinite loop in check_overlap()
      Enable error checking for the mutex that serializes overlapping I/O
      Add a test for serialize_overlap=1
      workqueue: Rework while loop locking
      workqueue: Fix race conditions in the workqueue mechanism
      os/windows/posix.c: Strip trailing whitespace
      os/windows/posix.c: Use INVALID_SOCKET instead of < 0

Jens Axboe (3):
      Merge branch 'overlap' of https://github.com/bvanassche/fio
      Merge branch 'workqueue' of https://github.com/bvanassche/fio
      Merge branch 'windows' of https://github.com/bvanassche/fio

 .appveyor.yml      |  3 +++
 backend.c          | 18 ++++++++++-----
 ioengines.c        |  6 +++--
 os/windows/posix.c |  8 +++----
 rate-submit.c      | 66 ++++++++++++++++++++++++++++--------------------------
 t/jobs/t0013.fio   | 14 ++++++++++++
 t/run-fio-tests.py | 19 +++++++++++++++-
 workqueue.c        | 50 +++++++++++++++++++++--------------------
 8 files changed, 116 insertions(+), 68 deletions(-)
 create mode 100644 t/jobs/t0013.fio

---

Diff of recent changes:

diff --git a/.appveyor.yml b/.appveyor.yml
index 70c337f8..5f4a33e2 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -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
diff --git a/backend.c b/backend.c
index 0075a733..0e454cdd 100644
--- 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/ioengines.c b/ioengines.c
index c1b430a1..1c5970a4 100644
--- a/ioengines.c
+++ b/ioengines.c
@@ -313,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));
 
diff --git a/os/windows/posix.c b/os/windows/posix.c
index e36453e9..31271de0 100644
--- a/os/windows/posix.c
+++ b/os/windows/posix.c
@@ -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))
diff --git a/rate-submit.c b/rate-submit.c
index cf00d9bc..b7b70372 100644
--- a/rate-submit.c
+++ b/rate-submit.c
@@ -4,6 +4,7 @@
  * Copyright (C) 2015 Jens Axboe <axboe@xxxxxxxxx>
  *
  */
+#include <assert.h>
 #include "fio.h"
 #include "ioengines.h"
 #include "lib/getrusage.h"
@@ -11,40 +12,41 @@
 
 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,
diff --git a/t/jobs/t0013.fio b/t/jobs/t0013.fio
new file mode 100644
index 00000000..b4ec1b42
--- /dev/null
+++ b/t/jobs/t0013.fio
@@ -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
diff --git a/t/run-fio-tests.py b/t/run-fio-tests.py
index ae2cb096..c116bf5a 100755
--- a/t/run-fio-tests.py
+++ b/t/run-fio-tests.py
@@ -438,7 +438,7 @@ class FioJobTest_iops_rate(FioJobTest):
         logging.debug("Test %d: iops1: %f", self.testnum, iops1)
         logging.debug("Test %d: ratio: %f", self.testnum, ratio)
 
-        if iops1 < 995 or iops1 > 1005:
+        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_iops_rate(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"""
@@ -687,6 +694,16 @@ TEST_LIST = [
         '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,
diff --git a/workqueue.c b/workqueue.c
index b5959512..9e6c41ff 100644
--- a/workqueue.c
+++ b/workqueue.c
@@ -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;



[Index of Archives]     [Linux Kernel]     [Linux SCSI]     [Linux IDE]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux