From 14adf6e31487aa2bc8e47cd037428036089a3834 Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Fri, 14 Jul 2023 17:06:01 +0000 Subject: [PATCH] thinktime: Avoid calculating a negative time left to wait When the thinktime_spin option specifies a value that is within a few milliseconds of the thinktime value, in handle_thinktime() it's possible in a VM environment for the duration of usec_spin() to exceed the thinktime value. While doing usec_spin(), the vCPU could get de-scheduled or the hypervisor could steal CPU time from the vCPU. When the guest vCPU runs after being scheduled again, it may read the clock and find that more time has elapsed than intended. In such a case, the time left to wait could be calculated as a negative value. Subsequent calculations then go awry because the time left is cast as unsigned. Fix this by detecting when the time left would go negative and just set it to zero. Fixes: 1a9bf8146 ("Add option to ignore thinktime for rated IO") Fixes: https://github.com/axboe/fio/issues/1588 Link: https://lore.kernel.org/fio/1689354334-131024-1-git-send-email-mikelley@microsoft.com/T/#u Signed-off-by: Michael Kelley Signed-off-by: Vincent Fu --- backend.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/backend.c b/backend.c index d67a4a07c..b06a11a56 100644 --- a/backend.c +++ b/backend.c @@ -897,7 +897,16 @@ static void handle_thinktime(struct thread_data *td, enum fio_ddir ddir, if (left) total = usec_spin(left); - left = td->o.thinktime - total; + /* + * usec_spin() might run for slightly longer than intended in a VM + * where the vCPU could get descheduled or the hypervisor could steal + * CPU time. Ensure "left" doesn't become negative. + */ + if (total < td->o.thinktime) + left = td->o.thinktime - total; + else + left = 0; + if (td->o.timeout) { runtime_left = td->o.timeout - utime_since_now(&td->epoch); if (runtime_left < (unsigned long long)left)