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 Load more
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 */ void debug_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_FREE static 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); #else static 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 __init check_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; } #else static 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.