⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 debugobjects.c

📁 Lib files of linux kernel
💻 C
📖 第 1 页 / 共 2 页
字号:
	if (!obj)		goto out_unlock;	switch (obj->state) {	case ODEBUG_STATE_NONE:	case ODEBUG_STATE_INIT:	case ODEBUG_STATE_INACTIVE:		obj->state = ODEBUG_STATE_DESTROYED;		break;	case ODEBUG_STATE_ACTIVE:		debug_print_object(obj, "destroy");		state = obj->state;		spin_unlock_irqrestore(&db->lock, flags);		debug_object_fixup(descr->fixup_destroy, addr, state);		return;	case ODEBUG_STATE_DESTROYED:		debug_print_object(obj, "destroy");		break;	default:		break;	}out_unlock:	spin_unlock_irqrestore(&db->lock, flags);}/** * debug_object_free - debug checks when an object is freed * @addr:	address of the object * @descr:	pointer to an object specific debug description structure */void debug_object_free(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);	spin_lock_irqsave(&db->lock, flags);	obj = lookup_object(addr, db);	if (!obj)		goto out_unlock;	switch (obj->state) {	case ODEBUG_STATE_ACTIVE:		debug_print_object(obj, "free");		state = obj->state;		spin_unlock_irqrestore(&db->lock, flags);		debug_object_fixup(descr->fixup_free, addr, state);		return;	default:		hlist_del(&obj->node);		spin_unlock_irqrestore(&db->lock, flags);		free_object(obj);		return;	}out_unlock:	spin_unlock_irqrestore(&db->lock, flags);}#ifdef CONFIG_DEBUG_OBJECTS_FREEstatic void __debug_check_no_obj_freed(const void *address, unsigned long size){	unsigned long flags, oaddr, saddr, eaddr, paddr, chunks;	struct hlist_node *node, *tmp;	HLIST_HEAD(freelist);	struct debug_obj_descr *descr;	enum debug_obj_state state;	struct debug_bucket *db;	struct debug_obj *obj;	int cnt;	saddr = (unsigned long) address;	eaddr = saddr + size;	paddr = saddr & ODEBUG_CHUNK_MASK;	chunks = ((eaddr - paddr) + (ODEBUG_CHUNK_SIZE - 1));	chunks >>= ODEBUG_CHUNK_SHIFT;	for (;chunks > 0; chunks--, paddr += ODEBUG_CHUNK_SIZE) {		db = get_bucket(paddr);repeat:		cnt = 0;		spin_lock_irqsave(&db->lock, flags);		hlist_for_each_entry_safe(obj, node, tmp, &db->list, node) {			cnt++;			oaddr = (unsigned long) obj->object;			if (oaddr < saddr || oaddr >= eaddr)				continue;			switch (obj->state) {			case ODEBUG_STATE_ACTIVE:				debug_print_object(obj, "free");				descr = obj->descr;				state = obj->state;				spin_unlock_irqrestore(&db->lock, flags);				debug_object_fixup(descr->fixup_free,						   (void *) oaddr, state);				goto repeat;			default:				hlist_del(&obj->node);				hlist_add_head(&obj->node, &freelist);				break;			}		}		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);		}		if (cnt > debug_objects_maxchain)			debug_objects_maxchain = cnt;	}}void debug_check_no_obj_freed(const void *address, unsigned long size){	if (debug_objects_enabled)		__debug_check_no_obj_freed(address, size);}#endif#ifdef CONFIG_DEBUG_FSstatic int debug_stats_show(struct seq_file *m, void *v){	seq_printf(m, "max_chain     :%d\n", debug_objects_maxchain);	seq_printf(m, "warnings      :%d\n", debug_objects_warnings);	seq_printf(m, "fixups        :%d\n", debug_objects_fixups);	seq_printf(m, "pool_free     :%d\n", obj_pool_free);	seq_printf(m, "pool_min_free :%d\n", obj_pool_min_free);	seq_printf(m, "pool_used     :%d\n", obj_pool_used);	seq_printf(m, "pool_max_used :%d\n", obj_pool_max_used);	return 0;}static int debug_stats_open(struct inode *inode, struct file *filp){	return single_open(filp, debug_stats_show, NULL);}static const struct file_operations debug_stats_fops = {	.open		= debug_stats_open,	.read		= seq_read,	.llseek		= seq_lseek,	.release	= single_release,};static int __init debug_objects_init_debugfs(void){	struct dentry *dbgdir, *dbgstats;	if (!debug_objects_enabled)		return 0;	dbgdir = debugfs_create_dir("debug_objects", NULL);	if (!dbgdir)		return -ENOMEM;	dbgstats = debugfs_create_file("stats", 0444, dbgdir, NULL,				       &debug_stats_fops);	if (!dbgstats)		goto err;	return 0;err:	debugfs_remove(dbgdir);	return -ENOMEM;}__initcall(debug_objects_init_debugfs);#elsestatic inline void debug_objects_init_debugfs(void) { }#endif#ifdef CONFIG_DEBUG_OBJECTS_SELFTEST/* Random data structure for the self test */struct self_test {	unsigned long	dummy1[6];	int		static_init;	unsigned long	dummy2[3];};static __initdata struct debug_obj_descr descr_type_test;/* * fixup_init is called when: * - an active object is initialized */static int __init fixup_init(void *addr, enum debug_obj_state state){	struct self_test *obj = addr;	switch (state) {	case ODEBUG_STATE_ACTIVE:		debug_object_deactivate(obj, &descr_type_test);		debug_object_init(obj, &descr_type_test);		return 1;	default:		return 0;	}}/* * fixup_activate is called when: * - an active object is activated * - an unknown object is activated (might be a statically initialized object) */static int __init fixup_activate(void *addr, enum debug_obj_state state){	struct self_test *obj = addr;	switch (state) {	case ODEBUG_STATE_NOTAVAILABLE:		if (obj->static_init == 1) {			debug_object_init(obj, &descr_type_test);			debug_object_activate(obj, &descr_type_test);			/*			 * Real code should return 0 here ! This is			 * not a fixup of some bad behaviour. We			 * merily call the debug_init function to keep			 * track of the object.			 */			return 1;		} else {			/* Real code needs to emit a warning here */		}		return 0;	case ODEBUG_STATE_ACTIVE:		debug_object_deactivate(obj, &descr_type_test);		debug_object_activate(obj, &descr_type_test);		return 1;	default:		return 0;	}}/* * fixup_destroy is called when: * - an active object is destroyed */static int __init fixup_destroy(void *addr, enum debug_obj_state state){	struct self_test *obj = addr;	switch (state) {	case ODEBUG_STATE_ACTIVE:		debug_object_deactivate(obj, &descr_type_test);		debug_object_destroy(obj, &descr_type_test);		return 1;	default:		return 0;	}}/* * fixup_free is called when: * - an active object is freed */static int __init fixup_free(void *addr, enum debug_obj_state state){	struct self_test *obj = addr;	switch (state) {	case ODEBUG_STATE_ACTIVE:		debug_object_deactivate(obj, &descr_type_test);		debug_object_free(obj, &descr_type_test);		return 1;	default:		return 0;	}}static intcheck_results(void *addr, enum debug_obj_state state, int fixups, int warnings){	struct debug_bucket *db;	struct debug_obj *obj;	unsigned long flags;	int res = -EINVAL;	db = get_bucket((unsigned long) addr);	spin_lock_irqsave(&db->lock, flags);	obj = lookup_object(addr, db);	if (!obj && state != ODEBUG_STATE_NONE) {		WARN(1, KERN_ERR "ODEBUG: selftest object not found\n");		goto out;	}	if (obj && obj->state != state) {		WARN(1, KERN_ERR "ODEBUG: selftest wrong state: %d != %d\n",		       obj->state, state);		goto out;	}	if (fixups != debug_objects_fixups) {		WARN(1, KERN_ERR "ODEBUG: selftest fixups failed %d != %d\n",		       fixups, debug_objects_fixups);		goto out;	}	if (warnings != debug_objects_warnings) {		WARN(1, KERN_ERR "ODEBUG: selftest warnings failed %d != %d\n",		       warnings, debug_objects_warnings);		goto out;	}	res = 0;out:	spin_unlock_irqrestore(&db->lock, flags);	if (res)		debug_objects_enabled = 0;	return res;}static __initdata struct debug_obj_descr descr_type_test = {	.name			= "selftest",	.fixup_init		= fixup_init,	.fixup_activate		= fixup_activate,	.fixup_destroy		= fixup_destroy,	.fixup_free		= fixup_free,};static __initdata struct self_test obj = { .static_init = 0 };static void __init debug_objects_selftest(void){	int fixups, oldfixups, warnings, oldwarnings;	unsigned long flags;	local_irq_save(flags);	fixups = oldfixups = debug_objects_fixups;	warnings = oldwarnings = debug_objects_warnings;	descr_test = &descr_type_test;	debug_object_init(&obj, &descr_type_test);	if (check_results(&obj, ODEBUG_STATE_INIT, fixups, warnings))		goto out;	debug_object_activate(&obj, &descr_type_test);	if (check_results(&obj, ODEBUG_STATE_ACTIVE, fixups, warnings))		goto out;	debug_object_activate(&obj, &descr_type_test);	if (check_results(&obj, ODEBUG_STATE_ACTIVE, ++fixups, ++warnings))		goto out;	debug_object_deactivate(&obj, &descr_type_test);	if (check_results(&obj, ODEBUG_STATE_INACTIVE, fixups, warnings))		goto out;	debug_object_destroy(&obj, &descr_type_test);	if (check_results(&obj, ODEBUG_STATE_DESTROYED, fixups, warnings))		goto out;	debug_object_init(&obj, &descr_type_test);	if (check_results(&obj, ODEBUG_STATE_DESTROYED, fixups, ++warnings))		goto out;	debug_object_activate(&obj, &descr_type_test);	if (check_results(&obj, ODEBUG_STATE_DESTROYED, fixups, ++warnings))		goto out;	debug_object_deactivate(&obj, &descr_type_test);	if (check_results(&obj, ODEBUG_STATE_DESTROYED, fixups, ++warnings))		goto out;	debug_object_free(&obj, &descr_type_test);	if (check_results(&obj, ODEBUG_STATE_NONE, fixups, warnings))		goto out;	obj.static_init = 1;	debug_object_activate(&obj, &descr_type_test);	if (check_results(&obj, ODEBUG_STATE_ACTIVE, ++fixups, warnings))		goto out;	debug_object_init(&obj, &descr_type_test);	if (check_results(&obj, ODEBUG_STATE_INIT, ++fixups, ++warnings))		goto out;	debug_object_free(&obj, &descr_type_test);	if (check_results(&obj, ODEBUG_STATE_NONE, fixups, warnings))		goto out;#ifdef CONFIG_DEBUG_OBJECTS_FREE	debug_object_init(&obj, &descr_type_test);	if (check_results(&obj, ODEBUG_STATE_INIT, fixups, warnings))		goto out;	debug_object_activate(&obj, &descr_type_test);	if (check_results(&obj, ODEBUG_STATE_ACTIVE, fixups, warnings))		goto out;	__debug_check_no_obj_freed(&obj, sizeof(obj));	if (check_results(&obj, ODEBUG_STATE_NONE, ++fixups, ++warnings))		goto out;#endif	printk(KERN_INFO "ODEBUG: selftest passed\n");out:	debug_objects_fixups = oldfixups;	debug_objects_warnings = oldwarnings;	descr_test = NULL;	local_irq_restore(flags);}#elsestatic inline void debug_objects_selftest(void) { }#endif/* * Called during early boot to initialize the hash buckets and link * the static object pool objects into the poll list. After this call * the object tracker is fully operational. */void __init debug_objects_early_init(void){	int i;	for (i = 0; i < ODEBUG_HASH_SIZE; i++)		spin_lock_init(&obj_hash[i].lock);	for (i = 0; i < ODEBUG_POOL_SIZE; i++)		hlist_add_head(&obj_static_pool[i].node, &obj_pool);}/* * Called after the kmem_caches are functional to setup a dedicated * cache pool, which has the SLAB_DEBUG_OBJECTS flag set. This flag * prevents that the debug code is called on kmem_cache_free() for the * debug tracker objects to avoid recursive calls. */void __init debug_objects_mem_init(void){	if (!debug_objects_enabled)		return;	obj_cache = kmem_cache_create("debug_objects_cache",				      sizeof (struct debug_obj), 0,				      SLAB_DEBUG_OBJECTS, NULL);	if (!obj_cache)		debug_objects_enabled = 0;	else		debug_objects_selftest();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -