[PATCH v3 22/22] ext4: add tracepoints for ordered I/O in the iomap buffered I/O path

From: Zhang Yi

Date: Tue Apr 21 2026 - 22:24:02 EST


From: Zhang Yi <yi.zhang@xxxxxxxxxx>

To facilitate the tracing of ordered I/Os in the iomap buffered I/O
path, add tracepoints to track the ordered I/O flow:

- ext4_iomap_ordered_submit: trace when ordered I/O is being submitted;
- ext4_iomap_ordered_complete: trace when ordered I/O completes;
- ext4_iomap_disksize_update: trace when i_disksize is updated, either
when appending I/O or when an ordered I/O completes;
- ext4_block_zero_eof - trace zero EOF partial block.

Signed-off-by: Zhang Yi <yi.zhang@xxxxxxxxxx>
---
fs/ext4/inode.c | 4 ++
fs/ext4/page-io.c | 8 +++
include/trace/events/ext4.h | 97 +++++++++++++++++++++++++++++++++++++
3 files changed, 109 insertions(+)

diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index d983336390c7..ca4284da2a2b 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4377,6 +4377,9 @@ static int ext4_iomap_writeback_submit(struct iomap_writepage_ctx *wpc,
ioend->io_offset + ioend->io_size);

if (start <= order_lblk && end >= order_lblk + order_len) {
+ trace_ext4_iomap_ordered_submit(ioend->io_inode,
+ ioend->io_offset, ioend->io_size,
+ order_lblk, order_len);
ioend->io_bio.bi_end_io = ext4_iomap_end_bio;
ioend->io_private = (void *)EXT4_IOMAP_IOEND_ORDER_IO;
ioend->io_flags |= IOMAP_IOEND_BOUNDARY;
@@ -4879,6 +4882,7 @@ int ext4_block_zero_eof(struct inode *inode, loff_t from, loff_t end)
}
}

+ trace_ext4_block_zero_eof(inode, from, length, did_zero, zero_written);
return 0;
}

diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 589c74b9f8a3..979a88c38fff 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -31,6 +31,8 @@
#include "xattr.h"
#include "acl.h"

+#include <trace/events/ext4.h>
+
static struct kmem_cache *io_end_cachep;
static struct kmem_cache *io_end_vec_cachep;

@@ -673,6 +675,9 @@ static int ext4_iomap_wb_update_disksize(handle_t *handle, struct inode *inode,
* never be exposed.
*/
new_disksize = is_ordered ? i_size : min(end, i_size);
+ trace_ext4_iomap_disksize_update(inode, end, i_size, ei->i_disksize,
+ new_disksize, is_ordered);
+
if (new_disksize > ei->i_disksize)
ei->i_disksize = new_disksize;
up_write(&ei->i_data_sem);
@@ -782,6 +787,9 @@ void ext4_iomap_end_bio(struct bio *bio)
* waiters.
*/
smp_store_release(&ei->i_ordered_len, 0);
+ trace_ext4_iomap_ordered_complete(inode, ioend->io_offset,
+ ioend->io_size, READ_ONCE(ei->i_ordered_lblk),
+ READ_ONCE(ei->i_ordered_len));
wake_up_all(&ei->i_ordered_wq);
goto defer;
}
diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h
index ebafa06cd191..423aec6d09d1 100644
--- a/include/trace/events/ext4.h
+++ b/include/trace/events/ext4.h
@@ -3141,6 +3141,103 @@ DEFINE_SET_IOMAP_EVENT(ext4_iomap_buffered_write_begin);
DEFINE_SET_IOMAP_EVENT(ext4_iomap_map_writeback_range);
DEFINE_SET_IOMAP_EVENT(ext4_iomap_zero_begin);

+/* Ordered I/O tracepoints for iomap buffered I/O path */
+DECLARE_EVENT_CLASS(ext4_iomap_ordered_io,
+ TP_PROTO(struct inode *inode, loff_t io_offset, size_t io_size,
+ ext4_lblk_t i_ordered_lblk, unsigned int i_ordered_len),
+ TP_ARGS(inode, io_offset, io_size, i_ordered_lblk, i_ordered_len),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(u64, ino)
+ __field(loff_t, io_offset)
+ __field(size_t, io_size)
+ __field(ext4_lblk_t, i_ordered_lblk)
+ __field(unsigned int, i_ordered_len)
+ ),
+ TP_fast_assign(
+ __entry->dev = inode->i_sb->s_dev;
+ __entry->ino = inode->i_ino;
+ __entry->io_offset = io_offset;
+ __entry->io_size = io_size;
+ __entry->i_ordered_lblk = i_ordered_lblk;
+ __entry->i_ordered_len = i_ordered_len;
+ ),
+ TP_printk("dev %d:%d ino %llu io_offset %lld io_size %zu i_ordered_lblk %u i_ordered_len %u",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->ino, __entry->io_offset, __entry->io_size,
+ __entry->i_ordered_lblk, __entry->i_ordered_len)
+);
+
+DEFINE_EVENT(ext4_iomap_ordered_io, ext4_iomap_ordered_submit,
+ TP_PROTO(struct inode *inode, loff_t io_offset, size_t io_size,
+ ext4_lblk_t i_ordered_lblk, unsigned int i_ordered_len),
+ TP_ARGS(inode, io_offset, io_size, i_ordered_lblk, i_ordered_len)
+);
+
+DEFINE_EVENT(ext4_iomap_ordered_io, ext4_iomap_ordered_complete,
+ TP_PROTO(struct inode *inode, loff_t io_offset, size_t io_size,
+ ext4_lblk_t i_ordered_lblk, unsigned int i_ordered_len),
+ TP_ARGS(inode, io_offset, io_size, i_ordered_lblk, i_ordered_len)
+);
+
+
+/* i_disksize update tracepoint */
+TRACE_EVENT(ext4_iomap_disksize_update,
+ TP_PROTO(struct inode *inode, loff_t end, loff_t i_size,
+ loff_t i_disksize, loff_t new_disksize, bool is_ordered),
+ TP_ARGS(inode, end, i_size, i_disksize, new_disksize, is_ordered),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(u64, ino)
+ __field(loff_t, end)
+ __field(loff_t, i_size)
+ __field(loff_t, i_disksize)
+ __field(loff_t, new_disksize)
+ __field(bool, is_ordered)
+ ),
+ TP_fast_assign(
+ __entry->dev = inode->i_sb->s_dev;
+ __entry->ino = inode->i_ino;
+ __entry->end = end;
+ __entry->i_size = i_size;
+ __entry->i_disksize = i_disksize;
+ __entry->new_disksize = new_disksize;
+ __entry->is_ordered = is_ordered;
+ ),
+ TP_printk("dev %d:%d ino %llu end %lld i_size %lld i_disksize %lld new_disksize %lld is_ordered %d",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->ino, __entry->end, __entry->i_size,
+ __entry->i_disksize, __entry->new_disksize,
+ __entry->is_ordered)
+);
+
+/* Block zero EOF tracepoint */
+TRACE_EVENT(ext4_block_zero_eof,
+ TP_PROTO(struct inode *inode, loff_t from, loff_t length,
+ bool did_zero, bool zero_written),
+ TP_ARGS(inode, from, length, did_zero, zero_written),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(u64, ino)
+ __field(loff_t, from)
+ __field(loff_t, length)
+ __field(bool, did_zero)
+ __field(bool, zero_written)
+ ),
+ TP_fast_assign(
+ __entry->dev = inode->i_sb->s_dev;
+ __entry->ino = inode->i_ino;
+ __entry->from = from;
+ __entry->length = length;
+ __entry->did_zero = did_zero;
+ __entry->zero_written = zero_written;
+ ),
+ TP_printk("dev %d:%d ino %llu zero EOF from %lld length %lld did_zero %d zero_written %d",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->ino, __entry->from, __entry->length,
+ __entry->did_zero, __entry->zero_written)
+);
+
#endif /* _TRACE_EXT4_H */

/* This part must be outside protection */
--
2.52.0