Re: [RFC PATCH 01/53] netfs: Add a procfile to list in-progress requests
From: Jeff Layton
Date: Mon Oct 16 2023 - 10:44:32 EST
On Fri, 2023-10-13 at 16:56 +0100, David Howells wrote:
> Add a procfile, /proc/fs/netfs/requests, to list in-progress netfslib I/O
> requests.
>
> Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
> cc: Jeff Layton <jlayton@xxxxxxxxxx>
> cc: linux-cachefs@xxxxxxxxxx
> cc: linux-fsdevel@xxxxxxxxxxxxxxx
> cc: linux-mm@xxxxxxxxx
> ---
> fs/netfs/internal.h | 22 +++++++++++
> fs/netfs/main.c | 91 +++++++++++++++++++++++++++++++++++++++++++
> fs/netfs/objects.c | 4 +-
> include/linux/netfs.h | 6 ++-
> 4 files changed, 121 insertions(+), 2 deletions(-)
>
> diff --git a/fs/netfs/internal.h b/fs/netfs/internal.h
> index 43fac1b14e40..1f067aa96c50 100644
> --- a/fs/netfs/internal.h
> +++ b/fs/netfs/internal.h
> @@ -29,6 +29,28 @@ int netfs_begin_read(struct netfs_io_request *rreq, bool sync);
> * main.c
> */
> extern unsigned int netfs_debug;
> +extern struct list_head netfs_io_requests;
> +extern spinlock_t netfs_proc_lock;
> +
> +#ifdef CONFIG_PROC_FS
> +static inline void netfs_proc_add_rreq(struct netfs_io_request *rreq)
> +{
> + spin_lock(&netfs_proc_lock);
> + list_add_tail_rcu(&rreq->proc_link, &netfs_io_requests);
> + spin_unlock(&netfs_proc_lock);
> +}
> +static inline void netfs_proc_del_rreq(struct netfs_io_request *rreq)
> +{
> + if (!list_empty(&rreq->proc_link)) {
> + spin_lock(&netfs_proc_lock);
> + list_del_rcu(&rreq->proc_link);
> + spin_unlock(&netfs_proc_lock);
> + }
> +}
> +#else
> +static inline void netfs_proc_add_rreq(struct netfs_io_request *rreq) {}
> +static inline void netfs_proc_del_rreq(struct netfs_io_request *rreq) {}
> +#endif
>
> /*
> * objects.c
> diff --git a/fs/netfs/main.c b/fs/netfs/main.c
> index 068568702957..21f814eee6af 100644
> --- a/fs/netfs/main.c
> +++ b/fs/netfs/main.c
> @@ -7,6 +7,8 @@
>
> #include <linux/module.h>
> #include <linux/export.h>
> +#include <linux/proc_fs.h>
> +#include <linux/seq_file.h>
> #include "internal.h"
> #define CREATE_TRACE_POINTS
> #include <trace/events/netfs.h>
> @@ -18,3 +20,92 @@ MODULE_LICENSE("GPL");
> unsigned netfs_debug;
> module_param_named(debug, netfs_debug, uint, S_IWUSR | S_IRUGO);
> MODULE_PARM_DESC(netfs_debug, "Netfs support debugging mask");
> +
> +#ifdef CONFIG_PROC_FS
> +LIST_HEAD(netfs_io_requests);
> +DEFINE_SPINLOCK(netfs_proc_lock);
> +
> +static const char *netfs_origins[] = {
> + [NETFS_READAHEAD] = "RA",
> + [NETFS_READPAGE] = "RP",
> + [NETFS_READ_FOR_WRITE] = "RW",
> +};
> +
> +/*
> + * Generate a list of I/O requests in /proc/fs/netfs/requests
> + */
> +static int netfs_requests_seq_show(struct seq_file *m, void *v)
> +{
> + struct netfs_io_request *rreq;
> +
> + if (v == &netfs_io_requests) {
> + seq_puts(m,
> + "REQUEST OR REF FL ERR OPS COVERAGE\n"
> + "======== == === == ==== === =========\n"
> + );
> + return 0;
> + }
> +
> + rreq = list_entry(v, struct netfs_io_request, proc_link);
> + seq_printf(m,
> + "%08x %s %3d %2lx %4d %3d @%04llx %zx/%zx",
> + rreq->debug_id,
> + netfs_origins[rreq->origin],
> + refcount_read(&rreq->ref),
> + rreq->flags,
> + rreq->error,
> + atomic_read(&rreq->nr_outstanding),
> + rreq->start, rreq->submitted, rreq->len);
> + seq_putc(m, '\n');
> + return 0;
> +}
> +
> +static void *netfs_requests_seq_start(struct seq_file *m, loff_t *_pos)
> + __acquires(rcu)
> +{
> + rcu_read_lock();
> + return seq_list_start_head(&netfs_io_requests, *_pos);
> +}
> +
> +static void *netfs_requests_seq_next(struct seq_file *m, void *v, loff_t *_pos)
> +{
> + return seq_list_next(v, &netfs_io_requests, _pos);
> +}
> +
> +static void netfs_requests_seq_stop(struct seq_file *m, void *v)
> + __releases(rcu)
> +{
> + rcu_read_unlock();
> +}
> +
> +static const struct seq_operations netfs_requests_seq_ops = {
> + .start = netfs_requests_seq_start,
> + .next = netfs_requests_seq_next,
> + .stop = netfs_requests_seq_stop,
> + .show = netfs_requests_seq_show,
> +};
> +#endif /* CONFIG_PROC_FS */
> +
> +static int __init netfs_init(void)
> +{
> + if (!proc_mkdir("fs/netfs", NULL))
> + goto error;
> +
It seems like this should go under debugfs instead.
> + if (!proc_create_seq("fs/netfs/requests", S_IFREG | 0444, NULL,
> + &netfs_requests_seq_ops))
> + goto error_proc;
> +
> + return 0;
> +
> +error_proc:
> + remove_proc_entry("fs/netfs", NULL);
> +error:
> + return -ENOMEM;
> +}
> +fs_initcall(netfs_init);
> +
> +static void __exit netfs_exit(void)
> +{
> + remove_proc_entry("fs/netfs", NULL);
> +}
> +module_exit(netfs_exit);
> diff --git a/fs/netfs/objects.c b/fs/netfs/objects.c
> index e17cdf53f6a7..85f428fc52e6 100644
> --- a/fs/netfs/objects.c
> +++ b/fs/netfs/objects.c
> @@ -45,6 +45,7 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
> }
> }
>
> + netfs_proc_add_rreq(rreq);
> netfs_stat(&netfs_n_rh_rreq);
> return rreq;
> }
> @@ -76,12 +77,13 @@ static void netfs_free_request(struct work_struct *work)
> container_of(work, struct netfs_io_request, work);
>
> trace_netfs_rreq(rreq, netfs_rreq_trace_free);
> + netfs_proc_del_rreq(rreq);
> netfs_clear_subrequests(rreq, false);
> if (rreq->netfs_ops->free_request)
> rreq->netfs_ops->free_request(rreq);
> if (rreq->cache_resources.ops)
> rreq->cache_resources.ops->end_operation(&rreq->cache_resources);
> - kfree(rreq);
> + kfree_rcu(rreq, rcu);
> netfs_stat_d(&netfs_n_rh_rreq);
> }
>
> diff --git a/include/linux/netfs.h b/include/linux/netfs.h
> index b11a84f6c32b..b447cb67f599 100644
> --- a/include/linux/netfs.h
> +++ b/include/linux/netfs.h
> @@ -175,10 +175,14 @@ enum netfs_io_origin {
> * operations to a variety of data stores and then stitch the result together.
> */
> struct netfs_io_request {
> - struct work_struct work;
> + union {
> + struct work_struct work;
> + struct rcu_head rcu;
> + };
> struct inode *inode; /* The file being accessed */
> struct address_space *mapping; /* The mapping being accessed */
> struct netfs_cache_resources cache_resources;
> + struct list_head proc_link; /* Link in netfs_iorequests */
> struct list_head subrequests; /* Contributory I/O operations */
> void *netfs_priv; /* Private data for the netfs */
> unsigned int debug_id;
>
ACK on the general concept however. This is useful debugging info.
--
Jeff Layton <jlayton@xxxxxxxxxx>