[PATCH v2 09/11] iowatcher: natively parse blk_io_trace2

Johannes Thumshirn <[email protected]> Mon, 20 Jul 2026 13:14:15 +0200
Newsgroups org.kernel.vger.linux-btrace,org.kernel.vger.linux-block
Message-ID <[email protected]>
Natively parse 'struct blk_io_trace2' from a blktrace binary.

Reviewed-by: Damien Le Moal <[email protected]>
Signed-off-by: Johannes Thumshirn <[email protected]>
---
 iowatcher/blkparse.c | 69 +++++++++++++++++++++++++++++++++++++++++++-
 iowatcher/blkparse.h |  1 +
 2 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/iowatcher/blkparse.c b/iowatcher/blkparse.c
index ee1c2c511de6..92ee1cc8ec31 100644
--- a/iowatcher/blkparse.c
+++ b/iowatcher/blkparse.c
@@ -288,11 +288,75 @@ static void handle_notify(struct trace *trace)
 	}
 }
 
+/*
+ * Count how many consecutive well-formed traces the input holds when parsed
+ * with the given trace version.
+ */
+static int count_traces(struct trace *trace, int version)
+{
+	size_t hdr = (version == BLK_IO_TRACE2_VERSION) ?
+			sizeof(struct blk_io_trace2) : sizeof(struct blk_io_trace);
+	char *p = trace->start;
+	char *end = trace->start + trace->len;
+	int n = 0;
+
+	while (n < 16) {
+		struct blk_io_trace *io = (struct blk_io_trace *)p;
+		int pdu_len;
+
+		if (p == end)			/* traces tile up to the end */
+			break;
+		if (p + hdr > end)
+			break;
+		if (!CHECK_MAGIC(io))
+			break;
+
+		if (version == BLK_IO_TRACE2_VERSION)
+			pdu_len = ((struct blk_io_trace2 *)p)->pdu_len;
+		else
+			pdu_len = io->pdu_len;
+
+		p += hdr + pdu_len;
+		n++;
+	}
+
+	return n;
+}
+
+/*
+ * A recent blkparse always emits 'struct blk_io_trace2', while an old blkparse
+ * emits 'struct blk_io_trace'. As both share the same magic for version 1
+ * traces, the on-disk layout cannot be told apart by the version alone. Pick
+ * the layout that parses the input cleanly.
+ */
+static int detect_trace_version(struct trace *trace)
+{
+	struct blk_io_trace *io = (struct blk_io_trace *)trace->start;
+
+	if ((io->magic & 0xff) == BLK_IO_TRACE2_VERSION)
+		return BLK_IO_TRACE2_VERSION;
+
+	if (count_traces(trace, BLK_IO_TRACE2_VERSION) >=
+	    count_traces(trace, BLK_IO_TRACE_VERSION))
+		return BLK_IO_TRACE2_VERSION;
+
+	return BLK_IO_TRACE_VERSION;
+}
+
 static void trace_convert_io(struct trace *trace)
 {
 	struct blk_io_trace *old = (struct blk_io_trace *)trace->cur;
 	struct blk_io_trace2 *io;
 
+	if (trace->version == BLK_IO_TRACE2_VERSION) {
+		struct blk_io_trace2 *new = (struct blk_io_trace2 *)trace->cur;
+
+		io = realloc(trace->io, sizeof(*new) + new->pdu_len);
+		memcpy(io, new, sizeof(*new) + new->pdu_len);
+		trace->io = io;
+		return;
+	}
+
 	io = realloc(trace->io, sizeof(struct blk_io_trace2) + old->pdu_len);
 
 	io->magic	= old->magic;
@@ -316,10 +380,12 @@ static void trace_convert_io(struct trace *trace)
 
 int next_record(struct trace *trace)
 {
+	int hdr = (trace->version == BLK_IO_TRACE2_VERSION) ?
+		  sizeof(struct blk_io_trace2) : sizeof(struct blk_io_trace);
 	int skip = trace->io->pdu_len;
 	u64 offset;
 
-	trace->cur += sizeof(struct blk_io_trace) + skip;
+	trace->cur += hdr + skip;
 	offset = trace->cur - trace->start;
 	if (offset >= trace->len)
 		return 1;
@@ -857,6 +923,7 @@ struct trace *open_trace(char *filename)
 	trace->len = st.st_size;
 	trace->start = p;
 	trace->cur = p;
+	trace->version = detect_trace_version(trace);
 	trace_convert_io(trace);
 	return trace;
 
diff --git a/iowatcher/blkparse.h b/iowatcher/blkparse.h
index 304431e0f0d9..c59bcf7b5277 100644
--- a/iowatcher/blkparse.h
+++ b/iowatcher/blkparse.h
@@ -39,6 +39,7 @@ struct trace {
 	u64 len;
 	char *start;
 	char *cur;
+	int version;
 	struct blk_io_trace2 *io;
 	u64 start_timestamp;
 	struct timespec abs_start_time;
-- 
2.54.0