1377 lines · 34.6 KB · C
RawDownload
 #ifdef CONFIG_DEBUG_FS static int debug_stats_show(struct seq_file *m, void *v){	int cpu, obj_percpu_free = 0; 	for_each_possible_cpu(cpu)		obj_percpu_free += per_cpu(percpu_obj_pool.obj_free, cpu); 	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     :%d\n", READ_ONCE(obj_pool_free) + obj_percpu_free);	seq_printf(m, "pool_pcp_free :%d\n", obj_percpu_free);	seq_printf(m, "pool_min_free :%d\n", obj_pool_min_free);	seq_printf(m, "pool_used     :%d\n", obj_pool_used - obj_percpu_free);	seq_printf(m, "pool_max_used :%d\n", obj_pool_max_used);	seq_printf(m, "on_free_list  :%d\n", READ_ONCE(obj_nr_tofree));	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 __initdata struct debug_obj_descr descr_type_test; static 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 = 0;	return res;} static __initdata 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 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	pr_info("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++)		raw_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);} /* * Convert the statically allocated objects to dynamic ones: */static int __init debug_objects_replace_static_objects(void){	struct debug_bucket *db = obj_hash;	struct hlist_node *tmp;	struct debug_obj *obj, *new;	HLIST_HEAD(objects);	int i, cnt = 0; 	for (i = 0; i < ODEBUG_POOL_SIZE; i++) {		obj = kmem_cache_zalloc(obj_cache, GFP_KERNEL);		if (!obj)			goto free;		hlist_add_head(&obj->node, &objects);	} 	/*	 * debug_objects_mem_init() is now called early that only one CPU is up	 * and interrupts have been disabled, so it is safe to replace the	 * active object references.	 */ 	/* Remove the statically allocated objects from the pool */	hlist_for_each_entry_safe(obj, tmp, &obj_pool, node)		hlist_del(&obj->node);	/* Move the allocated objects to the pool */	hlist_move_list(&objects, &obj_pool); 	/* Replace the active object references */	for (i = 0; i < ODEBUG_HASH_SIZE; i++, db++) {		hlist_move_list(&db->list, &objects); 		hlist_for_each_entry(obj, &objects, node) {			new = hlist_entry(obj_pool.first, typeof(*obj), node);			hlist_del(&new->node);			/* copy object data */			*new = *obj;			hlist_add_head(&new->node, &db->list);			cnt++;		}	} 	pr_debug("%d of %d active objects replaced\n",		 cnt, obj_pool_used);	return 0;free:	hlist_for_each_entry_safe(obj, tmp, &objects, node) {		hlist_del(&obj->node);		kmem_cache_free(obj_cache, obj);	}	return -ENOMEM;} /* * 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){	int cpu, extras; 	if (!debug_objects_enabled)		return; 	/*	 * Initialize the percpu object pools	 *	 * Initialization is not strictly necessary, but was done for	 * completeness.	 */	for_each_possible_cpu(cpu)		INIT_HLIST_HEAD(&per_cpu(percpu_obj_pool.free_objs, cpu)); 	obj_cache = kmem_cache_create("debug_objects_cache",				      sizeof (struct debug_obj), 0,				      SLAB_DEBUG_OBJECTS | SLAB_NOLEAKTRACE,				      NULL); 	if (!obj_cache || debug_objects_replace_static_objects()) {		debug_objects_enabled = 0;		kmem_cache_destroy(obj_cache);		pr_warn("out of memory.\n");	} else		debug_objects_selftest(); 	/*	 * Increase the thresholds for allocating and freeing objects	 * according to the number of possible CPUs available in the system.	 */	extras = num_possible_cpus() * ODEBUG_BATCH_SIZE;	debug_objects_pool_size += extras;	debug_objects_pool_min_level += extras;}

Lines 1001–1377 of 1377. Previous lines