Enable error checking for the mutex that serializes overlapping I/O
authorBart Van Assche <bvanassche@acm.org>
Sat, 13 Jun 2020 18:33:37 +0000 (11:33 -0700)
committerBart Van Assche <bvanassche@acm.org>
Sat, 4 Jul 2020 04:20:30 +0000 (21:20 -0700)
Since it is nontrivial to verify that pthread_mutex_lock() and unlock
calls are paired for the overlap_check mutex, enable runtime verification.
The PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP initializer causes
pthread_mutex_lock() to fail with EDEADLK if the mutex was already locked
and causes pthread_mutex_unlock() to fail with EPERM if the mutex is owned
by another thread.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
backend.c
ioengines.c
rate-submit.c

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);
index c1b430a1722bfd2ee5f7566bbcf5775b413cd472..1c5970a4b5a188e5f4aa5f924b483c976a04142f 100644 (file)
@@ -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));
 
index 3bcb5053d8be1b69d6f68906239ceb6a939a2c44..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"
@@ -11,7 +12,7 @@
 
 static void check_overlap(struct io_u *io_u)
 {
-       int i;
+       int i, res;
        struct thread_data *td;
 
        /*
@@ -26,7 +27,8 @@ static void check_overlap(struct io_u *io_u)
         * 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);
+       res = pthread_mutex_lock(&overlap_check);
+       assert(res == 0);
 
 retry:
        for_each_td(td, i) {
@@ -39,8 +41,10 @@ retry:
                if (!in_flight_overlap(&td->io_u_all, io_u))
                        continue;
 
-               pthread_mutex_unlock(&overlap_check);
-               pthread_mutex_lock(&overlap_check);
+               res = pthread_mutex_unlock(&overlap_check);
+               assert(res == 0);
+               res = pthread_mutex_lock(&overlap_check);
+               assert(res == 0);
                goto retry;
        }
 }