Skip to content
Permalink
Browse files
netfs: Provide /proc/fs/netfs/writebacks to display writeback slices
  • Loading branch information
dhowells committed Feb 10, 2022
1 parent e934067 commit 429e2bb6fb190f390ed23afc0d2308e877c43be5
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 0 deletions.
@@ -468,6 +468,7 @@ static int netfs_flush_dirty(struct netfs_writeback *wback,

netfs_writeback_lock(wback);
netfs_writeback_start(wback);
netfs_proc_add_writeback(wback);
trace_netfs_wback(wback);

wbc->nr_to_write -= wback->last - wback->first + 1;
@@ -57,6 +57,7 @@ int netfs_flush_conflicting_writes(struct netfs_i_context *ctx,
* main.c
*/
extern struct list_head netfs_regions;
extern struct list_head netfs_writebacks;
extern spinlock_t netfs_regions_lock;

#ifdef CONFIG_PROC_FS
@@ -72,9 +73,25 @@ static inline void netfs_proc_del_region(struct netfs_dirty_region *region)
list_del_rcu(&region->proc_link);
spin_unlock(&netfs_regions_lock);
}
static inline void netfs_proc_add_writeback(struct netfs_writeback *wback)
{
spin_lock(&netfs_regions_lock);
list_add_tail_rcu(&wback->proc_link, &netfs_writebacks);
spin_unlock(&netfs_regions_lock);
}
static inline void netfs_proc_del_writeback(struct netfs_writeback *wback)
{
if (!list_empty(&wback->proc_link)) {
spin_lock(&netfs_regions_lock);
list_del_rcu(&wback->proc_link);
spin_unlock(&netfs_regions_lock);
}
}
#else
static inline void netfs_proc_add_region(struct netfs_dirty_region *region) {}
static inline void netfs_proc_del_region(struct netfs_dirty_region *region) {}
static inline void netfs_proc_add_wback(struct netfs_writeback *wback) {}
static inline void netfs_proc_del_wback(struct netfs_writeback *wback) {}
#endif

/*
@@ -15,6 +15,7 @@

#ifdef CONFIG_PROC_FS
LIST_HEAD(netfs_regions);
LIST_HEAD(netfs_writebacks);
DEFINE_SPINLOCK(netfs_regions_lock);

/*
@@ -67,6 +68,68 @@ const struct seq_operations netfs_regions_seq_ops = {
.stop = netfs_regions_seq_stop,
.show = netfs_regions_seq_show,
};

/*
* Generate a list of writebacks in /proc/fs/netfs/writebacks
*/
static int netfs_writebacks_seq_show(struct seq_file *m, void *v)
{
struct netfs_writeback *wback;
struct netfs_dirty_region *r;
char sep = ' ';

if (v == &netfs_writebacks) {
seq_puts(m,
"WBACK REF FL ERR OPS COVERAGE REGIONS\n"
"======== === == ==== === ========= =======\n"
);
return 0;
}

wback = list_entry(v, struct netfs_writeback, proc_link);
seq_printf(m,
"%08x %3d %2lx %4d %d/%u %04lx-%04lx",
wback->debug_id,
refcount_read(&wback->usage),
wback->flags,
wback->error,
atomic_read(&wback->outstanding), wback->n_ops,
wback->first, wback->last);

read_lock(&wback->regions_lock);
list_for_each_entry(r, &wback->regions, flush_link) {
seq_printf(m, "%c%x", sep, r->debug_id);
sep = ',';
}
read_unlock(&wback->regions_lock);
seq_putc(m, '\n');
return 0;
}

static void *netfs_writebacks_seq_start(struct seq_file *m, loff_t *_pos)
__acquires(rcu)
{
rcu_read_lock();
return seq_list_start_head(&netfs_writebacks, *_pos);
}

static void *netfs_writebacks_seq_next(struct seq_file *m, void *v, loff_t *_pos)
{
return seq_list_next(v, &netfs_writebacks, _pos);
}

static void netfs_writebacks_seq_stop(struct seq_file *m, void *v)
__releases(rcu)
{
rcu_read_unlock();
}

const struct seq_operations netfs_writebacks_seq_ops = {
.start = netfs_writebacks_seq_start,
.next = netfs_writebacks_seq_next,
.stop = netfs_writebacks_seq_stop,
.show = netfs_writebacks_seq_show,
};
#endif /* CONFIG_PROC_FS */

static int __init netfs_init(void)
@@ -78,6 +141,10 @@ static int __init netfs_init(void)
&netfs_regions_seq_ops))
goto error_proc;

if (!proc_create_seq("fs/netfs/writebacks", S_IFREG | 0444, NULL,
&netfs_writebacks_seq_ops))
goto error_proc;

return 0;

error_proc:
@@ -135,6 +135,7 @@ struct netfs_writeback *netfs_alloc_writeback(struct address_space *mapping,
xa_init(&wback->buffer);
xa_init(&wback->buffer2);
INIT_WORK(&wback->work, netfs_writeback_worker);
INIT_LIST_HEAD(&wback->proc_link);
INIT_LIST_HEAD(&wback->regions);
rwlock_init(&wback->regions_lock);
refcount_set(&wback->usage, 1);
@@ -201,6 +202,7 @@ void netfs_put_writeback(struct netfs_writeback *wback,
dead = __refcount_dec_and_test(&wback->usage, &ref);
trace_netfs_ref_wback(debug_id, ref - 1, what);
if (dead) {
netfs_proc_del_writeback(wback);
if (was_async) {
wback->work.func = netfs_free_writeback;
if (!queue_work(system_unbound_wq, &wback->work))
@@ -266,6 +266,7 @@ struct netfs_writeback {
struct address_space *mapping; /* The mapping being accessed */
struct xarray buffer; /* Buffer for raw data */
struct xarray buffer2; /* Buffer for encrypted/compressed data */
struct list_head proc_link; /* Link in netfs_wreqs */
struct list_head regions; /* The contributory regions (by ->flush_link) */
struct netfs_flush_group *group; /* Flush group this write is from */
rwlock_t regions_lock; /* Lock for ->regions */
@@ -276,6 +277,8 @@ struct netfs_writeback {
unsigned long long from; /* File position of start of modified part */
unsigned long long to; /* File position of end of modified part */
short error; /* 0 or error that occurred */
unsigned char n_ops; /* Number of ops allocated */
atomic_t outstanding; /* Number of outstanding writes */
refcount_t usage;
unsigned long flags;
#define NETFS_WBACK_WRITE_TO_CACHE 0 /* Need to write to the cache */

0 comments on commit 429e2bb

Please sign in to comment.