mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Jeff Layton <jlayton@kernel.org>
To: Chuck Lever <cel@kernel.org>, NeilBrown <neil@brown.name>,
	 Olga Kornievskaia <okorniev@redhat.com>,
	Dai Ngo <Dai.Ngo@oracle.com>,  Tom Talpey <tom@talpey.com>,
	Trond Myklebust <trondmy@kernel.org>,
	 Anna Schumaker <anna@kernel.org>,
	Jonathan Corbet <corbet@lwn.net>,
	 Shuah Khan <skhan@linuxfoundation.org>,
	 Randy Dunlap <rdunlap@infradead.org>,
	Mike Snitzer <snitzer@kernel.org>,
	 Donald Hunter <donald.hunter@gmail.com>,
	Jakub Kicinski <kuba@kernel.org>,
	 "David S. Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@kernel.org>,
	 Paolo Abeni <pabeni@redhat.com>, Simon Horman <horms@kernel.org>
Cc: Steve Dickson <steved@redhat.com>,
	netdev@vger.kernel.org,  linux-kernel@vger.kernel.org,
	linux-nfs@vger.kernel.org,  linux-doc@vger.kernel.org,
	Jeff Layton <jlayton@kernel.org>
Subject: [PATCH 5/6] NFSD: Count the storage reads of each export's READs
Date: Tue, 27 Oct 2026 12:45:28 -0400	[thread overview]
Message-ID: <20261027-export-iomode-v1-5-262ed932a036@kernel.org> (raw)
In-Reply-To: <20261027-export-iomode-v1-0-262ed932a036@kernel.org>

The page cache miss ratio of an export is the best indicator of the IO
mode that suits it, but NFSD reports only the bytes that READ returned.
Comparing that with the reads of the block device is approximate: the
device can hold other exports or local data, the count includes every
user of the device, and btrfs can span devices.

submit_bio() charges read bytes to the submitting task. Take a snapshot
of current->ioac.read_bytes when a READ starts, and add the difference
to a new io_read_storage counter of the export when it finishes. This
includes the readahead that the READ started and the metadata that it
needed, and works the same for buffered, dontcache, direct and splice
reads. export_stats shows the counter only with
CONFIG_TASK_IO_ACCOUNTING, so a missing counter means it is not
available.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 fs/nfsd/export.c |  4 ++++
 fs/nfsd/export.h |  1 +
 fs/nfsd/stats.h  | 33 +++++++++++++++++++++++++++++++++
 fs/nfsd/vfs.c    | 20 ++++++++++++++------
 4 files changed, 52 insertions(+), 6 deletions(-)

diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 640973d02b6c..ac2d71a9c562 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1675,6 +1675,10 @@ static int svc_export_show(struct seq_file *m,
 			   export_stats_sum(stats, EXP_STATS_IO_READ));
 		seq_printf(m, "\tio_write: %lld\n",
 			   export_stats_sum(stats, EXP_STATS_IO_WRITE));
+		if (IS_ENABLED(CONFIG_TASK_IO_ACCOUNTING))
+			seq_printf(m, "\tio_read_storage: %lld\n",
+				   export_stats_sum(stats,
+						    EXP_STATS_IO_READ_STORAGE));
 		seq_putc(m, '\n');
 		return 0;
 	}
diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h
index 70842782629f..8ecd43894bec 100644
--- a/fs/nfsd/export.h
+++ b/fs/nfsd/export.h
@@ -53,6 +53,7 @@ enum {
 	EXP_STATS_FH_STALE,
 	EXP_STATS_IO_READ,
 	EXP_STATS_IO_WRITE,
+	EXP_STATS_IO_READ_STORAGE,
 	EXP_STATS_COUNTERS_NUM
 };
 
diff --git a/fs/nfsd/stats.h b/fs/nfsd/stats.h
index aabfbb1a9c71..d88d2229a4c7 100644
--- a/fs/nfsd/stats.h
+++ b/fs/nfsd/stats.h
@@ -9,6 +9,7 @@
 
 #include <uapi/linux/nfsd/stats.h>
 #include <linux/percpu_counter.h>
+#include <linux/sched.h>
 
 #include "export.h"
 #include "netns.h"
@@ -97,6 +98,38 @@ static inline void nfsd_stats_io_write_add(struct nfsd_net *nn,
 					 amount);
 }
 
+/**
+ * nfsd_storage_read_bytes - bytes the current task has read from storage
+ *
+ * submit_bio() charges read bytes to the submitting task, so the change
+ * across a READ is what that READ, including the readahead it starts,
+ * read from storage instead of the page cache.
+ *
+ * Return: the task's storage read byte count, or zero without
+ * CONFIG_TASK_IO_ACCOUNTING.
+ */
+static inline u64 nfsd_storage_read_bytes(void)
+{
+#ifdef CONFIG_TASK_IO_ACCOUNTING
+	return current->ioac.read_bytes;
+#else
+	return 0;
+#endif
+}
+
+/**
+ * nfsd_stats_io_read_storage_add - Count storage bytes read for an NFS READ
+ * @exp: target export
+ * @amount: byte count
+ */
+static inline void nfsd_stats_io_read_storage_add(struct svc_export *exp,
+						  s64 amount)
+{
+	if (exp && exp->ex_stats && amount > 0)
+		percpu_counter_add_local(&exp->ex_stats->counter[EXP_STATS_IO_READ_STORAGE],
+					 amount);
+}
+
 static inline void nfsd_stats_payload_misses_inc(struct nfsd_net *nn)
 {
 	percpu_counter_inc(&nn->counter[NFSD_STATS_PAYLOAD_MISSES]);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 15613b6df290..50ef96292003 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1113,8 +1113,11 @@ static u32 nfsd_eof_on_read(struct file *file, loff_t offset, ssize_t len,
 
 static __be32 nfsd_finish_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
 			       struct file *file, loff_t offset,
-			       unsigned long *count, u32 *eof, ssize_t host_err)
+			       unsigned long *count, u32 *eof, ssize_t host_err,
+			       u64 storage_start)
 {
+	nfsd_stats_io_read_storage_add(fhp->fh_export,
+				       nfsd_storage_read_bytes() - storage_start);
 	if (host_err >= 0) {
 		struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
@@ -1145,12 +1148,14 @@ __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
 			struct file *file, loff_t offset, unsigned long *count,
 			u32 *eof)
 {
+	u64 storage_start = nfsd_storage_read_bytes();
 	ssize_t host_err;
 
 	trace_nfsd_read_splice(rqstp, fhp, offset, *count);
 	host_err = vfs_splice_to_actor(file, offset, *count,
 				       nfsd_direct_splice_actor, rqstp);
-	return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err);
+	return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err,
+				storage_start);
 }
 
 /*
@@ -1168,7 +1173,7 @@ __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
 static noinline_for_stack __be32
 nfsd_direct_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		 struct nfsd_file *nf, loff_t offset, unsigned long *count,
-		 struct page **page, u32 *eof)
+		 struct page **page, u32 *eof, u64 storage_start)
 {
 	u64 dio_start, dio_end;
 	unsigned long v, total;
@@ -1226,7 +1231,7 @@ nfsd_direct_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
 	}
 
 	return nfsd_finish_read(rqstp, fhp, nf->nf_file, offset, count,
-				eof, host_err);
+				eof, host_err, storage_start);
 }
 
 static bool nfsd_direct_read_ok(struct svc_rqst *rqstp, struct svc_fh *fhp,
@@ -1324,6 +1329,7 @@ __be32 nfsd_iter_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
 	struct page **page = buf->pages + (buf->page_len >> PAGE_SHIFT);
 	unsigned int base = buf->page_len & ~PAGE_MASK;
 	struct file *file = nf->nf_file;
+	u64 storage_start = nfsd_storage_read_bytes();
 	unsigned long v, total;
 	struct iov_iter iter;
 	struct kiocb kiocb;
@@ -1338,7 +1344,8 @@ __be32 nfsd_iter_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
 	case NFSD_IO_DIRECT:
 		if (nfsd_direct_read_ok(rqstp, fhp, nf, offset, *count))
 			return nfsd_direct_read(rqstp, fhp, nf, offset,
-						count, page, eof);
+						count, page, eof,
+						storage_start);
 		fallthrough;
 	case NFSD_IO_DONTCACHE:
 		if (file->f_op->fop_flags & FOP_DONTCACHE)
@@ -1367,7 +1374,8 @@ __be32 nfsd_iter_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
 				  kiocb.ki_flags);
 	iov_iter_bvec(&iter, ITER_DEST, rqstp->rq_bvec, v, *count - total);
 	host_err = vfs_iocb_iter_read(file, &kiocb, &iter);
-	return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err);
+	return nfsd_finish_read(rqstp, fhp, file, offset, count, eof, host_err,
+				storage_start);
 }
 
 /*

-- 
2.56.0


  parent reply	other threads:[~2026-10-27 16:45 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-27 16:45 [PATCH 0/6] nfsd: add new export options for controlling read/write iomode Jeff Layton
2026-10-27 16:45 ` [PATCH 1/6] NFSD: Add per-export read/write I/O mode settings Jeff Layton
2026-10-27 16:45 ` [PATCH 2/6] NFSD: Apply per-export I/O modes to READ and WRITE Jeff Layton
2026-10-27 17:54   ` Chuck Lever
2026-10-27 17:59     ` Jeff Layton
2026-10-27 19:42       ` Chuck Lever
2026-10-27 16:45 ` [PATCH 3/6] NFSD: Document per-export riomode= and wiomode= options Jeff Layton
2026-10-27 16:45 ` [PATCH 4/6] NFSD: Keep per-export statistics across export cache updates Jeff Layton
2026-10-27 16:45 ` Jeff Layton [this message]
2026-10-27 16:45 ` [PATCH 6/6] NFSD: Document how to choose an IO mode Jeff Layton

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261027-export-iomode-v1-5-262ed932a036@kernel.org \
    --to=jlayton@kernel.org \
    --cc=Dai.Ngo@oracle.com \
    --cc=anna@kernel.org \
    --cc=cel@kernel.org \
    --cc=corbet@lwn.net \
    --cc=davem@davemloft.net \
    --cc=donald.hunter@gmail.com \
    --cc=edumazet@kernel.org \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=neil@brown.name \
    --cc=netdev@vger.kernel.org \
    --cc=okorniev@redhat.com \
    --cc=pabeni@redhat.com \
    --cc=rdunlap@infradead.org \
    --cc=skhan@linuxfoundation.org \
    --cc=snitzer@kernel.org \
    --cc=steved@redhat.com \
    --cc=tom@talpey.com \
    --cc=trondmy@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®