The DRC pruning path evicts entries for memory pressure and expiry, and neither emits a trace event, so there is no way to see which reason is retiring entries or how old they are when it happens. A further eviction reason needs the same visibility. Add an event class that records the cache population, the XID, the transport, and the entry's age, and define an event for each eviction reason. Reviewed-by: NeilBrown Link: https://patch.msgid.link/20260921-duplicate-reply-cache-v6-6-db5e13fd9944@kernel.org Signed-off-by: Chuck Lever --- fs/nfsd/nfscache.c | 8 ++++++-- fs/nfsd/trace.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 988b955590cc..680025334f1f 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -274,10 +274,14 @@ nfsd_prune_bucket_locked(struct nfsd_net *nn, struct nfsd_drc_bucket *b, /* The bucket LRU is ordered oldest-first. */ list_for_each_entry_safe(rp, tmp, &b->lru_head, c_lru) { - if (atomic_read(&nn->num_drc_entries) > nn->max_drc_entries) + if (atomic_read(&nn->num_drc_entries) > nn->max_drc_entries) { + trace_nfsd_drc_evict_pressure(nn, rp); goto evict; - if (time_before_eq(rp->c_timestamp, expiry)) + } + if (time_before_eq(rp->c_timestamp, expiry)) { + trace_nfsd_drc_evict_expired(nn, rp); goto evict; + } break; evict: diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index e58b753c1ebc..4a3623b3899a 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -1709,6 +1709,43 @@ TRACE_EVENT(nfsd_drc_mismatch, __entry->ingress) ); +DECLARE_EVENT_CLASS(nfsd_drc_entry_class, + TP_PROTO( + const struct nfsd_net *nn, + const struct nfsd_cacherep *rp + ), + TP_ARGS(nn, rp), + TP_STRUCT__entry( + __field(unsigned long long, boot_time) + __field(unsigned int, num_drc_entries) + __field(u32, xid) + __field(u64, xprt) + __field(unsigned long, age) + ), + TP_fast_assign( + __entry->boot_time = nn->boot_time; + __entry->num_drc_entries = atomic_read(&nn->num_drc_entries); + __entry->xid = be32_to_cpu(rp->c_key.k_xid); + __entry->xprt = rp->c_xprt; + __entry->age = time_is_after_jiffies(rp->c_timestamp) ? + 1 : jiffies - rp->c_timestamp; + ), + TP_printk("boot_time=%16llx entries=%u xid=0x%08x xprt=%llu age=%lu", + __entry->boot_time, __entry->num_drc_entries, + __entry->xid, __entry->xprt, __entry->age) +); + +#define DEFINE_NFSD_DRC_ENTRY_EVENT(name) \ +DEFINE_EVENT(nfsd_drc_entry_class, nfsd_drc_##name, \ + TP_PROTO( \ + const struct nfsd_net *nn, \ + const struct nfsd_cacherep *rp \ + ), \ + TP_ARGS(nn, rp)) + +DEFINE_NFSD_DRC_ENTRY_EVENT(evict_pressure); +DEFINE_NFSD_DRC_ENTRY_EVENT(evict_expired); + TRACE_EVENT(nfsd_cb_args, TP_PROTO( const struct nfs4_client *clp, -- 2.56.0