add memory resource debug

main use is to find memory and buffer leaks at the moment
This commit is contained in:
Karsten Keil 2003-11-21 22:57:08 +00:00
parent 85337c9851
commit 8d5f6a65d3
18 changed files with 396 additions and 17 deletions

View File

@ -7,4 +7,4 @@ CONFIG_MISDN_HFCPCI=y
CONFIG_MISDN_SPEEDFAX=y
CONFIG_MISDN_W6692=y
CONFIG_MISDN_DSP=y
CONFIG_MISDN_MEMDEBUG=y

View File

@ -13,6 +13,15 @@ config MISDN_DRV
if MISDN_DRV!=n
config MISDN_MEMDEBUG
bool "Enable memory leak debug for mISDN"
help
This option is for watching the use of several resources in mISDN.
It includes extra code to maintain list of allocated memory and
sk_buffs. On module unload you can see not freed resources an
their allocation orging and some object specific informations.
If unsure, say 'N'.
config MISDN_AVM_FRITZ
bool "Support for AVM Fritz!Cards"
depends on PCI || ISA

View File

@ -3,6 +3,10 @@
# EXTRA_CFLAGS += -S -g
#
ifdef CONFIG_MISDN_MEMDEBUG
EXTRA_CFLAGS += -DMISDN_MEMDEBUG
endif
obj-$(CONFIG_MISDN_DRV) += mISDN_core.o
obj-$(CONFIG_MISDN_DRV) += mISDN_isac.o
obj-$(CONFIG_MISDN_DRV) += mISDN_l1.o
@ -43,6 +47,9 @@ hfcpci-objs := hfc_pci.o debug.o helper.o dchannel.o bchannel.o
w6692pci-objs := w6692.o debug.o helper.o dchannel.o bchannel.o
mISDN_isac-objs := isac.o arcofi.o debug.o
mISDN_core-objs := core.o stack.o udevice.o helper.o
ifdef CONFIG_MISDN_MEMDEBUG
mISDN_core-objs += memdbg.o
endif
mISDN_l1-objs := layer1.o helper.o debug.o fsm.o
mISDN_l2-objs := layer2.o tei.o helper.o debug.o fsm.o
l3udss1-objs := layer3.o helper.o l3helper.o debug.o fsm.o l3_udss1.o

View File

@ -3,6 +3,10 @@
# EXTRA_CFLAGS += -S -g
#
ifdef CONFIG_MISDN_MEMDEBUG
EXTRA_CFLAGS += -DMISDN_MEMDEBUG
endif
obj-$(CONFIG_MISDN_DRV) += mISDN_core.o
obj-$(CONFIG_MISDN_DRV) += mISDN_isac.o
obj-$(CONFIG_MISDN_DRV) += mISDN_l1.o
@ -43,6 +47,9 @@ hfcpci-objs := hfc_pci.o debug.o helper.o dchannel.o bchannel.o
w6692pci-objs := w6692.o debug.o helper.o dchannel.o bchannel.o
mISDN_isac-objs := isac.o arcofi.o debug.o
mISDN_core-objs := core.o stack.o udevice.o helper.o
ifdef CONFIG_MISDN_MEMDEBUG
mISDN_core-objs += memdbg.o
endif
mISDN_l1-objs := layer1.o helper.o debug.o fsm.o
mISDN_l2-objs := layer2.o tei.o helper.o debug.o fsm.o
l3udss1-objs := layer3.o helper.o l3helper.o debug.o fsm.o l3_udss1.o

View File

@ -4,9 +4,8 @@
O_TARGET := vmlinux-obj.o
ifdef MEMDBG
EXTRA_CFLAGS += -DMEMDBG
MX_OBJS += memdbg.o
ifdef CONFIG_MISDN_MEMDEBUG
export-objs += memdbg.o
endif
export-objs := core.o isac.o

View File

@ -19,7 +19,7 @@
#include <asm/io.h>
#include <linux/ioport.h>
#include <linux/skbuff.h>
#ifdef MEMDBG
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif

View File

@ -609,6 +609,11 @@ mISDNInit(void)
printk(KERN_INFO "Modular ISDN Stack core %s\n", mISDN_core_revision);
core_debug = debug;
#ifdef MISDN_MEMDEBUG
err = __mid_init();
if (err)
return(err);
#endif
err = init_mISDNdev(debug);
if (err)
return(err);
@ -652,6 +657,9 @@ void mISDN_cleanup(void) {
down(&sem);
mISDN_thread.notify = NULL;
}
#ifdef MISDN_MEMDEBUG
__mid_cleanup();
#endif
printk(KERN_DEBUG "mISDNcore unloaded\n");
}

View File

@ -8,7 +8,7 @@
#include <linux/string.h>
#include <linux/mISDNif.h>
#include "helper.h"
#ifdef MEMDBG
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif

View File

@ -19,7 +19,7 @@
#include <asm/io.h>
#include <linux/ioport.h>
#include <linux/skbuff.h>
#ifdef MEMDBG
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif

View File

@ -8,7 +8,7 @@
#ifndef _mISDN_HELPER_H
#define _mISDN_HELPER_H
#include <linux/kernel.h>
#ifdef MEMDBG
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif
@ -69,12 +69,22 @@ discard_queue(struct sk_buff_head *q)
return(ret);
}
#ifdef MISDN_MEMDEBUG
#define alloc_stack_skb(s, r) __mid_alloc_stack_skb(s, r, __FILE__, __LINE__)
static inline struct sk_buff *
__mid_alloc_stack_skb(size_t size, size_t reserve, char *fn, int line)
{
struct sk_buff *skb;
if (!(skb = __mid_alloc_skb(size + reserve, GFP_ATOMIC, fn, line)))
#else
static inline struct sk_buff *
alloc_stack_skb(size_t size, size_t reserve)
{
struct sk_buff *skb;
if (!(skb = alloc_skb(size + reserve, GFP_ATOMIC)))
#endif
printk(KERN_WARNING "%s(%d,%d): no skb size\n", __FUNCTION__,
size, reserve);
else
@ -119,13 +129,22 @@ extern __inline__ int if_newhead(mISDNif_t *i, u_int prim, int dinfo,
return(i->func(i, skb));
}
#ifdef MISDN_MEMDEBUG
#define create_link_skb(p, d, l, a, r) __mid_create_link_skb(p, d, l, a, r, __FILE__, __LINE__)
extern __inline__ struct sk_buff *
__mid_create_link_skb(u_int prim, int dinfo, int len, void *arg, int reserve, char *fn, int line)
{
struct sk_buff *skb;
extern __inline__ struct sk_buff *create_link_skb(u_int prim, int dinfo,
int len, void *arg, int reserve)
if (!(skb = __mid_alloc_skb(len + reserve, GFP_ATOMIC, fn, line))) {
#else
extern __inline__ struct sk_buff *
create_link_skb(u_int prim, int dinfo, int len, void *arg, int reserve)
{
struct sk_buff *skb;
if (!(skb = alloc_skb(len + reserve, GFP_ATOMIC))) {
#endif
printk(KERN_WARNING "%s: no skb size %d+%d\n",
__FUNCTION__, len, reserve);
return(NULL);
@ -137,13 +156,24 @@ extern __inline__ struct sk_buff *create_link_skb(u_int prim, int dinfo,
return(skb);
}
extern __inline__ int if_link(mISDNif_t *i, u_int prim, int dinfo, int len,
void *arg, int reserve)
#ifdef MISDN_MEMDEBUG
#define if_link(i, p, d, l, a, r) __mid_if_link(i, p, d, l, a, r, __FILE__, __LINE__)
extern __inline__ int
__mid_if_link(mISDNif_t *i, u_int prim, int dinfo, int len, void *arg, int reserve, char *fn, int line)
{
struct sk_buff *skb;
int err;
if (!(skb = __mid_create_link_skb(prim, dinfo, len, arg, reserve, fn, line)))
#else
extern __inline__ int
if_link(mISDNif_t *i, u_int prim, int dinfo, int len, void *arg, int reserve)
{
struct sk_buff *skb;
int err;
if (!(skb = create_link_skb(prim, dinfo, len, arg, reserve)))
#endif
return(-ENOMEM);
if (!i)
err = -ENXIO;
@ -159,7 +189,12 @@ extern __inline__ int if_link(mISDNif_t *i, u_int prim, int dinfo, int len,
extern signed int l3_ie2pos(u_char);
extern unsigned char l3_pos2ie(int);
extern void initQ931_info(Q931_info_t *);
#ifdef MISDN_MEMDEBUG
#define alloc_l3msg(a, b) __mid_alloc_l3msg(a, b, __FILE__, __LINE__)
extern struct sk_buff *__mid_alloc_l3msg(int, u_char, char *, int);
#else
extern struct sk_buff *alloc_l3msg(int, u_char);
#endif
extern void AddvarIE(struct sk_buff *, u_char *);
extern void AddIE(struct sk_buff *, u_char, u_char *);
extern void LogL3Msg(struct sk_buff *);

View File

@ -52,12 +52,20 @@ initQ931_info(Q931_info_t *qi) {
};
struct sk_buff *
#ifdef MISDN_MEMDEBUG
__mid_alloc_l3msg(int len, u_char type, char *fn, int line)
#else
alloc_l3msg(int len, u_char type)
#endif
{
struct sk_buff *skb;
Q931_info_t *qi;
#ifdef MISDN_MEMDEBUG
if (!(skb = __mid_alloc_skb(len + L3_EXTRA_SIZE +1, GFP_ATOMIC, fn, line))) {
#else
if (!(skb = alloc_skb(len + L3_EXTRA_SIZE +1, GFP_ATOMIC))) {
#endif
printk(KERN_WARNING "mISDN: No skb for L3\n");
return (NULL);
}

View File

@ -8,7 +8,7 @@
#include <linux/mISDNif.h>
#include "fsm.h"
#ifdef MEMDBG
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif

View File

@ -9,7 +9,7 @@
#include <linux/mISDNif.h>
#include <linux/skbuff.h>
#include "fsm.h"
#ifdef MEMDBG
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif

View File

@ -263,7 +263,7 @@ l3_process_t
l3_process_t
*new_l3_process(layer3_t *l3, int cr, int n303, u_int id)
{
l3_process_t *p;
l3_process_t *p = NULL;
if (id == MISDN_ID_ANY) {
if (l3->entity == MISDN_ENTITY_NONE) {

View File

@ -7,7 +7,7 @@
#include <linux/mISDNif.h>
#include <linux/skbuff.h>
#include "fsm.h"
#ifdef MEMDBG
#ifdef MISDN_MEMDEBUG
#include "memdbg.h"
#endif

View File

@ -0,0 +1,265 @@
#include <linux/stddef.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/skbuff.h>
#include <linux/mISDNif.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
static struct list_head mISDN_memdbg_list = LIST_HEAD_INIT(mISDN_memdbg_list);
static struct list_head mISDN_skbdbg_list = LIST_HEAD_INIT(mISDN_skbdbg_list);
static kmem_cache_t *mid_sitem_cache;
#define MAX_FILE_STRLEN (64 - 3*sizeof(u_int) - sizeof(struct list_head))
#define MID_ITEM_TYP_KMALLOC 1
#define MID_ITEM_TYP_VMALLOC 2
typedef struct _mid_item {
struct list_head head;
u_int typ;
u_int size;
u_int line;
char file[MAX_FILE_STRLEN];
} _mid_item_t;
typedef struct _mid_sitem {
struct list_head head;
struct sk_buff *skb;
unsigned int size;
int line;
char file[MAX_FILE_STRLEN];
} _mid_sitem_t;
void *
__mid_kmalloc(size_t size, int ord, char *fn, int line)
{
_mid_item_t *mid;
mid = kmalloc(size + sizeof(_mid_item_t), ord);
if (mid) {
INIT_LIST_HEAD(&mid->head);
mid->typ = MID_ITEM_TYP_KMALLOC;
mid->size = size;
mid->line = line;
memcpy(mid->file, fn, MAX_FILE_STRLEN);
mid->file[MAX_FILE_STRLEN-1] = 0;
list_add_tail(&mid->head, &mISDN_memdbg_list);
return((void *)&mid->file[MAX_FILE_STRLEN]);
} else
return(NULL);
}
void
__mid_kfree(const void *p)
{
_mid_item_t *mid;
if (!p) {
printk(KERN_ERR "zero pointer kfree at %p", __builtin_return_address(0));
return;
}
mid = (_mid_item_t *)((u_char *)p - sizeof(_mid_item_t));
list_del(&mid->head);
kfree(mid);
}
void *
__mid_vmalloc(size_t size, char *fn, int line)
{
_mid_item_t *mid;
mid = vmalloc(size + sizeof(_mid_item_t));
if (mid) {
INIT_LIST_HEAD(&mid->head);
mid->typ = MID_ITEM_TYP_VMALLOC;
mid->size = size;
mid->line = line;
memcpy(mid->file, fn, MAX_FILE_STRLEN);
mid->file[MAX_FILE_STRLEN-1] = 0;
list_add_tail(&mid->head, &mISDN_memdbg_list);
return((void *)&mid->file[MAX_FILE_STRLEN]);
} else
return(NULL);
}
void
__mid_vfree(const void *p)
{
_mid_item_t *mid;
if (!p) {
printk(KERN_ERR "zero pointer vfree at %p", __builtin_return_address(0));
return;
}
mid = (_mid_item_t *)((u_char *)p - sizeof(_mid_item_t));
list_del(&mid->head);
vfree(mid);
}
static void
__mid_skb_destructor(struct sk_buff *skb)
{
struct list_head *item, *next;
_mid_sitem_t *sid;
list_for_each_safe(item, next, &mISDN_skbdbg_list) {
sid = (_mid_sitem_t *)item;
if (sid->skb == skb) {
list_del(&sid->head);
kmem_cache_free(mid_sitem_cache, sid);
return;
}
}
printk(KERN_DEBUG "%s: item(%p) not in list\n", __FUNCTION__, skb);
}
static __inline__ void
__mid_sitem_setup(struct sk_buff *skb, unsigned int size, char *fn, int line)
{
_mid_sitem_t *sid;
sid = kmem_cache_alloc(mid_sitem_cache, GFP_ATOMIC);
if (!sid)
return;
INIT_LIST_HEAD(&sid->head);
sid->skb = skb;
sid->size = size;
sid->line = line;
memcpy(sid->file, fn, MAX_FILE_STRLEN);
sid->file[MAX_FILE_STRLEN-1] = 0;
skb->destructor = __mid_skb_destructor;
list_add_tail(&sid->head, &mISDN_skbdbg_list);
}
struct sk_buff *
__mid_alloc_skb(unsigned int size, int gfp_mask, char *fn, int line)
{
struct sk_buff *skb = alloc_skb(size, gfp_mask);
if (!skb)
return(NULL);
__mid_sitem_setup(skb, size, fn, line);
return(skb);
}
struct sk_buff *
__mid_dev_alloc_skb(unsigned int size, char *fn, int line)
{
struct sk_buff *skb = dev_alloc_skb(size);
if (!skb)
return(NULL);
__mid_sitem_setup(skb, size, fn, line);
return(skb);
}
struct sk_buff
*__mid_skb_clone(struct sk_buff *skb, int gfp_mask, char *fn, int line)
{
struct sk_buff *nskb = skb_clone(skb, gfp_mask);
if (!nskb)
return(NULL);
__mid_sitem_setup(nskb, (nskb->end - nskb->head), fn, line);
return(nskb);
}
struct sk_buff
*__mid_skb_copy(struct sk_buff *skb, int gfp_mask, char *fn, int line)
{
struct sk_buff *nskb = skb_copy(skb, gfp_mask);
if (!nskb)
return(NULL);
__mid_sitem_setup(nskb, (nskb->end - nskb->head), fn, line);
return(nskb);
}
struct sk_buff
*__mid_skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom, char *fn, int line)
{
struct sk_buff *nskb = skb_realloc_headroom(skb, headroom);
if (!nskb || (nskb == skb))
return(nskb);
__mid_sitem_setup(nskb, (nskb->end - nskb->head), fn, line);
return(nskb);
}
void
__mid_cleanup(void)
{
struct list_head *item, *next;
_mid_item_t *mid;
_mid_sitem_t *sid;
mISDN_head_t *hh;
int n = 0;
list_for_each_safe(item, next, &mISDN_memdbg_list) {
mid = (_mid_item_t *)item;
switch(mid->typ) {
case MID_ITEM_TYP_KMALLOC:
printk(KERN_ERR "not freed kmalloc size(%d) from %s:%d\n",
mid->size, mid->file, mid->line);
kfree(mid);
break;
case MID_ITEM_TYP_VMALLOC:
printk(KERN_ERR "not freed vmalloc size(%d) from %s:%d\n",
mid->size, mid->file, mid->line);
vfree(mid);
break;
default:
printk(KERN_ERR "unknown mid->typ(%d) size(%d) from %s:%d\n",
mid->typ, mid->size, mid->file, mid->line);
break;
}
n++;
}
printk(KERN_DEBUG "%s: %d kmalloc item(s) freed\n", __FUNCTION__, n);
n = 0;
list_for_each_safe(item, next, &mISDN_skbdbg_list) {
sid = (_mid_sitem_t *)item;
hh = mISDN_HEAD_P(sid->skb);
printk(KERN_ERR "not freed skb(%p) size(%d) prim(%x) dinfo(%x) allocated at %s:%d\n",
sid->skb, sid->size, hh->prim, hh->dinfo, sid->file, sid->line);
/*maybe the skb is still aktiv */
sid->skb->destructor = NULL;
list_del(&sid->head);
kmem_cache_free(mid_sitem_cache, sid);
n++;
}
if (mid_sitem_cache)
kmem_cache_destroy(mid_sitem_cache);
printk(KERN_DEBUG "%s: %d sk_buff item(s) freed\n", __FUNCTION__, n);
}
int
__mid_init(void)
{
mid_sitem_cache = kmem_cache_create("mISDN_skbdbg",
sizeof(_mid_sitem_t),
0, 0, NULL, NULL);
if (!mid_sitem_cache)
return(-ENOMEM);
return(0);
}
#ifdef MODULE
EXPORT_SYMBOL(__mid_kmalloc);
EXPORT_SYMBOL(__mid_kfree);
EXPORT_SYMBOL(__mid_vmalloc);
EXPORT_SYMBOL(__mid_vfree);
EXPORT_SYMBOL(__mid_alloc_skb);
EXPORT_SYMBOL(__mid_dev_alloc_skb);
EXPORT_SYMBOL(__mid_skb_clone);
EXPORT_SYMBOL(__mid_skb_copy);
EXPORT_SYMBOL(__mid_skb_realloc_headroom);
#endif

View File

@ -0,0 +1,41 @@
#ifndef MEMDBG_H
#define MEMDBG_H
#ifdef MISDN_MEMDEBUG
#include <linux/vmalloc.h>
#include <linux/slab.h>
#undef kmalloc
#undef kfree
#undef vmalloc
#undef vfree
#undef alloc_skb
#undef dev_alloc_skb
#undef skb_clone
#undef skb_copy
#undef skb_realloc_headroom
#define kmalloc(a, b) __mid_kmalloc(a, b, __FILE__, __LINE__)
#define kfree(a) __mid_kfree(a)
#define vmalloc(s) __mid_vmalloc(s, __FILE__, __LINE__)
#define vfree(p) __mid_vfree(p)
#define alloc_skb(a, b) __mid_alloc_skb(a, b, __FILE__, __LINE__)
#define dev_alloc_skb(a) __mid_dev_alloc_skb(a, __FILE__, __LINE__)
#define skb_clone(a, b) __mid_skb_clone(a, b, __FILE__, __LINE__)
#define skb_copy(a, b) __mid_skb_copy(a, b, __FILE__, __LINE__)
#define skb_realloc_headroom(a, b) __mid_skb_realloc_headroom(a, b, __FILE__, __LINE__)
extern void *__mid_kmalloc(size_t, int, char *, int);
extern void __mid_kfree(const void *);
extern void *__mid_vmalloc(size_t, char *, int);
extern void __mid_vfree(const void *);
extern void __mid_cleanup(void);
extern int __mid_init(void);
extern struct sk_buff *__mid_alloc_skb(unsigned int,int, char *, int);
extern struct sk_buff *__mid_dev_alloc_skb(unsigned int,char *, int);
extern struct sk_buff *__mid_skb_clone(struct sk_buff *, int, char *, int);
extern struct sk_buff *__mid_skb_copy(struct sk_buff *, int, char *, int);
extern struct sk_buff *__mid_skb_realloc_headroom(struct sk_buff *, unsigned int, char *, int);
#endif
#endif

View File

@ -1,7 +1,7 @@
Vendor: SuSE GmbH, Nuernberg, Germany
Distribution: SuSE Linux 8.2 (i386)
Name: km_mISDN
Release: 8
Release: 9
Packager: feedback@suse.de
Copyright: Karsten Keil GPL