Recent changes (master)
Jens Axboe <[email protected]> Sat, 19 Jul 2025 06:00:02 -0600 (MDT)
| Newsgroups | org.kernel.vger.fio |
|---|---|
| Message-ID | <[email protected]> |
The following changes since commit 34fa726e0ae0236c36fb1409bddeab2bab7839d2:
Merge branch 'fsync-get-io-u-from-freelist' of https://github.com/jeongjonghwi/fio (2025-07-16 11:59:46 -0400)
are available in the Git repository at:
git://git.kernel.dk/fio.git master
for you to fetch changes up to 60c19edf22e4a81fe0320370c2386c5b42127dc0:
Merge branch 'fix/io_uring-cq-reap' of https://github.com/calebsander/fio (2025-07-18 12:38:12 -0600)
----------------------------------------------------------------
Caleb Sander Mateos (7):
Revert "engines/io_uring: update getevents max to reflect previously seen events"
engines/io_uring: consolidate fio_ioring_cqring_reap() arguments
engines/io_uring: remove loop over CQEs in fio_ioring_cqring_reap()
engines/io_uring: return unsigned from fio_ioring_cqring_reap()
engines/io_uring: simplify getevents control flow
arch: add atomic_store_relaxed()
engines/io_uring: relax CQ head atomic store ordering
Jens Axboe (1):
Merge branch 'fix/io_uring-cq-reap' of https://github.com/calebsander/fio
arch/arch.h | 5 +++++
engines/io_uring.c | 46 +++++++++++++++++++++++-----------------------
2 files changed, 28 insertions(+), 23 deletions(-)
---
Diff of recent changes:
diff --git a/arch/arch.h b/arch/arch.h
index 7e294ddf..437736f8 100644
--- a/arch/arch.h
+++ b/arch/arch.h
@@ -53,6 +53,8 @@ extern unsigned long arch_flags;
#define atomic_load_acquire(p) \
std::atomic_load_explicit(p, \
std::memory_order_acquire)
+#define atomic_store_relaxed(p, v) \
+ std::atomic_store_explicit((p), (v), std::memory_order_relaxed)
#define atomic_store_release(p, v) \
std::atomic_store_explicit(p, (v), \
std::memory_order_release)
@@ -67,6 +69,9 @@ extern unsigned long arch_flags;
#define atomic_load_acquire(p) \
atomic_load_explicit((_Atomic typeof(*(p)) *)(p), \
memory_order_acquire)
+#define atomic_store_relaxed(p, v) \
+ atomic_store_explicit((_Atomic typeof(*(p)) *)(p), (v), \
+ memory_order_relaxed)
#define atomic_store_release(p, v) \
atomic_store_explicit((_Atomic typeof(*(p)) *)(p), (v), \
memory_order_release)
diff --git a/engines/io_uring.c b/engines/io_uring.c
index c87e1cd4..87018f84 100644
--- a/engines/io_uring.c
+++ b/engines/io_uring.c
@@ -674,25 +674,26 @@ static char *fio_ioring_cmd_errdetails(struct thread_data *td,
return msg;
}
-static int fio_ioring_cqring_reap(struct thread_data *td, unsigned int events,
- unsigned int max)
+static unsigned fio_ioring_cqring_reap(struct thread_data *td, unsigned int max)
{
struct ioring_data *ld = td->io_ops_data;
struct io_cq_ring *ring = &ld->cq_ring;
- unsigned head, reaped = 0;
+ unsigned head = *ring->head;
+ unsigned available = atomic_load_acquire(ring->tail) - head;
- head = *ring->head;
- do {
- if (head == atomic_load_acquire(ring->tail))
- break;
- reaped++;
- head++;
- } while (reaped + events < max);
-
- if (reaped)
- atomic_store_release(ring->head, head);
+ if (!available)
+ return 0;
- return reaped;
+ available = min(available, max);
+ /*
+ * The CQ consumer index is advanced before the CQEs are actually read.
+ * This is generally unsafe, as it lets the kernel reuse the CQE slots.
+ * However, the CQ is sized large enough for the maximum iodepth and a
+ * new SQE won't be submitted until the CQE is processed, so the CQE
+ * slot won't actually be reused until it has been processed.
+ */
+ atomic_store_relaxed(ring->head, head + available);
+ return available;
}
static int fio_ioring_getevents(struct thread_data *td, unsigned int min,
@@ -706,14 +707,15 @@ static int fio_ioring_getevents(struct thread_data *td, unsigned int min,
int r;
ld->cq_ring_off = *ring->head;
- do {
- r = fio_ioring_cqring_reap(td, events, max);
+ for (;;) {
+ r = fio_ioring_cqring_reap(td, max - events);
if (r) {
events += r;
- max -= r;
+ if (events >= min)
+ return events;
+
if (actual_min != 0)
actual_min -= r;
- continue;
}
if (!o->sqpoll_thread) {
@@ -724,12 +726,10 @@ static int fio_ioring_getevents(struct thread_data *td, unsigned int min,
continue;
r = -errno;
td_verror(td, errno, "io_uring_enter");
- break;
+ return r;
}
}
- } while (events < min);
-
- return r < 0 ? r : events;
+ }
}
static inline void fio_ioring_cmd_nvme_pi(struct thread_data *td,
@@ -884,7 +884,7 @@ static int fio_ioring_commit(struct thread_data *td)
continue;
} else {
if (errno == EAGAIN || errno == EINTR) {
- ret = fio_ioring_cqring_reap(td, 0, ld->queued);
+ ret = fio_ioring_cqring_reap(td, ld->queued);
if (ret)
continue;
/* Shouldn't happen */