1052 lines · 25.3 KB · C
RawDownload
/* * Generic infrastructure for lifetime debugging of objects. * * Started by Thomas Gleixner * * Copyright (C) 2008, Thomas Gleixner <tglx@linutronix.de> * * For licencing details see kernel-base/COPYING */#include <linux/debugobjects.h>#include <linux/interrupt.h>#include <linux/sched.h>#include <linux/seq_file.h>#include <linux/debugfs.h>#include <linux/slab.h>#include <linux/hash.h> #define ODEBUG_HASH_BITS	14#define ODEBUG_HASH_SIZE	(1 << ODEBUG_HASH_BITS) #define ODEBUG_POOL_SIZE	512#define ODEBUG_POOL_MIN_LEVEL	256 #define ODEBUG_CHUNK_SHIFT	PAGE_SHIFT#define ODEBUG_CHUNK_SIZE	(1 << ODEBUG_CHUNK_SHIFT)#define ODEBUG_CHUNK_MASK	(~(ODEBUG_CHUNK_SIZE - 1)) struct debug_bucket {	struct hlist_head	list;	raw_spinlock_t		lock;}; static struct debug_bucket	obj_hash[ODEBUG_HASH_SIZE]; static struct debug_obj		obj_static_pool[ODEBUG_POOL_SIZE] __initdata; static DEFINE_RAW_SPINLOCK(pool_lock); static HLIST_HEAD(obj_pool); static int			obj_pool_min_free = ODEBUG_POOL_SIZE;static int			obj_pool_free = ODEBUG_POOL_SIZE;static int			obj_pool_used;static int			obj_pool_max_used;static struct kmem_cache	*obj_cache; static int			debug_objects_maxchain __read_mostly;static int			debug_objects_fixups __read_mostly;static int			debug_objects_warnings __read_mostly;static int			debug_objects_enabled __read_mostly				= CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT; static struct debug_obj_descr	*descr_test  __read_mostly; static void free_obj_work(struct work_struct *work);static DECLARE_WORK(debug_obj_work, free_obj_work); static int __init enable_object_debug(char *str){	debug_objects_enabled = 1;	return 0;} static int __init disable_object_debug(char *str){	debug_objects_enabled = 0;	return 0;} early_param("debug_objects", enable_object_debug);early_param("no_debug_objects", disable_object_debug); static const char *obj_states[ODEBUG_STATE_MAX] = {	[ODEBUG_STATE_NONE]		= "none",	[ODEBUG_STATE_INIT]		= "initialized",	[ODEBUG_STATE_INACTIVE]		= "inactive",	[ODEBUG_STATE_ACTIVE]		= "active",	[ODEBUG_STATE_DESTROYED]	= "destroyed",	[ODEBUG_STATE_NOTAVAILABLE]	= "not available",}; static int fill_pool(void){	gfp_t gfp = GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN;	struct debug_obj *new;	unsigned long flags; 	if (likely(obj_pool_free >= ODEBUG_POOL_MIN_LEVEL))		return obj_pool_free; 	if (unlikely(!obj_cache))		return obj_pool_free; 	while (obj_pool_free < ODEBUG_POOL_MIN_LEVEL) { 		new = kmem_cache_zalloc(obj_cache, gfp);		if (!new)			return obj_pool_free; 		raw_spin_lock_irqsave(&pool_lock, flags);		hlist_add_head(&new->node, &obj_pool);		obj_pool_free++;		raw_spin_unlock_irqrestore(&pool_lock, flags);	}	return obj_pool_free;} /* * Lookup an object in the hash bucket. */static struct debug_obj *lookup_object(void *addr, struct debug_bucket *b){	struct hlist_node *node;	struct debug_obj *obj;	int cnt = 0; 	hlist_for_each_entry(obj, node, &b->list, node) {		cnt++;		if (obj->object == addr)			return obj;	}	if (cnt > debug_objects_maxchain)		debug_objects_maxchain = cnt; 	return NULL;} /* * Allocate a new object. If the pool is empty, switch off the debugger. * Must be called with interrupts disabled. */static struct debug_obj *alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr){	struct debug_obj *obj = NULL; 	raw_spin_lock(&pool_lock);	if (obj_pool.first) {		obj	    = hlist_entry(obj_pool.first, typeof(*obj), node); 		obj->object = addr;		obj->descr  = descr;		obj->state  = ODEBUG_STATE_NONE;		obj->astate = 0;		hlist_del(&obj->node); 		hlist_add_head(&obj->node, &b->list); 		obj_pool_used++;		if (obj_pool_used > obj_pool_max_used)			obj_pool_max_used = obj_pool_used; 		obj_pool_free--;		if (obj_pool_free < obj_pool_min_free)			obj_pool_min_free = obj_pool_free;	}	raw_spin_unlock(&pool_lock); 	return obj;} /* * workqueue function to free objects. */static void free_obj_work(struct work_struct *work){	struct debug_obj *obj;	unsigned long flags; 	raw_spin_lock_irqsave(&pool_lock, flags);	while (obj_pool_free > ODEBUG_POOL_SIZE) {		obj = hlist_entry(obj_pool.first, typeof(*obj), node);		hlist_del(&obj->node);		obj_pool_free--;		/*		 * We release pool_lock across kmem_cache_free() to		 * avoid contention on pool_lock.		 */		raw_spin_unlock_irqrestore(&pool_lock, flags);		kmem_cache_free(obj_cache, obj);		raw_spin_lock_irqsave(&pool_lock, flags);	}	raw_spin_unlock_irqrestore(&pool_lock, flags);} /* * Put the object back into the pool and schedule work to free objects * if necessary. */static void free_object(struct debug_obj *obj){	unsigned long flags;	int sched = 0; 	raw_spin_lock_irqsave(&pool_lock, flags);	/*	 * schedule work when the pool is filled and the cache is	 * initialized:	 */	if (obj_pool_free > ODEBUG_POOL_SIZE && obj_cache)		sched = keventd_up() && !work_pending(&debug_obj_work);	hlist_add_head(&obj->node, &obj_pool);	obj_pool_free++;	obj_pool_used--;	raw_spin_unlock_irqrestore(&pool_lock, flags);	if (sched)		schedule_work(&debug_obj_work);} /* * We run out of memory. That means we probably have tons of objects * allocated. */static void debug_objects_oom(void){	struct debug_bucket *db = obj_hash;	struct hlist_node *node, *tmp;	HLIST_HEAD(freelist);	struct debug_obj *obj;	unsigned long flags;	int i; 	printk(KERN_WARNING "ODEBUG: Out of memory. ODEBUG disabled\n"); 	for (i = 0; i < ODEBUG_HASH_SIZE; i++, db++) {		raw_spin_lock_irqsave(&db->lock, flags);		hlist_move_list(&db->list, &freelist);		raw_spin_unlock_irqrestore(&db->lock, flags); 		/* Now free them */		hlist_for_each_entry_safe(obj, node, tmp, &freelist, node) {			hlist_del(&obj->node);			free_object(obj);		}	}} /* * We use the pfn of the address for the hash. That way we can check * for freed objects simply by checking the affected bucket. */static struct debug_bucket *get_bucket(unsigned long addr){	unsigned long hash; 	hash = hash_long((addr >> ODEBUG_CHUNK_SHIFT), ODEBUG_HASH_BITS);	return &obj_hash[hash];} static void debug_print_object(struct debug_obj *obj, char *msg){	struct debug_obj_descr *descr = obj->descr;	static int limit; 	if (limit < 5 && descr != descr_test) {		void *hint = descr->debug_hint ?			descr->debug_hint(obj->object) : NULL;		limit++;		WARN(1, KERN_ERR "ODEBUG: %s %s (active state %u) "				 "object type: %s hint: %pS\n",			msg, obj_states[obj->state], obj->astate,			descr->name, hint);	}	debug_objects_warnings++;} /* * Try to repair the damage, so we have a better chance to get useful * debug output. */static voiddebug_object_fixup(int (*fixup)(void *addr, enum debug_obj_state state),		   void * addr, enum debug_obj_state state){	if (fixup)		debug_objects_fixups += fixup(addr, state);} static void debug_object_is_on_stack(void *addr, int onstack){	int is_on_stack;	static int limit; 	if (limit > 4)		return; 	is_on_stack = object_is_on_stack(addr);	if (is_on_stack == onstack)		return; 	limit++;	if (is_on_stack)		printk(KERN_WARNING		       "ODEBUG: object is on stack, but not annotated\n");	else		printk(KERN_WARNING		       "ODEBUG: object is not on stack, but annotated\n");	WARN_ON(1);} static void__debug_object_init(void *addr, struct debug_obj_descr *descr, int onstack){	enum debug_obj_state state;	struct debug_bucket *db;	struct debug_obj *obj;	unsigned long flags; 	fill_pool(); 	db = get_bucket((unsigned long) addr); 	raw_spin_lock_irqsave(&db->lock, flags); 	obj = lookup_object(addr, db);	if (!obj) {		obj = alloc_object(addr, db, descr);		if (!obj) {			debug_objects_enabled = 0;			raw_spin_unlock_irqrestore(&db->lock, flags);			debug_objects_oom();			return;		}		debug_object_is_on_stack(addr, onstack);	} 	switch (obj->state) {	case ODEBUG_STATE_NONE:	case ODEBUG_STATE_INIT:	case ODEBUG_STATE_INACTIVE:		obj->state = ODEBUG_STATE_INIT;		break; 	case ODEBUG_STATE_ACTIVE:		debug_print_object(obj, "init");		state = obj->state;		raw_spin_unlock_irqrestore(&db->lock, flags);		debug_object_fixup(descr->fixup_init, addr, state);		return; 	case ODEBUG_STATE_DESTROYED:		debug_print_object(obj, "init");		break;	default:		break;	} 	raw_spin_unlock_irqrestore(&db->lock, flags);} /** * debug_object_init - debug checks when an object is initialized * @addr:	address of the object * @descr:	pointer to an object specific debug description structure */void debug_object_init(void *addr, struct debug_obj_descr *descr){	if (!debug_objects_enabled)		return; 	__debug_object_init(addr, descr, 0);} /** * debug_object_init_on_stack - debug checks when an object on stack is *				initialized * @addr:	address of the object * @descr:	pointer to an object specific debug description structure */void debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr){	if (!debug_objects_enabled)		return; 	__debug_object_init(addr, descr, 1);} /** * debug_object_activate - debug checks when an object is activated * @addr:	address of the object * @descr:	pointer to an object specific debug description structure */void debug_object_activate(void *addr, struct debug_obj_descr *descr){	enum debug_obj_state state;	struct debug_bucket *db;	struct debug_obj *obj;	unsigned long flags; 	if (!debug_objects_enabled)		return; 	db = get_bucket((unsigned long) addr); 	raw_spin_lock_irqsave(&db->lock, flags); 	obj = lookup_object(addr, db);	if (obj) {		switch (obj->state) {		case ODEBUG_STATE_INIT:		case ODEBUG_STATE_INACTIVE:			obj->state = ODEBUG_STATE_ACTIVE;			break; 		case ODEBUG_STATE_ACTIVE:			debug_print_object(obj, "activate");			state = obj->state;			raw_spin_unlock_irqrestore(&db->lock, flags);			debug_object_fixup(descr->fixup_activate, addr, state);			return; 		case ODEBUG_STATE_DESTROYED:			debug_print_object(obj, "activate");			break;		default:			break;		}		raw_spin_unlock_irqrestore(&db->lock, flags);		return;	} 	raw_spin_unlock_irqrestore(&db->lock, flags);	/*	 * This happens when a static object is activated. We	 * let the type specific code decide whether this is	 * true or not.	 */	debug_object_fixup(descr->fixup_activate, addr,			   ODEBUG_STATE_NOTAVAILABLE);} /** * debug_object_deactivate - debug checks when an object is deactivated * @addr:	address of the object * @descr:	pointer to an object specific debug description structure */void debug_object_deactivate(void *addr, struct debug_obj_descr *descr){	struct debug_bucket *db;	struct debug_obj *obj;	unsigned long flags; 	if (!debug_objects_enabled)		return; 	db = get_bucket((unsigned long) addr); 	raw_spin_lock_irqsave(&db->lock, flags); 	obj = lookup_object(addr, db);	if (obj) {		switch (obj->state) {		case ODEBUG_STATE_INIT:		case ODEBUG_STATE_INACTIVE:		case ODEBUG_STATE_ACTIVE:			if (!obj->astate)				obj->state = ODEBUG_STATE_INACTIVE;			else				debug_print_object(obj, "deactivate");			break; 		case ODEBUG_STATE_DESTROYED:			debug_print_object(obj, "deactivate");			break;		default:			break;		}	} else {		struct debug_obj o = { .object = addr,				       .state = ODEBUG_STATE_NOTAVAILABLE,				       .descr = descr }; 		debug_print_object(&o, "deactivate");	} 	raw_spin_unlock_irqrestore(&db->lock, flags);} /** * debug_object_destroy - debug checks when an object is destroyed * @addr:	address of the object * @descr:	pointer to an object specific debug description structure */void debug_object_destroy(void *addr, struct debug_obj_descr *descr){	enum debug_obj_state state;	struct debug_bucket *db;	struct debug_obj *obj;	unsigned long flags; 	if (!debug_objects_enabled)		return; 	db = get_bucket((unsigned long) addr); 	raw_spin_lock_irqsave(&db->lock, flags); 	obj = lookup_object(addr, db);	if (!obj)		goto out_unlock;

Lines 1–500 of 1052.