From bdb3d504dcfc11d44d6a4e6d2d099dffb933fb47 Mon Sep 17 00:00:00 2001 From: Roman Sofin Date: Mon, 25 Aug 2025 10:09:58 +0300 Subject: [PATCH 1/2] io_u: make should_fsync() take a const Make should_fsync() safer by using a pointer to a constant thread_data structure instance. Signed-off-by: Roman Sofin roma.sofin@gmail.com --- fio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fio.h b/fio.h index 4bb6cfa7f3..14163e2d2b 100644 --- a/fio.h +++ b/fio.h @@ -628,7 +628,7 @@ static inline bool multi_range_trim(struct thread_data *td, struct io_u *io_u) return false; } -static inline bool should_fsync(struct thread_data *td) +static inline bool should_fsync(const struct thread_data *td) { if (ddir_sync(td->last_ddir_issued)) return false; From 7b7f18c1e33c7223788bfd42490d673150b30079 Mon Sep 17 00:00:00 2001 From: Roman Sofin Date: Mon, 8 Sep 2025 11:44:29 +0300 Subject: [PATCH 2/2] io_u/backend: fix missing final fsync() when using fsync=N When fsync=N is specified and the final I/O issued happens to be the Nth, the following fsync() is missed. This update checks if it needs to loop again in do_io() to issue that final fsync when all the IO work is done. Signed-off-by: Roman Sofin roma.sofin@gmail.com --- backend.c | 7 ++++--- io_u.c | 37 +++++++++++++++++++++++++------------ io_u.h | 2 ++ 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/backend.c b/backend.c index fe03eab387..5704cb7db9 100644 --- a/backend.c +++ b/backend.c @@ -1000,7 +1000,8 @@ static void do_io(struct thread_data *td, uint64_t *bytes_done) while ((td->o.read_iolog_file && !flist_empty(&td->io_log_list)) || (!flist_empty(&td->trim_list)) || !io_issue_bytes_exceeded(td) || - td->o.time_based) { + td->o.time_based || + (should_fsync(td) && ddir_is_sync(td))) { struct timespec comp_time; struct io_u *io_u; int full; @@ -1032,8 +1033,8 @@ static void do_io(struct thread_data *td, uint64_t *bytes_done) */ if (bytes_issued >= total_bytes && !td->o.read_iolog_file && - (!td->o.time_based || - (td->o.time_based && td->o.verify != VERIFY_NONE))) + ((!td->o.time_based && !(should_fsync(td) && ddir_is_sync(td))) || + (td->o.time_based && td->o.verify != VERIFY_NONE))) break; io_u = get_io_u(td); diff --git a/io_u.c b/io_u.c index f81086b658..21b7f2a334 100644 --- a/io_u.c +++ b/io_u.c @@ -742,19 +742,8 @@ static enum fio_ddir rate_ddir(struct thread_data *td, enum fio_ddir ddir) return ddir; } -/* - * Return the data direction for the next io_u. If the job is a - * mixed read/write workload, check the rwmix cycle and switch if - * necessary. - */ -static enum fio_ddir get_rw_ddir(struct thread_data *td) +static inline enum fio_ddir get_sync_ddir(const struct thread_data *td) { - enum fio_ddir ddir; - - /* - * See if it's time to fsync/fdatasync/sync_file_range first, - * and if not then move on to check regular I/Os. - */ if (should_fsync(td) && td->last_ddir_issued == DDIR_WRITE) { if (td->o.fsync_blocks && td->io_issues[DDIR_WRITE] && !(td->io_issues[DDIR_WRITE] % td->o.fsync_blocks)) @@ -768,6 +757,30 @@ static enum fio_ddir get_rw_ddir(struct thread_data *td) !(td->io_issues[DDIR_WRITE] % td->sync_file_range_nr)) return DDIR_SYNC_FILE_RANGE; } + return DDIR_INVAL; +} + +bool ddir_is_sync(const struct thread_data *td) +{ + return get_sync_ddir(td) != DDIR_INVAL; +} + +/* + * Return the data direction for the next io_u. If the job is a + * mixed read/write workload, check the rwmix cycle and switch if + * necessary. + */ +static enum fio_ddir get_rw_ddir(struct thread_data *td) +{ + enum fio_ddir ddir; + + /* + * See if it's time to fsync/fdatasync/sync_file_range first, + * and if not then move on to check regular I/Os. + */ + ddir = get_sync_ddir(td); + if (ddir != DDIR_INVAL) + return ddir; if (td_rw(td)) { /* diff --git a/io_u.h b/io_u.h index ab93d50f96..25a0c0e865 100644 --- a/io_u.h +++ b/io_u.h @@ -169,6 +169,8 @@ bool queue_full(const struct thread_data *); int do_io_u_sync(const struct thread_data *, struct io_u *); int do_io_u_trim(struct thread_data *, struct io_u *); +bool ddir_is_sync(const struct thread_data *); + #ifdef FIO_INC_DEBUG static inline void dprint_io_u(struct io_u *io_u, const char *p) {