Commit e3e1aa90 authored by David Howells's avatar David Howells

rxrpc: Do procfs lists through objcache

Use the object cache primary hash to provide lists of RxRPC objects through
/proc/net/ for all caches where desired.  Each user of the cache just needs
to provide a show function in its objcache struct and register the proc
file with objcache_seq_fops as its file operations.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent 7c02dc94
......@@ -11,6 +11,8 @@
#include <linux/sched.h>
#include <linux/hash.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include "ar-internal.h"
#include "objcache.h"
......@@ -475,3 +477,105 @@ void objcache_clear(struct objcache *cache)
_leave("");
}
/*
* Generate a list of cached objects in /proc/net/x
*/
static void *objcache_seq_start(struct seq_file *seq, loff_t *_pos)
__acquires(rcu)
{
struct objcache *cache = seq->private;
struct hlist_head *hash;
loff_t pos_l = *_pos;
unsigned pos = pos_l, bucket;
void *ret;
if (*_pos > UINT_MAX)
return NULL;
bucket = pos >> 16;
pos &= 0xffff;
rcu_read_lock();
do {
hash = &cache->hash_table[bucket];
if (bucket == 0)
ret = seq_hlist_start_head(hash, pos);
else
ret = seq_hlist_start(hash, pos);
} while (!ret && (bucket++,
*_pos = bucket << 16,
bucket < cache->nr_buckets));
return ret;
}
static void *objcache_seq_next(struct seq_file *seq, void *v, loff_t *_pos)
{
struct objcache *cache = seq->private;
struct hlist_head *hash;
unsigned bucket;
void *ret;
if (*_pos > UINT_MAX)
return NULL;
bucket = *_pos >> 16;
hash = &cache->hash_table[bucket];
ret = seq_hlist_next(v, hash, _pos);
if (ret)
return ret;
while (bucket++,
*_pos = bucket << 16,
bucket < cache->nr_buckets
) {
hash = &cache->hash_table[bucket];
ret = seq_hlist_start(hash, 0);
if (ret)
break;
}
return ret;
}
static void objcache_seq_stop(struct seq_file *seq, void *v)
__releases(rcu)
{
rcu_read_unlock();
}
static int objcache_seq_show(struct seq_file *seq, void *v)
{
struct objcache *cache = seq->private;
struct obj_node *obj = v;
return cache->seq_show(seq, obj);
}
static const struct seq_operations objcache_seq_ops = {
.start = objcache_seq_start,
.next = objcache_seq_next,
.stop = objcache_seq_stop,
.show = objcache_seq_show,
};
static int objcache_seq_open(struct inode *inode, struct file *file)
{
struct objcache *cache = PDE_DATA(inode);
struct seq_file *seq;
int ret;
ret = seq_open(file, &objcache_seq_ops);
if (ret == 0) {
seq = file->private_data;
seq->private = cache;
}
return ret;
}
const struct file_operations objcache_seq_fops = {
.owner = THIS_MODULE,
.open = objcache_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
......@@ -52,6 +52,11 @@ struct objcache {
unsigned long (*hash_key_2)(const void *);
int (*cmp_key_2)(const struct obj_node *, const void *);
/* If the cache should be visible through /proc, the following
* should be implemented.
*/
int (*seq_show)(struct seq_file *, void *);
/* Internal data */
spinlock_t lock;
atomic_t count;
......@@ -64,6 +69,7 @@ struct objcache {
time64_t gc_next_run;
unsigned gc_bucket;
unsigned gc_last_bucket;
struct seq_operations seq_ops;
};
static inline bool objcache_get_maybe(struct obj_node *obj)
......@@ -86,4 +92,6 @@ extern void objcache_put(struct objcache *, struct obj_node *);
extern void objcache_obj_rcu_done(struct objcache *);
extern void objcache_clear(struct objcache *);
extern const struct file_operations objcache_seq_fops;
#endif /* _OBJCACHE_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment