Add nfs_analyze_dio_class and use it to create nfs_analyze_read_dio and nfs_analyze_write_dio trace events. These trace events show how the NFS client splits a given misaligned IO into a mix of misaligned head and/or tail extents and a DIO-aligned middle extent. The misaligned head and/or tail extents are issued using buffered IO and the DIO-aligned middle is issued using O_DIRECT. This combination of trace events is useful for LOCALIO DIO READs: echo 1 > /sys/kernel/tracing/events/nfs/nfs_analyze_read_dio/enable echo 1 > /sys/kernel/tracing/events/nfs/nfs_initiate_read/enable echo 1 > /sys/kernel/tracing/events/nfs/nfs_readpage_done/enable echo 1 > /sys/kernel/tracing/events/xfs/xfs_file_direct_read/enable This combination of trace events is useful for LOCALIO DIO WRITEs: echo 1 > /sys/kernel/tracing/events/nfs/nfs_analyze_write_dio/enable echo 1 > /sys/kernel/tracing/events/nfs/nfs_initiate_write/enable echo 1 > /sys/kernel/tracing/events/nfs/nfs_writeback_done/enable echo 1 > /sys/kernel/tracing/events/xfs/xfs_file_direct_write/enable Signed-off-by: Mike Snitzer <snitzer@xxxxxxxxxx> --- fs/nfs/direct.c | 10 +++++--- fs/nfs/nfstrace.h | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 3803289a94793..012f5bfa15c21 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -441,7 +441,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, * IO to a DIO-aligned middle and misaligned head and/or tail. */ static bool nfs_analyze_dio(loff_t offset, ssize_t len, - struct nfs_direct_req *dreq) + struct nfs_direct_req *dreq, int rw) { #if IS_ENABLED(CONFIG_NFS_LOCALIO) /* Hardcoded to PAGE_SIZE (since don't have LOCALIO nfsd_file's @@ -471,6 +471,10 @@ static bool nfs_analyze_dio(loff_t offset, ssize_t len, dreq->end_offset = middle_end; dreq->end_len = orig_end - middle_end; + if (rw == READ) + trace_nfs_analyze_read_dio(offset, len, dreq); + else + trace_nfs_analyze_write_dio(offset, len, dreq); return true; #else return false; @@ -524,7 +528,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, struct iov_iter *iter, goto out; dreq->inode = inode; - if (swap || !nfs_analyze_dio(iocb->ki_pos, count, dreq)) { + if (swap || !nfs_analyze_dio(iocb->ki_pos, count, dreq, READ)) { dreq->max_count = count; dreq->io_start = iocb->ki_pos; } @@ -1119,7 +1123,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter, goto out; dreq->inode = inode; - if (swap || !nfs_analyze_dio(pos, count, dreq)) { + if (swap || !nfs_analyze_dio(pos, count, dreq, WRITE)) { dreq->max_count = count; dreq->io_start = pos; } diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h index 4ec66d5e9cc6c..ec4c0f073361a 100644 --- a/fs/nfs/nfstrace.h +++ b/fs/nfs/nfstrace.h @@ -1598,6 +1598,64 @@ DEFINE_NFS_DIRECT_REQ_EVENT(nfs_direct_write_completion); DEFINE_NFS_DIRECT_REQ_EVENT(nfs_direct_write_schedule_iovec); DEFINE_NFS_DIRECT_REQ_EVENT(nfs_direct_write_reschedule_io); +DECLARE_EVENT_CLASS(nfs_analyze_dio_class, + TP_PROTO( + loff_t offset, + ssize_t count, + const struct nfs_direct_req *dreq + ), + TP_ARGS(offset, count, dreq), + TP_STRUCT__entry( + __field(dev_t, dev) + __field(u64, fileid) + __field(u32, fhandle) + __field(loff_t, offset) + __field(ssize_t, count) + __field(loff_t, start) + __field(ssize_t, start_len) + __field(loff_t, middle) + __field(ssize_t, middle_len) + __field(loff_t, end) + __field(ssize_t, end_len) + ), + TP_fast_assign( + const struct inode *inode = dreq->inode; + const struct nfs_inode *nfsi = NFS_I(inode); + const struct nfs_fh *fh = &nfsi->fh; + + __entry->dev = inode->i_sb->s_dev; + __entry->fileid = nfsi->fileid; + __entry->fhandle = nfs_fhandle_hash(fh); + __entry->offset = offset; + __entry->count = count; + __entry->start = dreq->io_start; + __entry->start_len = dreq->start_len; + __entry->middle = dreq->middle_offset; + __entry->middle_len = dreq->middle_len; + __entry->end = dreq->end_offset; + __entry->end_len = dreq->end_len; + ), + TP_printk("fileid=%02x:%02x:%llu fhandle=0x%08x " + "offset=%lld count=%zd " + "start=%llu+%lu middle=%llu+%lu end=%llu+%lu", + MAJOR(__entry->dev), MINOR(__entry->dev), + (unsigned long long)__entry->fileid, + __entry->fhandle, __entry->offset, __entry->count, + __entry->start, __entry->start_len, + __entry->middle, __entry->middle_len, + __entry->end, __entry->end_len) +) + +#define DEFINE_NFS_ANALYZE_DIO_EVENT(name) \ +DEFINE_EVENT(nfs_analyze_dio_class, nfs_analyze_##name##_dio, \ + TP_PROTO(loff_t offset, \ + ssize_t count, \ + const struct nfs_direct_req *dreq), \ + TP_ARGS(offset, count, dreq)) + +DEFINE_NFS_ANALYZE_DIO_EVENT(read); +DEFINE_NFS_ANALYZE_DIO_EVENT(write); + TRACE_EVENT(nfs_fh_to_dentry, TP_PROTO( const struct super_block *sb, -- 2.44.0