if (fixup && fixup(addr, state)) { debug_objects_fixups++; return true; } return false;} static void debug_object_is_on_stack(void *addr, int onstack){ int is_on_stack; static int limit; if (limit > 4) return; is_on_stack = object_is_on_stack(addr); if (is_on_stack == onstack) return; limit++; if (is_on_stack) pr_warn("object %p is on stack %p, but NOT annotated.\n", addr, task_stack_page(current)); else pr_warn("object %p is NOT on stack %p, but annotated.\n", addr, task_stack_page(current)); WARN_ON(1);} static void__debug_object_init(void *addr, struct debug_obj_descr *descr, int onstack){ enum debug_obj_state state; bool check_stack = false; struct debug_bucket *db; struct debug_obj *obj; unsigned long flags; fill_pool(); db = get_bucket((unsigned long) addr); raw_spin_lock_irqsave(&db->lock, flags); obj = lookup_object(addr, db); if (!obj) { obj = alloc_object(addr, db, descr); if (!obj) { debug_objects_enabled = 0; raw_spin_unlock_irqrestore(&db->lock, flags); debug_objects_oom(); return; } check_stack = true; } switch (obj->state) { case ODEBUG_STATE_NONE: case ODEBUG_STATE_INIT: case ODEBUG_STATE_INACTIVE: obj->state = ODEBUG_STATE_INIT; break; case ODEBUG_STATE_ACTIVE: state = obj->state; raw_spin_unlock_irqrestore(&db->lock, flags); debug_print_object(obj, "init"); debug_object_fixup(descr->fixup_init, addr, state); return; case ODEBUG_STATE_DESTROYED: raw_spin_unlock_irqrestore(&db->lock, flags); debug_print_object(obj, "init"); return; default: break; } raw_spin_unlock_irqrestore(&db->lock, flags); if (check_stack) debug_object_is_on_stack(addr, onstack);} /** * debug_object_init - debug checks when an object is initialized * @addr: address of the object * @descr: pointer to an object specific debug description structure */void debug_object_init(void *addr, struct debug_obj_descr *descr){ if (!debug_objects_enabled) return; __debug_object_init(addr, descr, 0);}EXPORT_SYMBOL_GPL(debug_object_init); /** * debug_object_init_on_stack - debug checks when an object on stack is * initialized * @addr: address of the object * @descr: pointer to an object specific debug description structure */void debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr){ if (!debug_objects_enabled) return; __debug_object_init(addr, descr, 1);}EXPORT_SYMBOL_GPL(debug_object_init_on_stack); /** * debug_object_activate - debug checks when an object is activated * @addr: address of the object * @descr: pointer to an object specific debug description structure * Returns 0 for success, -EINVAL for check failed. */int debug_object_activate(void *addr, struct debug_obj_descr *descr){ enum debug_obj_state state; struct debug_bucket *db; struct debug_obj *obj; unsigned long flags; int ret; struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr }; if (!debug_objects_enabled) return 0; db = get_bucket((unsigned long) addr); raw_spin_lock_irqsave(&db->lock, flags); obj = lookup_object(addr, db); if (obj) { bool print_object = false; switch (obj->state) { case ODEBUG_STATE_INIT: case ODEBUG_STATE_INACTIVE: obj->state = ODEBUG_STATE_ACTIVE; ret = 0; break; case ODEBUG_STATE_ACTIVE: state = obj->state; raw_spin_unlock_irqrestore(&db->lock, flags); debug_print_object(obj, "activate"); ret = debug_object_fixup(descr->fixup_activate, addr, state); return ret ? 0 : -EINVAL; case ODEBUG_STATE_DESTROYED: print_object = true; ret = -EINVAL; break; default: ret = 0; break; } raw_spin_unlock_irqrestore(&db->lock, flags); if (print_object) debug_print_object(obj, "activate"); return ret; } raw_spin_unlock_irqrestore(&db->lock, flags); /* * We are here when a static object is activated. We * let the type specific code confirm whether this is * true or not. if true, we just make sure that the * static object is tracked in the object tracker. If * not, this must be a bug, so we try to fix it up. */ if (descr->is_static_object && descr->is_static_object(addr)) { /* track this static object */ debug_object_init(addr, descr); debug_object_activate(addr, descr); } else { debug_print_object(&o, "activate"); ret = debug_object_fixup(descr->fixup_activate, addr, ODEBUG_STATE_NOTAVAILABLE); return ret ? 0 : -EINVAL; } return 0;}EXPORT_SYMBOL_GPL(debug_object_activate); /** * debug_object_deactivate - debug checks when an object is deactivated * @addr: address of the object * @descr: pointer to an object specific debug description structure */void debug_object_deactivate(void *addr, struct debug_obj_descr *descr){ struct debug_bucket *db; struct debug_obj *obj; unsigned long flags; bool print_object = false; 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_INIT: case ODEBUG_STATE_INACTIVE: case ODEBUG_STATE_ACTIVE: if (!obj->astate) obj->state = ODEBUG_STATE_INACTIVE; else print_object = true; break; case ODEBUG_STATE_DESTROYED: print_object = true; break; default: break; } } raw_spin_unlock_irqrestore(&db->lock, flags); if (!obj) { struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr }; debug_print_object(&o, "deactivate"); } else if (print_object) { debug_print_object(obj, "deactivate"); }}EXPORT_SYMBOL_GPL(debug_object_deactivate); /** * debug_object_destroy - debug checks when an object is destroyed * @addr: address of the object * @descr: pointer to an object specific debug description structure */void debug_object_destroy(void *addr, struct debug_obj_descr *descr){ enum debug_obj_state state; struct debug_bucket *db; struct debug_obj *obj; unsigned long flags; bool print_object = false; 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_NONE: case ODEBUG_STATE_INIT: case ODEBUG_STATE_INACTIVE: obj->state = ODEBUG_STATE_DESTROYED; break; case ODEBUG_STATE_ACTIVE: state = obj->state; raw_spin_unlock_irqrestore(&db->lock, flags); debug_print_object(obj, "destroy"); debug_object_fixup(descr->fixup_destroy, addr, state); return; case ODEBUG_STATE_DESTROYED: print_object = true; break; default: break; }out_unlock: raw_spin_unlock_irqrestore(&db->lock, flags); if (print_object) debug_print_object(obj, "destroy");}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, 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: state = obj->state; raw_spin_unlock_irqrestore(&db->lock, flags); debug_print_object(obj, "free"); 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);}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, 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, and we let the type specific * code confirm. Track this static object if true, else invoke * fixup. */ if (descr->is_static_object && descr->is_static_object(addr)) { /* Track this static object */ debug_object_init(addr, descr); } else { debug_print_object(&o, "assert_init"); debug_object_fixup(descr->fixup_assert_init, addr, ODEBUG_STATE_NOTAVAILABLE); } return; } raw_spin_unlock_irqrestore(&db->lock, flags);}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, struct debug_obj_descr *descr, unsigned int expect, unsigned int next){ struct debug_bucket *db; struct debug_obj *obj; unsigned long flags; bool print_object = false; 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 print_object = true; break; default: print_object = true; break; } } raw_spin_unlock_irqrestore(&db->lock, flags); if (!obj) { struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr }; debug_print_object(&o, "active_state"); } else if (print_object) { debug_print_object(obj, "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; struct debug_obj_descr *descr; enum debug_obj_state state; struct debug_bucket *db; struct hlist_node *tmp; struct debug_obj *obj; int cnt, objs_checked = 0; 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: descr = obj->descr; state = obj->state; raw_spin_unlock_irqrestore(&db->lock, flags); debug_print_object(obj, "free"); debug_object_fixup(descr->fixup_free, (void *) oaddr, 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) && READ_ONCE(obj_nr_tofree)) { 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);}#endifLines 501–1000 of 1377. Previous lines Load more
if (fixup && fixup(addr, state)) { debug_objects_fixups++; return true; } return false; } static void debug_object_is_on_stack(void *addr, int onstack) { int is_on_stack; static int limit; if (limit > 4) return; is_on_stack = object_is_on_stack(addr); if (is_on_stack == onstack) return; limit++; if (is_on_stack) pr_warn("object %p is on stack %p, but NOT annotated.\n", addr, task_stack_page(current)); else pr_warn("object %p is NOT on stack %p, but annotated.\n", addr, task_stack_page(current)); WARN_ON(1); } static void __debug_object_init(void *addr, struct debug_obj_descr *descr, int onstack) { enum debug_obj_state state; bool check_stack = false; struct debug_bucket *db; struct debug_obj *obj; unsigned long flags; fill_pool(); db = get_bucket((unsigned long) addr); raw_spin_lock_irqsave(&db->lock, flags); obj = lookup_object(addr, db); if (!obj) { obj = alloc_object(addr, db, descr); if (!obj) { debug_objects_enabled = 0; raw_spin_unlock_irqrestore(&db->lock, flags); debug_objects_oom(); return; } check_stack = true; } switch (obj->state) { case ODEBUG_STATE_NONE: case ODEBUG_STATE_INIT: case ODEBUG_STATE_INACTIVE: obj->state = ODEBUG_STATE_INIT; break; case ODEBUG_STATE_ACTIVE: state = obj->state; raw_spin_unlock_irqrestore(&db->lock, flags); debug_print_object(obj, "init"); debug_object_fixup(descr->fixup_init, addr, state); return; case ODEBUG_STATE_DESTROYED: raw_spin_unlock_irqrestore(&db->lock, flags); debug_print_object(obj, "init"); return; default: break; } raw_spin_unlock_irqrestore(&db->lock, flags); if (check_stack) debug_object_is_on_stack(addr, onstack); } /** * debug_object_init - debug checks when an object is initialized * @addr: address of the object * @descr: pointer to an object specific debug description structure */ void debug_object_init(void *addr, struct debug_obj_descr *descr) { if (!debug_objects_enabled) return; __debug_object_init(addr, descr, 0); } EXPORT_SYMBOL_GPL(debug_object_init); /** * debug_object_init_on_stack - debug checks when an object on stack is * initialized * @addr: address of the object * @descr: pointer to an object specific debug description structure */ void debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr) { if (!debug_objects_enabled) return; __debug_object_init(addr, descr, 1); } EXPORT_SYMBOL_GPL(debug_object_init_on_stack); /** * debug_object_activate - debug checks when an object is activated * @addr: address of the object * @descr: pointer to an object specific debug description structure * Returns 0 for success, -EINVAL for check failed. */ int debug_object_activate(void *addr, struct debug_obj_descr *descr) { enum debug_obj_state state; struct debug_bucket *db; struct debug_obj *obj; unsigned long flags; int ret; struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr }; if (!debug_objects_enabled) return 0; db = get_bucket((unsigned long) addr); raw_spin_lock_irqsave(&db->lock, flags); obj = lookup_object(addr, db); if (obj) { bool print_object = false; switch (obj->state) { case ODEBUG_STATE_INIT: case ODEBUG_STATE_INACTIVE: obj->state = ODEBUG_STATE_ACTIVE; ret = 0; break; case ODEBUG_STATE_ACTIVE: state = obj->state; raw_spin_unlock_irqrestore(&db->lock, flags); debug_print_object(obj, "activate"); ret = debug_object_fixup(descr->fixup_activate, addr, state); return ret ? 0 : -EINVAL; case ODEBUG_STATE_DESTROYED: print_object = true; ret = -EINVAL; break; default: ret = 0; break; } raw_spin_unlock_irqrestore(&db->lock, flags); if (print_object) debug_print_object(obj, "activate"); return ret; } raw_spin_unlock_irqrestore(&db->lock, flags); /* * We are here when a static object is activated. We * let the type specific code confirm whether this is * true or not. if true, we just make sure that the * static object is tracked in the object tracker. If * not, this must be a bug, so we try to fix it up. */ if (descr->is_static_object && descr->is_static_object(addr)) { /* track this static object */ debug_object_init(addr, descr); debug_object_activate(addr, descr); } else { debug_print_object(&o, "activate"); ret = debug_object_fixup(descr->fixup_activate, addr, ODEBUG_STATE_NOTAVAILABLE); return ret ? 0 : -EINVAL; } return 0; } EXPORT_SYMBOL_GPL(debug_object_activate); /** * debug_object_deactivate - debug checks when an object is deactivated * @addr: address of the object * @descr: pointer to an object specific debug description structure */ void debug_object_deactivate(void *addr, struct debug_obj_descr *descr) { struct debug_bucket *db; struct debug_obj *obj; unsigned long flags; bool print_object = false; 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_INIT: case ODEBUG_STATE_INACTIVE: case ODEBUG_STATE_ACTIVE: if (!obj->astate) obj->state = ODEBUG_STATE_INACTIVE; else print_object = true; break; case ODEBUG_STATE_DESTROYED: print_object = true; break; default: break; } } raw_spin_unlock_irqrestore(&db->lock, flags); if (!obj) { struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr }; debug_print_object(&o, "deactivate"); } else if (print_object) { debug_print_object(obj, "deactivate"); } } EXPORT_SYMBOL_GPL(debug_object_deactivate); /** * debug_object_destroy - debug checks when an object is destroyed * @addr: address of the object * @descr: pointer to an object specific debug description structure */ void debug_object_destroy(void *addr, struct debug_obj_descr *descr) { enum debug_obj_state state; struct debug_bucket *db; struct debug_obj *obj; unsigned long flags; bool print_object = false; 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_NONE: case ODEBUG_STATE_INIT: case ODEBUG_STATE_INACTIVE: obj->state = ODEBUG_STATE_DESTROYED; break; case ODEBUG_STATE_ACTIVE: state = obj->state; raw_spin_unlock_irqrestore(&db->lock, flags); debug_print_object(obj, "destroy"); debug_object_fixup(descr->fixup_destroy, addr, state); return; case ODEBUG_STATE_DESTROYED: print_object = true; break; default: break; } out_unlock: raw_spin_unlock_irqrestore(&db->lock, flags); if (print_object) debug_print_object(obj, "destroy"); } 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, 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: state = obj->state; raw_spin_unlock_irqrestore(&db->lock, flags); debug_print_object(obj, "free"); 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); } 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, 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, and we let the type specific * code confirm. Track this static object if true, else invoke * fixup. */ if (descr->is_static_object && descr->is_static_object(addr)) { /* Track this static object */ debug_object_init(addr, descr); } else { debug_print_object(&o, "assert_init"); debug_object_fixup(descr->fixup_assert_init, addr, ODEBUG_STATE_NOTAVAILABLE); } return; } raw_spin_unlock_irqrestore(&db->lock, flags); } 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, struct debug_obj_descr *descr, unsigned int expect, unsigned int next) { struct debug_bucket *db; struct debug_obj *obj; unsigned long flags; bool print_object = false; 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 print_object = true; break; default: print_object = true; break; } } raw_spin_unlock_irqrestore(&db->lock, flags); if (!obj) { struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr }; debug_print_object(&o, "active_state"); } else if (print_object) { debug_print_object(obj, "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; struct debug_obj_descr *descr; enum debug_obj_state state; struct debug_bucket *db; struct hlist_node *tmp; struct debug_obj *obj; int cnt, objs_checked = 0; 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: descr = obj->descr; state = obj->state; raw_spin_unlock_irqrestore(&db->lock, flags); debug_print_object(obj, "free"); debug_object_fixup(descr->fixup_free, (void *) oaddr, 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) && READ_ONCE(obj_nr_tofree)) { 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