📄 debugobjects.c
字号:
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 + -