1089 lines · 26.2 KB · C
RawDownload
	db = get_bucket((unsigned long) addr); 	raw_spin_lock_irqsave(&db->lock, flags); 	obj = lookup_object(addr, db);	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;		raw_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:	raw_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); 	raw_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;		raw_spin_unlock_irqrestore(&db->lock, flags);		debug_object_fixup(descr->fixup_free, addr, state);		return;	default:		hlist_del(&obj->node);		raw_spin_unlock_irqrestore(&db->lock, flags);		free_object(obj);		return;	}out_unlock:	raw_spin_unlock_irqrestore(&db->lock, flags);} /** * debug_object_assert_init - debug checks when object should be init-ed * @addr:	address of the object * @descr:	pointer to an object specific debug description structure */void debug_object_assert_init(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) {		struct debug_obj o = { .object = addr,				       .state = ODEBUG_STATE_NOTAVAILABLE,				       .descr = descr }; 		raw_spin_unlock_irqrestore(&db->lock, flags);		/*		 * Maybe the object is static.  Let the type specific		 * code decide what to do.		 */		if (debug_object_fixup(descr->fixup_assert_init, addr,				       ODEBUG_STATE_NOTAVAILABLE))			debug_print_object(&o, "assert_init");		return;	} 	raw_spin_unlock_irqrestore(&db->lock, flags);} /** * debug_object_active_state - debug checks object usage state machine * @addr:	address of the object * @descr:	pointer to an object specific debug description structure * @expect:	expected state * @next:	state to move to if expected state is found */voiddebug_object_active_state(void *addr, struct debug_obj_descr *descr,			  unsigned int expect, unsigned int next){	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_ACTIVE:			if (obj->astate == expect)				obj->astate = next;			else				debug_print_object(obj, "active_state");			break; 		default:			debug_print_object(obj, "active_state");			break;		}	} else {		struct debug_obj o = { .object = addr,				       .state = ODEBUG_STATE_NOTAVAILABLE,				       .descr = descr }; 		debug_print_object(&o, "active_state");	} 	raw_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;		raw_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;				raw_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;			}		}		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);		} 		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_FS static 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);			return 0;		}		return 1; 	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 int __initcheck_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); 	raw_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:	raw_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){

Lines 501–1000 of 1089. Previous lines