1585 lines · 39.7 KB · C
RawDownload
	raw_spin_unlock_irqrestore(&db->lock, flags);	debug_print_object(&o, "destroy"); 	if (o.state == ODEBUG_STATE_ACTIVE)		debug_object_fixup(descr->fixup_destroy, addr, o.state);}EXPORT_SYMBOL_GPL(debug_object_destroy); /** * 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, const struct debug_obj_descr *descr){	struct debug_obj *obj, o;	struct debug_bucket *db;	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) {		raw_spin_unlock_irqrestore(&db->lock, flags);		return;	} 	switch (obj->state) {	case ODEBUG_STATE_ACTIVE:		break;	default:		hlist_del(&obj->node);		raw_spin_unlock_irqrestore(&db->lock, flags);		free_object(obj);		return;	} 	o = *obj;	raw_spin_unlock_irqrestore(&db->lock, flags);	debug_print_object(&o, "free"); 	debug_object_fixup(descr->fixup_free, addr, o.state);}EXPORT_SYMBOL_GPL(debug_object_free); /** * 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, const struct debug_obj_descr *descr){	struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr };	struct debug_bucket *db;	struct debug_obj *obj;	unsigned long flags; 	if (!debug_objects_enabled)		return; 	debug_objects_fill_pool(); 	db = get_bucket((unsigned long) addr); 	raw_spin_lock_irqsave(&db->lock, flags);	obj = lookup_object_or_alloc(addr, db, descr, false, true);	raw_spin_unlock_irqrestore(&db->lock, flags);	if (!IS_ERR_OR_NULL(obj))		return; 	/* If NULL the allocation has hit OOM */	if (!obj) {		debug_objects_oom();		return;	} 	/*	 * lookup_object_or_alloc() might have raced with a concurrent	 * allocation failure which disabled debug objects. Don't run the fixup	 * as it might turn a valid object useless. See for example	 * hrtimer_fixup_assert_init().	 */	if (!debug_objects_enabled)		return; 	/* Object is neither tracked nor static. It's not initialized. */	debug_print_object(&o, "assert_init");	debug_object_fixup(descr->fixup_assert_init, addr, ODEBUG_STATE_NOTAVAILABLE);}EXPORT_SYMBOL_GPL(debug_object_assert_init); /** * 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, const struct debug_obj_descr *descr,			  unsigned int expect, unsigned int next){	struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .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_ACTIVE:			if (obj->astate != expect)				break;			obj->astate = next;			raw_spin_unlock_irqrestore(&db->lock, flags);			return;		default:			break;		}		o = *obj;	} 	raw_spin_unlock_irqrestore(&db->lock, flags);	debug_print_object(&o, "active_state");}EXPORT_SYMBOL_GPL(debug_object_active_state); #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;	int cnt, objs_checked = 0;	struct debug_obj *obj, o;	struct debug_bucket *db;	struct hlist_node *tmp; 	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, tmp, &db->list, node) {			cnt++;			oaddr = (unsigned long) obj->object;			if (oaddr < saddr || oaddr >= eaddr)				continue; 			switch (obj->state) {			case ODEBUG_STATE_ACTIVE:				o = *obj;				raw_spin_unlock_irqrestore(&db->lock, flags);				debug_print_object(&o, "free");				debug_object_fixup(o.descr->fixup_free, (void *)oaddr, o.state);				goto repeat;			default:				hlist_del(&obj->node);				__free_object(obj);				break;			}		}		raw_spin_unlock_irqrestore(&db->lock, flags); 		if (cnt > debug_objects_maxchain)			debug_objects_maxchain = cnt; 		objs_checked += cnt;	} 	if (objs_checked > debug_objects_maxchecked)		debug_objects_maxchecked = objs_checked; 	/* Schedule work to actually kmem_cache_free() objects */	if (!READ_ONCE(obj_freeing) && pool_count(&pool_to_free)) {		WRITE_ONCE(obj_freeing, true);		schedule_delayed_work(&debug_obj_work, ODEBUG_FREE_WORK_DELAY);	}} 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){	unsigned int cpu, pool_used, pcp_free = 0; 	/*	 * pool_global.stats.cur_used is the number of batches currently	 * handed out to per CPU pools. Convert it to number of objects	 * and subtract the number of free objects in the per CPU pools.	 * As this is lockless the number is an estimate.	 */	for_each_possible_cpu(cpu)		pcp_free += per_cpu(pool_pcpu.cnt, cpu); 	pool_used = READ_ONCE(pool_global.stats.cur_used);	pcp_free = min(pool_used, pcp_free);	pool_used -= pcp_free; 	seq_printf(m, "max_chain     : %d\n", debug_objects_maxchain);	seq_printf(m, "max_checked   : %d\n", debug_objects_maxchecked);	seq_printf(m, "warnings      : %d\n", debug_objects_warnings);	seq_printf(m, "fixups        : %d\n", debug_objects_fixups);	seq_printf(m, "pool_free     : %u\n", pool_count(&pool_global) + pcp_free);	seq_printf(m, "pool_pcp_free : %u\n", pcp_free);	seq_printf(m, "pool_min_free : %u\n", data_race(pool_global.stats.min_fill));	seq_printf(m, "pool_used     : %u\n", pool_used);	seq_printf(m, "pool_max_used : %u\n", data_race(pool_global.stats.max_used));	seq_printf(m, "on_free_list  : %u\n", pool_count(&pool_to_free));	seq_printf(m, "objs_allocated: %d\n", debug_objects_allocated);	seq_printf(m, "objs_freed    : %d\n", debug_objects_freed);	return 0;}DEFINE_SHOW_ATTRIBUTE(debug_stats); static int __init debug_objects_init_debugfs(void){	struct dentry *dbgdir; 	if (!debug_objects_enabled)		return 0; 	dbgdir = debugfs_create_dir("debug_objects", NULL); 	debugfs_create_file("stats", 0444, dbgdir, NULL, &debug_stats_fops); 	return 0;}__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 __initconst const struct debug_obj_descr descr_type_test; static __noipa bool __init is_static_object(void *addr){	struct self_test *obj = addr; 	return obj->static_init;} /* * fixup_init is called when: * - an active object is initialized */static bool __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 true;	default:		return false;	}} /* * fixup_activate is called when: * - an active object is activated * - an unknown non-static object is activated */static bool __init fixup_activate(void *addr, enum debug_obj_state state){	struct self_test *obj = addr; 	switch (state) {	case ODEBUG_STATE_NOTAVAILABLE:		return true;	case ODEBUG_STATE_ACTIVE:		debug_object_deactivate(obj, &descr_type_test);		debug_object_activate(obj, &descr_type_test);		return true; 	default:		return false;	}} /* * fixup_destroy is called when: * - an active object is destroyed */static bool __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 true;	default:		return false;	}} /* * fixup_free is called when: * - an active object is freed */static bool __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 true;	default:		return false;	}} 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 = false;	return res;} static __initconst const struct debug_obj_descr descr_type_test = {	.name			= "selftest",	.is_static_object	= is_static_object,	.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 bool __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	pr_info("selftest passed\n"); out:	debug_objects_fixups = oldfixups;	debug_objects_warnings = oldwarnings;	descr_test = NULL; 	local_irq_restore(flags);	return debug_objects_enabled;}#elsestatic inline bool debug_objects_selftest(void) { return true; }#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++)		raw_spin_lock_init(&obj_hash[i].lock); 	/* Keep early boot simple and add everything to the boot list */	for (i = 0; i < ODEBUG_POOL_SIZE; i++)		hlist_add_head(&obj_static_pool[i].node, &pool_boot);} /* * Convert the statically allocated objects to dynamic ones. * debug_objects_mem_init() is called early so only one CPU is up and * interrupts are disabled, which means it is safe to replace the active * object references.

Lines 1001–1500 of 1585. Previous lines