Commit 62dfe539 authored by Alexander Viro's avatar Alexander Viro Committed by David S. Miller

[PATCH] /proc/slabinfo cleanup (seq_...)

	Straightforward rewrite to seq_file.
parent aa45600e
...@@ -223,6 +223,20 @@ static struct file_operations proc_ksyms_operations = { ...@@ -223,6 +223,20 @@ static struct file_operations proc_ksyms_operations = {
}; };
#endif #endif
extern struct seq_operations slabinfo_op;
extern ssize_t slabinfo_write(struct file *, const char *, size_t, loff_t *);
static int slabinfo_open(struct inode *inode, struct file *file)
{
return seq_open(file, &slabinfo_op);
}
static struct file_operations proc_slabinfo_operations = {
open: slabinfo_open,
read: seq_read,
write: slabinfo_write,
llseek: seq_lseek,
release: seq_release,
};
static int kstat_read_proc(char *page, char **start, off_t off, static int kstat_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data) int count, int *eof, void *data)
{ {
...@@ -551,6 +565,7 @@ void __init proc_misc_init(void) ...@@ -551,6 +565,7 @@ void __init proc_misc_init(void)
entry->proc_fops = &proc_kmsg_operations; entry->proc_fops = &proc_kmsg_operations;
create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
create_seq_entry("interrupts", 0, &proc_interrupts_operations); create_seq_entry("interrupts", 0, &proc_interrupts_operations);
create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
create_seq_entry("ksyms", 0, &proc_ksyms_operations); create_seq_entry("ksyms", 0, &proc_ksyms_operations);
#endif #endif
...@@ -575,8 +590,4 @@ void __init proc_misc_init(void) ...@@ -575,8 +590,4 @@ void __init proc_misc_init(void)
entry->proc_fops = &ppc_htab_operations; entry->proc_fops = &ppc_htab_operations;
} }
#endif #endif
entry = create_proc_read_entry("slabinfo", S_IWUSR | S_IRUGO, NULL,
slabinfo_read_proc, NULL);
if (entry)
entry->write_proc = slabinfo_write_proc;
} }
...@@ -62,11 +62,6 @@ extern void *kmalloc(size_t, int); ...@@ -62,11 +62,6 @@ extern void *kmalloc(size_t, int);
extern void kfree(const void *); extern void kfree(const void *);
extern int FASTCALL(kmem_cache_reap(int)); extern int FASTCALL(kmem_cache_reap(int));
extern int slabinfo_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data);
struct file;
extern int slabinfo_write_proc(struct file *file, const char *buffer,
unsigned long count, void *data);
/* System wide caches */ /* System wide caches */
extern kmem_cache_t *vm_area_cachep; extern kmem_cache_t *vm_area_cachep;
......
...@@ -75,6 +75,7 @@ ...@@ -75,6 +75,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
/* /*
...@@ -1869,31 +1870,56 @@ int kmem_cache_reap (int gfp_mask) ...@@ -1869,31 +1870,56 @@ int kmem_cache_reap (int gfp_mask)
} }
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
/* /proc/slabinfo
* cache-name num-active-objs total-objs
* obj-size num-active-slabs total-slabs
* num-pages-per-slab
*/
#define FIXUP(t) \
do { \
if (len <= off) { \
off -= len; \
len = 0; \
} else { \
if (len-off > count) \
goto t; \
} \
} while (0)
static int proc_getdata (char*page, char**start, off_t off, int count) static void *s_start(struct seq_file *m, loff_t *pos)
{ {
loff_t n = *pos;
struct list_head *p; struct list_head *p;
int len = 0;
/* Output format version, so at least we can change it without _too_ down(&cache_chain_sem);
* many complaints. if (!n)
*/ return (void *)1;
len += sprintf(page+len, "slabinfo - version: 1.1" p = &cache_cache.next;
while (--n) {
p = p->next;
if (p == &cache_cache.next)
return NULL;
}
return list_entry(p, kmem_cache_t, next);
}
static void *s_next(struct seq_file *m, void *p, loff_t *pos)
{
kmem_cache_t *cachep = p;
++*pos;
if (p == (void *)1)
return &cache_cache;
cachep = list_entry(cachep->next.next, kmem_cache_t, next);
return cachep == &cache_cache ? NULL : cachep;
}
static void s_stop(struct seq_file *m, void *p)
{
up(&cache_chain_sem);
}
static int s_show(struct seq_file *m, void *p)
{
kmem_cache_t *cachep = p;
struct list_head *q;
slab_t *slabp;
unsigned long active_objs;
unsigned long num_objs;
unsigned long active_slabs = 0;
unsigned long num_slabs;
const char *name;
if (p == (void*)1) {
/*
* Output format version, so at least we can change it
* without _too_ many complaints.
*/
seq_puts(m, "slabinfo - version: 1.1"
#if STATS #if STATS
" (statistics)" " (statistics)"
#endif #endif
...@@ -1901,116 +1927,89 @@ static int proc_getdata (char*page, char**start, off_t off, int count) ...@@ -1901,116 +1927,89 @@ static int proc_getdata (char*page, char**start, off_t off, int count)
" (SMP)" " (SMP)"
#endif #endif
"\n"); "\n");
FIXUP(got_data); return 0;
}
down(&cache_chain_sem);
p = &cache_cache.next;
do {
kmem_cache_t *cachep;
struct list_head *q;
slab_t *slabp;
unsigned long active_objs;
unsigned long num_objs;
unsigned long active_slabs = 0;
unsigned long num_slabs;
const char *name;
cachep = list_entry(p, kmem_cache_t, next);
spin_lock_irq(&cachep->spinlock); spin_lock_irq(&cachep->spinlock);
active_objs = 0; active_objs = 0;
num_slabs = 0; num_slabs = 0;
list_for_each(q,&cachep->slabs_full) { list_for_each(q,&cachep->slabs_full) {
slabp = list_entry(q, slab_t, list); slabp = list_entry(q, slab_t, list);
if (slabp->inuse != cachep->num) if (slabp->inuse != cachep->num)
BUG(); BUG();
active_objs += cachep->num; active_objs += cachep->num;
active_slabs++; active_slabs++;
} }
list_for_each(q,&cachep->slabs_partial) { list_for_each(q,&cachep->slabs_partial) {
slabp = list_entry(q, slab_t, list); slabp = list_entry(q, slab_t, list);
if (slabp->inuse == cachep->num || !slabp->inuse) if (slabp->inuse == cachep->num || !slabp->inuse)
BUG(); BUG();
active_objs += slabp->inuse; active_objs += slabp->inuse;
active_slabs++; active_slabs++;
} }
list_for_each(q,&cachep->slabs_free) { list_for_each(q,&cachep->slabs_free) {
slabp = list_entry(q, slab_t, list); slabp = list_entry(q, slab_t, list);
if (slabp->inuse) if (slabp->inuse)
BUG(); BUG();
num_slabs++; num_slabs++;
} }
num_slabs+=active_slabs; num_slabs+=active_slabs;
num_objs = num_slabs*cachep->num; num_objs = num_slabs*cachep->num;
name = cachep->name; name = cachep->name;
{ {
char tmp; char tmp;
if (__get_user(tmp, name)) if (__get_user(tmp, name))
name = "broken"; name = "broken";
} }
len += sprintf(page+len, "%-17s %6lu %6lu %6u %4lu %4lu %4u", seq_printf(m, "%-17s %6lu %6lu %6u %4lu %4lu %4u",
name, active_objs, num_objs, cachep->objsize, name, active_objs, num_objs, cachep->objsize,
active_slabs, num_slabs, (1<<cachep->gfporder)); active_slabs, num_slabs, (1<<cachep->gfporder));
#if STATS #if STATS
{ {
unsigned long errors = cachep->errors; unsigned long errors = cachep->errors;
unsigned long high = cachep->high_mark; unsigned long high = cachep->high_mark;
unsigned long grown = cachep->grown; unsigned long grown = cachep->grown;
unsigned long reaped = cachep->reaped; unsigned long reaped = cachep->reaped;
unsigned long allocs = cachep->num_allocations; unsigned long allocs = cachep->num_allocations;
len += sprintf(page+len, " : %6lu %7lu %5lu %4lu %4lu", seq_printf(m, " : %6lu %7lu %5lu %4lu %4lu",
high, allocs, grown, reaped, errors); high, allocs, grown, reaped, errors);
} }
#endif #endif
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
{ {
unsigned int batchcount = cachep->batchcount; unsigned int batchcount = cachep->batchcount;
unsigned int limit; unsigned int limit;
if (cc_data(cachep)) if (cc_data(cachep))
limit = cc_data(cachep)->limit; limit = cc_data(cachep)->limit;
else else
limit = 0; limit = 0;
len += sprintf(page+len, " : %4u %4u", seq_printf(m, " : %4u %4u", limit, batchcount);
limit, batchcount); }
}
#endif #endif
#if STATS && defined(CONFIG_SMP) #if STATS && defined(CONFIG_SMP)
{ {
unsigned long allochit = atomic_read(&cachep->allochit); unsigned long allochit = atomic_read(&cachep->allochit);
unsigned long allocmiss = atomic_read(&cachep->allocmiss); unsigned long allocmiss = atomic_read(&cachep->allocmiss);
unsigned long freehit = atomic_read(&cachep->freehit); unsigned long freehit = atomic_read(&cachep->freehit);
unsigned long freemiss = atomic_read(&cachep->freemiss); unsigned long freemiss = atomic_read(&cachep->freemiss);
len += sprintf(page+len, " : %6lu %6lu %6lu %6lu", seq_printf(m, " : %6lu %6lu %6lu %6lu",
allochit, allocmiss, freehit, freemiss); allochit, allocmiss, freehit, freemiss);
} }
#endif #endif
len += sprintf(page+len,"\n"); spin_unlock_irq(&cachep->spinlock);
spin_unlock_irq(&cachep->spinlock); seq_putc(m, '\n');
FIXUP(got_data_up); return 0;
p = cachep->next.next;
} while (p != &cache_cache.next);
got_data_up:
up(&cache_chain_sem);
got_data:
*start = page+off;
return len;
} }
/** /**
* slabinfo_read_proc - generates /proc/slabinfo * slabinfo_op - iterator that generates /proc/slabinfo
* @page: scratch area, one page long
* @start: pointer to the pointer to the output buffer
* @off: offset within /proc/slabinfo the caller is interested in
* @count: requested len in bytes
* @eof: eof marker
* @data: unused
* *
* The contents of the buffer are * Output layout:
* cache-name * cache-name
* num-active-objs * num-active-objs
* total-objs * total-objs
...@@ -2020,28 +2019,24 @@ static int proc_getdata (char*page, char**start, off_t off, int count) ...@@ -2020,28 +2019,24 @@ static int proc_getdata (char*page, char**start, off_t off, int count)
* num-pages-per-slab * num-pages-per-slab
* + further values on SMP and with statistics enabled * + further values on SMP and with statistics enabled
*/ */
int slabinfo_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data) struct seq_operations slabinfo_op = {
{ start: s_start,
int len = proc_getdata(page, start, off, count); next: s_next,
len -= (*start-page); stop: s_stop,
if (len <= count) show: s_show
*eof = 1; };
if (len>count) len = count;
if (len<0) len = 0;
return len;
}
#define MAX_SLABINFO_WRITE 128 #define MAX_SLABINFO_WRITE 128
/** /**
* slabinfo_write_proc - SMP tuning for the slab allocator * slabinfo_write - SMP tuning for the slab allocator
* @file: unused * @file: unused
* @buffer: user buffer * @buffer: user buffer
* @count: data len * @count: data len
* @data: unused * @data: unused
*/ */
int slabinfo_write_proc (struct file *file, const char *buffer, ssize_t slabinfo_write(struct file *file, const char *buffer,
unsigned long count, void *data) size_t count, loff_t *ppos)
{ {
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
char kbuf[MAX_SLABINFO_WRITE+1], *tmp; char kbuf[MAX_SLABINFO_WRITE+1], *tmp;
......
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