1201 lines · 29.5 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 */ #define pr_fmt(fmt) "ODEBUG: " fmt #include <linux/debugobjects.h>#include <linux/interrupt.h>#include <linux/sched.h>#include <linux/sched/task_stack.h>#include <linux/seq_file.h>#include <linux/debugfs.h>#include <linux/slab.h>#include <linux/hash.h>#include <linux/kmemleak.h> #define ODEBUG_HASH_BITS	14#define ODEBUG_HASH_SIZE	(1 << ODEBUG_HASH_BITS) #define ODEBUG_POOL_SIZE	1024#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 HLIST_HEAD(obj_to_free); 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;/* The number of objs on the global free list */static int			obj_nr_tofree;static struct kmem_cache	*obj_cache; static int			debug_objects_maxchain __read_mostly;static int __maybe_unused	debug_objects_maxchecked __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 int			debug_objects_pool_size __read_mostly				= ODEBUG_POOL_SIZE;static int			debug_objects_pool_min_level __read_mostly				= ODEBUG_POOL_MIN_LEVEL;static struct debug_obj_descr	*descr_test  __read_mostly; /* * Track numbers of kmem_cache_alloc()/free() calls done. */static int			debug_objects_allocated;static int			debug_objects_freed; 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 void fill_pool(void){	gfp_t gfp = GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN;	struct debug_obj *new, *obj;	unsigned long flags; 	if (likely(obj_pool_free >= debug_objects_pool_min_level))		return; 	/*	 * Reuse objs from the global free list; they will be reinitialized	 * when allocating.	 */	while (obj_nr_tofree && (obj_pool_free < obj_pool_min_free)) {		raw_spin_lock_irqsave(&pool_lock, flags);		/*		 * Recheck with the lock held as the worker thread might have		 * won the race and freed the global free list already.		 */		if (obj_nr_tofree) {			obj = hlist_entry(obj_to_free.first, typeof(*obj), node);			hlist_del(&obj->node);			obj_nr_tofree--;			hlist_add_head(&obj->node, &obj_pool);			obj_pool_free++;		}		raw_spin_unlock_irqrestore(&pool_lock, flags);	} 	if (unlikely(!obj_cache))		return; 	while (obj_pool_free < debug_objects_pool_min_level) { 		new = kmem_cache_zalloc(obj_cache, gfp);		if (!new)			return; 		raw_spin_lock_irqsave(&pool_lock, flags);		hlist_add_head(&new->node, &obj_pool);		debug_objects_allocated++;		obj_pool_free++;		raw_spin_unlock_irqrestore(&pool_lock, flags);	}} /* * Lookup an object in the hash bucket. */static struct debug_obj *lookup_object(void *addr, struct debug_bucket *b){	struct debug_obj *obj;	int cnt = 0; 	hlist_for_each_entry(obj, &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. * * To reduce contention on the global pool_lock, the actual freeing of * debug objects will be delayed if the pool_lock is busy. */static void free_obj_work(struct work_struct *work){	struct hlist_node *tmp;	struct debug_obj *obj;	unsigned long flags;	HLIST_HEAD(tofree); 	if (!raw_spin_trylock_irqsave(&pool_lock, flags))		return; 	/*	 * The objs on the pool list might be allocated before the work is	 * run, so recheck if pool list it full or not, if not fill pool	 * list from the global free list	 */	while (obj_nr_tofree && obj_pool_free < debug_objects_pool_size) {		obj = hlist_entry(obj_to_free.first, typeof(*obj), node);		hlist_del(&obj->node);		hlist_add_head(&obj->node, &obj_pool);		obj_pool_free++;		obj_nr_tofree--;	} 	/*	 * Pool list is already full and there are still objs on the free	 * list. Move remaining free objs to a temporary list to free the	 * memory outside the pool_lock held region.	 */	if (obj_nr_tofree) {		hlist_move_list(&obj_to_free, &tofree);		debug_objects_freed += obj_nr_tofree;		obj_nr_tofree = 0;	}	raw_spin_unlock_irqrestore(&pool_lock, flags); 	hlist_for_each_entry_safe(obj, tmp, &tofree, node) {		hlist_del(&obj->node);		kmem_cache_free(obj_cache, obj);	}} static bool __free_object(struct debug_obj *obj){	unsigned long flags;	bool work; 	raw_spin_lock_irqsave(&pool_lock, flags);	work = (obj_pool_free > debug_objects_pool_size) && obj_cache;	obj_pool_used--; 	if (work) {		obj_nr_tofree++;		hlist_add_head(&obj->node, &obj_to_free);	} else {		obj_pool_free++;		hlist_add_head(&obj->node, &obj_pool);	}	raw_spin_unlock_irqrestore(&pool_lock, flags);	return work;} /* * Put the object back into the pool and schedule work to free objects * if necessary. */static void free_object(struct debug_obj *obj){	if (__free_object(obj))		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 *tmp;	HLIST_HEAD(freelist);	struct debug_obj *obj;	unsigned long flags;	int i; 	pr_warn("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, 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 booldebug_object_fixup(bool (*fixup)(void *addr, enum debug_obj_state state),		   void * addr, enum debug_obj_state state){	if (fixup && fixup(addr, state)) {		debug_objects_fixups++;		return true;	}	return false;} 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)		pr_warn("object %p is on stack %p, but NOT annotated.\n", addr,			 task_stack_page(current));	else		pr_warn("object %p is NOT on stack %p, but annotated.\n", addr,			 task_stack_page(current)); 	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);}EXPORT_SYMBOL_GPL(debug_object_init); /** * 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);}EXPORT_SYMBOL_GPL(debug_object_init_on_stack); /** * debug_object_activate - debug checks when an object is activated * @addr:	address of the object * @descr:	pointer to an object specific debug description structure * Returns 0 for success, -EINVAL for check failed. */int 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;	int ret;	struct debug_obj o = { .object = addr,			       .state = ODEBUG_STATE_NOTAVAILABLE,			       .descr = descr }; 	if (!debug_objects_enabled)		return 0; 	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;			ret = 0;			break; 		case ODEBUG_STATE_ACTIVE:			debug_print_object(obj, "activate");			state = obj->state;			raw_spin_unlock_irqrestore(&db->lock, flags);			ret = debug_object_fixup(descr->fixup_activate, addr, state);			return ret ? 0 : -EINVAL; 		case ODEBUG_STATE_DESTROYED:			debug_print_object(obj, "activate");			ret = -EINVAL;			break;		default:			ret = 0;			break;		}		raw_spin_unlock_irqrestore(&db->lock, flags);		return ret;	}

Lines 1–500 of 1201.