netfs: Add a tracepoint to log failures that would be otherwise unseen
authorDavid Howells <dhowells@redhat.com>
Tue, 6 Apr 2021 16:31:54 +0000 (17:31 +0100)
committerDavid Howells <dhowells@redhat.com>
Fri, 23 Apr 2021 09:14:32 +0000 (10:14 +0100)
Add a tracepoint to log internal failures (such as cache errors) that we
don't otherwise want to pass back to the netfs.

Signed-off-by: David Howells <dhowells@redhat.com>
Tested-by: Jeff Layton <jlayton@kernel.org>
Tested-by: Dave Wysochanski <dwysocha@redhat.com>
Tested-By: Marc Dionne <marc.dionne@auristor.com>
cc: Matthew Wilcox <willy@infradead.org>
cc: linux-mm@kvack.org
cc: linux-cachefs@redhat.com
cc: linux-afs@lists.infradead.org
cc: linux-nfs@vger.kernel.org
cc: linux-cifs@vger.kernel.org
cc: ceph-devel@vger.kernel.org
cc: v9fs-developer@lists.sourceforge.net
cc: linux-fsdevel@vger.kernel.org
Link: https://lore.kernel.org/r/161781048813.463527.1557000804674707986.stgit@warthog.procyon.org.uk/
Link: https://lore.kernel.org/r/161789082749.6155.15498680577213140870.stgit@warthog.procyon.org.uk/
fs/netfs/read_helper.c
include/trace/events/netfs.h

index cd3b61d5e1929d7b243950dbba2441102c71b679..1d3b50c5db6d97dc220e1939bfc60120c58ec157 100644 (file)
@@ -271,6 +271,8 @@ static void netfs_rreq_copy_terminated(void *priv, ssize_t transferred_or_error,
 
        if (IS_ERR_VALUE(transferred_or_error)) {
                netfs_stat(&netfs_n_rh_write_failed);
+               trace_netfs_failure(rreq, subreq, transferred_or_error,
+                                   netfs_fail_copy_to_cache);
        } else {
                netfs_stat(&netfs_n_rh_write_done);
        }
@@ -323,6 +325,7 @@ static void netfs_rreq_do_write_to_cache(struct netfs_read_request *rreq)
                ret = cres->ops->prepare_write(cres, &subreq->start, &subreq->len,
                                               rreq->i_size);
                if (ret < 0) {
+                       trace_netfs_failure(rreq, subreq, ret, netfs_fail_prepare_write);
                        trace_netfs_sreq(subreq, netfs_sreq_trace_write_skip);
                        continue;
                }
@@ -627,6 +630,8 @@ void netfs_subreq_terminated(struct netfs_read_subrequest *subreq,
 
        if (IS_ERR_VALUE(transferred_or_error)) {
                subreq->error = transferred_or_error;
+               trace_netfs_failure(rreq, subreq, transferred_or_error,
+                                   netfs_fail_read);
                goto failed;
        }
 
@@ -996,8 +1001,10 @@ int netfs_readpage(struct file *file,
        } while (test_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags));
 
        ret = rreq->error;
-       if (ret == 0 && rreq->submitted < rreq->len)
+       if (ret == 0 && rreq->submitted < rreq->len) {
+               trace_netfs_failure(rreq, NULL, ret, netfs_fail_short_readpage);
                ret = -EIO;
+       }
 out:
        netfs_put_read_request(rreq, false);
        return ret;
@@ -1069,6 +1076,7 @@ retry:
                /* Allow the netfs (eg. ceph) to flush conflicts. */
                ret = ops->check_write_begin(file, pos, len, page, _fsdata);
                if (ret < 0) {
+                       trace_netfs_failure(NULL, NULL, ret, netfs_fail_check_write_begin);
                        if (ret == -EAGAIN)
                                goto retry;
                        goto error;
@@ -1145,8 +1153,10 @@ retry:
        }
 
        ret = rreq->error;
-       if (ret == 0 && rreq->submitted < rreq->len)
+       if (ret == 0 && rreq->submitted < rreq->len) {
+               trace_netfs_failure(rreq, NULL, ret, netfs_fail_short_write_begin);
                ret = -EIO;
+       }
        netfs_put_read_request(rreq, false);
        if (ret < 0)
                goto error;
index e3ebeabd3852af92ff414a7b951c0f0b2734243c..de1c64635e42b4e9d28f820d306f9cd1158d77ab 100644 (file)
@@ -47,6 +47,15 @@ enum netfs_sreq_trace {
        netfs_sreq_trace_write_term,
 };
 
+enum netfs_failure {
+       netfs_fail_check_write_begin,
+       netfs_fail_copy_to_cache,
+       netfs_fail_read,
+       netfs_fail_short_readpage,
+       netfs_fail_short_write_begin,
+       netfs_fail_prepare_write,
+};
+
 #endif
 
 #define netfs_read_traces                                      \
@@ -81,6 +90,14 @@ enum netfs_sreq_trace {
        EM(netfs_sreq_trace_write_skip,         "SKIP ")        \
        E_(netfs_sreq_trace_write_term,         "WTERM")
 
+#define netfs_failures                                                 \
+       EM(netfs_fail_check_write_begin,        "check-write-begin")    \
+       EM(netfs_fail_copy_to_cache,            "copy-to-cache")        \
+       EM(netfs_fail_read,                     "read")                 \
+       EM(netfs_fail_short_readpage,           "short-readpage")       \
+       EM(netfs_fail_short_write_begin,        "short-write-begin")    \
+       E_(netfs_fail_prepare_write,            "prep-write")
+
 
 /*
  * Export enum symbols via userspace.
@@ -94,6 +111,7 @@ netfs_read_traces;
 netfs_rreq_traces;
 netfs_sreq_sources;
 netfs_sreq_traces;
+netfs_failures;
 
 /*
  * Now redefine the EM() and E_() macros to map the enums to the strings that
@@ -197,6 +215,46 @@ TRACE_EVENT(netfs_sreq,
                      __entry->error)
            );
 
+TRACE_EVENT(netfs_failure,
+           TP_PROTO(struct netfs_read_request *rreq,
+                    struct netfs_read_subrequest *sreq,
+                    int error, enum netfs_failure what),
+
+           TP_ARGS(rreq, sreq, error, what),
+
+           TP_STRUCT__entry(
+                   __field(unsigned int,               rreq            )
+                   __field(unsigned short,             index           )
+                   __field(short,                      error           )
+                   __field(unsigned short,             flags           )
+                   __field(enum netfs_read_source,     source          )
+                   __field(enum netfs_failure,         what            )
+                   __field(size_t,                     len             )
+                   __field(size_t,                     transferred     )
+                   __field(loff_t,                     start           )
+                            ),
+
+           TP_fast_assign(
+                   __entry->rreq       = rreq->debug_id;
+                   __entry->index      = sreq ? sreq->debug_index : 0;
+                   __entry->error      = error;
+                   __entry->flags      = sreq ? sreq->flags : 0;
+                   __entry->source     = sreq ? sreq->source : NETFS_INVALID_READ;
+                   __entry->what       = what;
+                   __entry->len        = sreq ? sreq->len : 0;
+                   __entry->transferred = sreq ? sreq->transferred : 0;
+                   __entry->start      = sreq ? sreq->start : 0;
+                          ),
+
+           TP_printk("R=%08x[%u] %s f=%02x s=%llx %zx/%zx %s e=%d",
+                     __entry->rreq, __entry->index,
+                     __print_symbolic(__entry->source, netfs_sreq_sources),
+                     __entry->flags,
+                     __entry->start, __entry->transferred, __entry->len,
+                     __print_symbolic(__entry->what, netfs_failures),
+                     __entry->error)
+           );
+
 #endif /* _TRACE_NETFS_H */
 
 /* This part must be outside protection */