aboutsummaryrefslogtreecommitdiffstats
path: root/mm/slab.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2006-03-25 06:06:39 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-25 11:22:49 -0500
commit871751e25d956ad24f129ca972b7851feaa61d53 (patch)
treec3213a17481f601339ce0c81a22eebca0946c2c7 /mm/slab.c
parentf52ac8fec8a13e207f675b0c16e0d5f800c1c204 (diff)
[PATCH] slab: implement /proc/slab_allocators
Implement /proc/slab_allocators. It produces output like: idr_layer_cache: 80 idr_pre_get+0x33/0x4e buffer_head: 2555 alloc_buffer_head+0x20/0x75 mm_struct: 9 mm_alloc+0x1e/0x42 mm_struct: 20 dup_mm+0x36/0x370 vm_area_struct: 384 dup_mm+0x18f/0x370 vm_area_struct: 151 do_mmap_pgoff+0x2e0/0x7c3 vm_area_struct: 1 split_vma+0x5a/0x10e vm_area_struct: 11 do_brk+0x206/0x2e2 vm_area_struct: 2 copy_vma+0xda/0x142 vm_area_struct: 9 setup_arg_pages+0x99/0x214 fs_cache: 8 copy_fs_struct+0x21/0x133 fs_cache: 29 copy_process+0xf38/0x10e3 files_cache: 30 alloc_files+0x1b/0xcf signal_cache: 81 copy_process+0xbaa/0x10e3 sighand_cache: 77 copy_process+0xe65/0x10e3 sighand_cache: 1 de_thread+0x4d/0x5f8 anon_vma: 241 anon_vma_prepare+0xd9/0xf3 size-2048: 1 add_sect_attrs+0x5f/0x145 size-2048: 2 journal_init_revoke+0x99/0x302 size-2048: 2 journal_init_revoke+0x137/0x302 size-2048: 2 journal_init_inode+0xf9/0x1c4 Cc: Manfred Spraul <manfred@colorfullife.com> Cc: Alexander Nyberg <alexn@telia.com> Cc: Pekka Enberg <penberg@cs.helsinki.fi> Cc: Christoph Lameter <clameter@engr.sgi.com> Cc: Ravikiran Thirumalai <kiran@scalex86.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> DESC slab-leaks3-locking-fix EDESC From: Andrew Morton <akpm@osdl.org> Update for slab-remove-cachep-spinlock.patch Cc: Al Viro <viro@ftp.linux.org.uk> Cc: Manfred Spraul <manfred@colorfullife.com> Cc: Alexander Nyberg <alexn@telia.com> Cc: Pekka Enberg <penberg@cs.helsinki.fi> Cc: Christoph Lameter <clameter@engr.sgi.com> Cc: Ravikiran Thirumalai <kiran@scalex86.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm/slab.c')
-rw-r--r--mm/slab.c180
1 files changed, 174 insertions, 6 deletions
diff --git a/mm/slab.c b/mm/slab.c
index 26138c9f8f0..a5047161084 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -204,7 +204,8 @@
204typedef unsigned int kmem_bufctl_t; 204typedef unsigned int kmem_bufctl_t;
205#define BUFCTL_END (((kmem_bufctl_t)(~0U))-0) 205#define BUFCTL_END (((kmem_bufctl_t)(~0U))-0)
206#define BUFCTL_FREE (((kmem_bufctl_t)(~0U))-1) 206#define BUFCTL_FREE (((kmem_bufctl_t)(~0U))-1)
207#define SLAB_LIMIT (((kmem_bufctl_t)(~0U))-2) 207#define BUFCTL_ACTIVE (((kmem_bufctl_t)(~0U))-2)
208#define SLAB_LIMIT (((kmem_bufctl_t)(~0U))-3)
208 209
209/* Max number of objs-per-slab for caches which use off-slab slabs. 210/* Max number of objs-per-slab for caches which use off-slab slabs.
210 * Needed to avoid a possible looping condition in cache_grow(). 211 * Needed to avoid a possible looping condition in cache_grow().
@@ -2399,7 +2400,7 @@ static void slab_put_obj(struct kmem_cache *cachep, struct slab *slabp,
2399 /* Verify that the slab belongs to the intended node */ 2400 /* Verify that the slab belongs to the intended node */
2400 WARN_ON(slabp->nodeid != nodeid); 2401 WARN_ON(slabp->nodeid != nodeid);
2401 2402
2402 if (slab_bufctl(slabp)[objnr] != BUFCTL_FREE) { 2403 if (slab_bufctl(slabp)[objnr] + 1 <= SLAB_LIMIT + 1) {
2403 printk(KERN_ERR "slab: double free detected in cache " 2404 printk(KERN_ERR "slab: double free detected in cache "
2404 "'%s', objp %p\n", cachep->name, objp); 2405 "'%s', objp %p\n", cachep->name, objp);
2405 BUG(); 2406 BUG();
@@ -2605,6 +2606,9 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
2605 */ 2606 */
2606 cachep->dtor(objp + obj_offset(cachep), cachep, 0); 2607 cachep->dtor(objp + obj_offset(cachep), cachep, 0);
2607 } 2608 }
2609#ifdef CONFIG_DEBUG_SLAB_LEAK
2610 slab_bufctl(slabp)[objnr] = BUFCTL_FREE;
2611#endif
2608 if (cachep->flags & SLAB_POISON) { 2612 if (cachep->flags & SLAB_POISON) {
2609#ifdef CONFIG_DEBUG_PAGEALLOC 2613#ifdef CONFIG_DEBUG_PAGEALLOC
2610 if ((cachep->buffer_size % PAGE_SIZE)==0 && OFF_SLAB(cachep)) { 2614 if ((cachep->buffer_size % PAGE_SIZE)==0 && OFF_SLAB(cachep)) {
@@ -2788,6 +2792,16 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
2788 *dbg_redzone1(cachep, objp) = RED_ACTIVE; 2792 *dbg_redzone1(cachep, objp) = RED_ACTIVE;
2789 *dbg_redzone2(cachep, objp) = RED_ACTIVE; 2793 *dbg_redzone2(cachep, objp) = RED_ACTIVE;
2790 } 2794 }
2795#ifdef CONFIG_DEBUG_SLAB_LEAK
2796 {
2797 struct slab *slabp;
2798 unsigned objnr;
2799
2800 slabp = page_get_slab(virt_to_page(objp));
2801 objnr = (unsigned)(objp - slabp->s_mem) / cachep->buffer_size;
2802 slab_bufctl(slabp)[objnr] = BUFCTL_ACTIVE;
2803 }
2804#endif
2791 objp += obj_offset(cachep); 2805 objp += obj_offset(cachep);
2792 if (cachep->ctor && cachep->flags & SLAB_POISON) { 2806 if (cachep->ctor && cachep->flags & SLAB_POISON) {
2793 unsigned long ctor_flags = SLAB_CTOR_CONSTRUCTOR; 2807 unsigned long ctor_flags = SLAB_CTOR_CONSTRUCTOR;
@@ -3220,22 +3234,23 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
3220 return __cache_alloc(cachep, flags, caller); 3234 return __cache_alloc(cachep, flags, caller);
3221} 3235}
3222 3236
3223#ifndef CONFIG_DEBUG_SLAB
3224 3237
3225void *__kmalloc(size_t size, gfp_t flags) 3238void *__kmalloc(size_t size, gfp_t flags)
3226{ 3239{
3240#ifndef CONFIG_DEBUG_SLAB
3227 return __do_kmalloc(size, flags, NULL); 3241 return __do_kmalloc(size, flags, NULL);
3242#else
3243 return __do_kmalloc(size, flags, __builtin_return_address(0));
3244#endif
3228} 3245}
3229EXPORT_SYMBOL(__kmalloc); 3246EXPORT_SYMBOL(__kmalloc);
3230 3247
3231#else 3248#ifdef CONFIG_DEBUG_SLAB
3232
3233void *__kmalloc_track_caller(size_t size, gfp_t flags, void *caller) 3249void *__kmalloc_track_caller(size_t size, gfp_t flags, void *caller)
3234{ 3250{
3235 return __do_kmalloc(size, flags, caller); 3251 return __do_kmalloc(size, flags, caller);
3236} 3252}
3237EXPORT_SYMBOL(__kmalloc_track_caller); 3253EXPORT_SYMBOL(__kmalloc_track_caller);
3238
3239#endif 3254#endif
3240 3255
3241#ifdef CONFIG_SMP 3256#ifdef CONFIG_SMP
@@ -3899,6 +3914,159 @@ ssize_t slabinfo_write(struct file *file, const char __user * buffer,
3899 res = count; 3914 res = count;
3900 return res; 3915 return res;
3901} 3916}
3917
3918#ifdef CONFIG_DEBUG_SLAB_LEAK
3919
3920static void *leaks_start(struct seq_file *m, loff_t *pos)
3921{
3922 loff_t n = *pos;
3923 struct list_head *p;
3924
3925 mutex_lock(&cache_chain_mutex);
3926 p = cache_chain.next;
3927 while (n--) {
3928 p = p->next;
3929 if (p == &cache_chain)
3930 return NULL;
3931 }
3932 return list_entry(p, struct kmem_cache, next);
3933}
3934
3935static inline int add_caller(unsigned long *n, unsigned long v)
3936{
3937 unsigned long *p;
3938 int l;
3939 if (!v)
3940 return 1;
3941 l = n[1];
3942 p = n + 2;
3943 while (l) {
3944 int i = l/2;
3945 unsigned long *q = p + 2 * i;
3946 if (*q == v) {
3947 q[1]++;
3948 return 1;
3949 }
3950 if (*q > v) {
3951 l = i;
3952 } else {
3953 p = q + 2;
3954 l -= i + 1;
3955 }
3956 }
3957 if (++n[1] == n[0])
3958 return 0;
3959 memmove(p + 2, p, n[1] * 2 * sizeof(unsigned long) - ((void *)p - (void *)n));
3960 p[0] = v;
3961 p[1] = 1;
3962 return 1;
3963}
3964
3965static void handle_slab(unsigned long *n, struct kmem_cache *c, struct slab *s)
3966{
3967 void *p;
3968 int i;
3969 if (n[0] == n[1])
3970 return;
3971 for (i = 0, p = s->s_mem; i < c->num; i++, p += c->buffer_size) {
3972 if (slab_bufctl(s)[i] != BUFCTL_ACTIVE)
3973 continue;
3974 if (!add_caller(n, (unsigned long)*dbg_userword(c, p)))
3975 return;
3976 }
3977}
3978
3979static void show_symbol(struct seq_file *m, unsigned long address)
3980{
3981#ifdef CONFIG_KALLSYMS
3982 char *modname;
3983 const char *name;
3984 unsigned long offset, size;
3985 char namebuf[KSYM_NAME_LEN+1];
3986
3987 name = kallsyms_lookup(address, &size, &offset, &modname, namebuf);
3988
3989 if (name) {
3990 seq_printf(m, "%s+%#lx/%#lx", name, offset, size);
3991 if (modname)
3992 seq_printf(m, " [%s]", modname);
3993 return;
3994 }
3995#endif
3996 seq_printf(m, "%p", (void *)address);
3997}
3998
3999static int leaks_show(struct seq_file *m, void *p)
4000{
4001 struct kmem_cache *cachep = p;
4002 struct list_head *q;
4003 struct slab *slabp;
4004 struct kmem_list3 *l3;
4005 const char *name;
4006 unsigned long *n = m->private;
4007 int node;
4008 int i;
4009
4010 if (!(cachep->flags & SLAB_STORE_USER))
4011 return 0;
4012 if (!(cachep->flags & SLAB_RED_ZONE))
4013 return 0;
4014
4015 /* OK, we can do it */
4016
4017 n[1] = 0;
4018
4019 for_each_online_node(node) {
4020 l3 = cachep->nodelists[node];
4021 if (!l3)
4022 continue;
4023
4024 check_irq_on();
4025 spin_lock_irq(&l3->list_lock);
4026
4027 list_for_each(q, &l3->slabs_full) {
4028 slabp = list_entry(q, struct slab, list);
4029 handle_slab(n, cachep, slabp);
4030 }
4031 list_for_each(q, &l3->slabs_partial) {
4032 slabp = list_entry(q, struct slab, list);
4033 handle_slab(n, cachep, slabp);
4034 }
4035 spin_unlock_irq(&l3->list_lock);
4036 }
4037 name = cachep->name;
4038 if (n[0] == n[1]) {
4039 /* Increase the buffer size */
4040 mutex_unlock(&cache_chain_mutex);
4041 m->private = kzalloc(n[0] * 4 * sizeof(unsigned long), GFP_KERNEL);
4042 if (!m->private) {
4043 /* Too bad, we are really out */
4044 m->private = n;
4045 mutex_lock(&cache_chain_mutex);
4046 return -ENOMEM;
4047 }
4048 *(unsigned long *)m->private = n[0] * 2;
4049 kfree(n);
4050 mutex_lock(&cache_chain_mutex);
4051 /* Now make sure this entry will be retried */
4052 m->count = m->size;
4053 return 0;
4054 }
4055 for (i = 0; i < n[1]; i++) {
4056 seq_printf(m, "%s: %lu ", name, n[2*i+3]);
4057 show_symbol(m, n[2*i+2]);
4058 seq_putc(m, '\n');
4059 }
4060 return 0;
4061}
4062
4063struct seq_operations slabstats_op = {
4064 .start = leaks_start,
4065 .next = s_next,
4066 .stop = s_stop,
4067 .show = leaks_show,
4068};
4069#endif
3902#endif 4070#endif
3903 4071
3904/** 4072/**