Recent changes (master)

Jens Axboe <[email protected]> Thu, 2 Apr 2026 06:00:01 -0600
Newsgroups org.kernel.vger.fio
Message-ID <[email protected]>
The following changes since commit 698fa8f0682b809b3f85f50c593067e90108f92e:

  Merge branch 'fix-null-comm-prctl' of https://github.com/Criticayon/fio (2026-03-18 19:31:08 -0600)

are available in the Git repository at:

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

for you to fetch changes up to d0218ba66e9dc8402f1ac366b964277a1f2f2797:

  Merge branch 'fix_statsem_deadlock' of https://github.com/RyanTedrick/fio (2026-04-01 09:08:08 -0600)

----------------------------------------------------------------
Jens Axboe (1):
      Merge branch 'fix_statsem_deadlock' of https://github.com/RyanTedrick/fio

Ryan Tedrick (1):
      Fix stat_sem/rusage_sem deadlock during stats collection

 backend.c |  9 ++++-----
 stat.c    | 35 ++++++++++++++++++++++-------------
 2 files changed, 26 insertions(+), 18 deletions(-)

---

Diff of recent changes:

diff --git a/backend.c b/backend.c
index c63bbd07..4ce3d07f 100644
--- a/backend.c
+++ b/backend.c
@@ -2095,11 +2095,10 @@ static void *thread_main(void *data)
 		clear_state = true;
 
 		/*
-		 * Make sure we've successfully updated the rusage stats
-		 * before waiting on the stat mutex. Otherwise we could have
-		 * the stat thread holding stat mutex and waiting for
-		 * the rusage_sem, which would never get upped because
-		 * this thread is waiting for the stat mutex.
+		 * Service any pending rusage request, then acquire stat_sem to update
+		 * runtime counters. This trylock loop will primarily guard against
+		 * contention from concurrent stat calls or other slow operations under
+		 * stat_sem.
 		 */
 		deadlock_loop_cnt = 0;
 		do {
diff --git a/stat.c b/stat.c
index 63c9927f..305d1ae3 100644
--- a/stat.c
+++ b/stat.c
@@ -2821,16 +2821,35 @@ int __show_running_run_stats(void)
 	unsigned long long *rt;
 	struct timespec ts;
 
-	fio_sem_down(stat_sem);
-
 	rt = malloc(thread_number * sizeof(unsigned long long));
 	fio_gettime(&ts, NULL);
 
+	/*
+	 * Collect rusage from workers outside stat_sem to prevent deadlock caused
+	 * by semaphore contention between the stat thread and the worker threads.
+	 */
 	for_each_td(td) {
 		if (td->runstate >= TD_EXITED)
 			continue;
 
-		td->update_rusage = 1;
+		if (td->rusage_sem) {
+			td->update_rusage = 1;
+			/* Prevent deadlock if worker exits between first check and sem_down */
+			if (td->runstate >= TD_EXITED) {
+				td->update_rusage = 0;
+				continue;
+			}
+			fio_sem_down(td->rusage_sem);
+		}
+		td->update_rusage = 0;
+	} end_for_each();
+
+	fio_sem_down(stat_sem);
+
+	for_each_td(td) {
+		if (td->runstate >= TD_EXITED)
+			continue;
+	
 		for_each_rw_ddir(ddir) {
 			td->ts.io_bytes[ddir] = td->io_bytes[ddir];
 		}
@@ -2845,16 +2864,6 @@ int __show_running_run_stats(void)
 			td->ts.runtime[DDIR_TRIM] += rt[__td_index];
 	} end_for_each();
 
-	for_each_td(td) {
-		if (td->runstate >= TD_EXITED)
-			continue;
-		if (td->rusage_sem) {
-			td->update_rusage = 1;
-			fio_sem_down(td->rusage_sem);
-		}
-		td->update_rusage = 0;
-	} end_for_each();
-
 	__show_run_stats();
 
 	for_each_td(td) {