18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Generic infrastructure for lifetime debugging of objects.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Started by Thomas Gleixner
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2008, Thomas Gleixner <tglx@linutronix.de>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * For licencing details see kernel-base/COPYING
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "ODEBUG: " fmt
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/debugobjects.h>
148c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
158c2ecf20Sopenharmony_ci#include <linux/sched.h>
168c2ecf20Sopenharmony_ci#include <linux/sched/task_stack.h>
178c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
188c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
198c2ecf20Sopenharmony_ci#include <linux/slab.h>
208c2ecf20Sopenharmony_ci#include <linux/hash.h>
218c2ecf20Sopenharmony_ci#include <linux/kmemleak.h>
228c2ecf20Sopenharmony_ci#include <linux/cpu.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define ODEBUG_HASH_BITS	14
258c2ecf20Sopenharmony_ci#define ODEBUG_HASH_SIZE	(1 << ODEBUG_HASH_BITS)
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define ODEBUG_POOL_SIZE	1024
288c2ecf20Sopenharmony_ci#define ODEBUG_POOL_MIN_LEVEL	256
298c2ecf20Sopenharmony_ci#define ODEBUG_POOL_PERCPU_SIZE	64
308c2ecf20Sopenharmony_ci#define ODEBUG_BATCH_SIZE	16
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define ODEBUG_CHUNK_SHIFT	PAGE_SHIFT
338c2ecf20Sopenharmony_ci#define ODEBUG_CHUNK_SIZE	(1 << ODEBUG_CHUNK_SHIFT)
348c2ecf20Sopenharmony_ci#define ODEBUG_CHUNK_MASK	(~(ODEBUG_CHUNK_SIZE - 1))
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/*
378c2ecf20Sopenharmony_ci * We limit the freeing of debug objects via workqueue at a maximum
388c2ecf20Sopenharmony_ci * frequency of 10Hz and about 1024 objects for each freeing operation.
398c2ecf20Sopenharmony_ci * So it is freeing at most 10k debug objects per second.
408c2ecf20Sopenharmony_ci */
418c2ecf20Sopenharmony_ci#define ODEBUG_FREE_WORK_MAX	1024
428c2ecf20Sopenharmony_ci#define ODEBUG_FREE_WORK_DELAY	DIV_ROUND_UP(HZ, 10)
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistruct debug_bucket {
458c2ecf20Sopenharmony_ci	struct hlist_head	list;
468c2ecf20Sopenharmony_ci	raw_spinlock_t		lock;
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/*
508c2ecf20Sopenharmony_ci * Debug object percpu free list
518c2ecf20Sopenharmony_ci * Access is protected by disabling irq
528c2ecf20Sopenharmony_ci */
538c2ecf20Sopenharmony_cistruct debug_percpu_free {
548c2ecf20Sopenharmony_ci	struct hlist_head	free_objs;
558c2ecf20Sopenharmony_ci	int			obj_free;
568c2ecf20Sopenharmony_ci};
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct debug_percpu_free, percpu_obj_pool);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistatic struct debug_bucket	obj_hash[ODEBUG_HASH_SIZE];
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic struct debug_obj		obj_static_pool[ODEBUG_POOL_SIZE] __initdata;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(pool_lock);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic HLIST_HEAD(obj_pool);
678c2ecf20Sopenharmony_cistatic HLIST_HEAD(obj_to_free);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci/*
708c2ecf20Sopenharmony_ci * Because of the presence of percpu free pools, obj_pool_free will
718c2ecf20Sopenharmony_ci * under-count those in the percpu free pools. Similarly, obj_pool_used
728c2ecf20Sopenharmony_ci * will over-count those in the percpu free pools. Adjustments will be
738c2ecf20Sopenharmony_ci * made at debug_stats_show(). Both obj_pool_min_free and obj_pool_max_used
748c2ecf20Sopenharmony_ci * can be off.
758c2ecf20Sopenharmony_ci */
768c2ecf20Sopenharmony_cistatic int			obj_pool_min_free = ODEBUG_POOL_SIZE;
778c2ecf20Sopenharmony_cistatic int			obj_pool_free = ODEBUG_POOL_SIZE;
788c2ecf20Sopenharmony_cistatic int			obj_pool_used;
798c2ecf20Sopenharmony_cistatic int			obj_pool_max_used;
808c2ecf20Sopenharmony_cistatic bool			obj_freeing;
818c2ecf20Sopenharmony_ci/* The number of objs on the global free list */
828c2ecf20Sopenharmony_cistatic int			obj_nr_tofree;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic int			debug_objects_maxchain __read_mostly;
858c2ecf20Sopenharmony_cistatic int __maybe_unused	debug_objects_maxchecked __read_mostly;
868c2ecf20Sopenharmony_cistatic int			debug_objects_fixups __read_mostly;
878c2ecf20Sopenharmony_cistatic int			debug_objects_warnings __read_mostly;
888c2ecf20Sopenharmony_cistatic int			debug_objects_enabled __read_mostly
898c2ecf20Sopenharmony_ci				= CONFIG_DEBUG_OBJECTS_ENABLE_DEFAULT;
908c2ecf20Sopenharmony_cistatic int			debug_objects_pool_size __read_mostly
918c2ecf20Sopenharmony_ci				= ODEBUG_POOL_SIZE;
928c2ecf20Sopenharmony_cistatic int			debug_objects_pool_min_level __read_mostly
938c2ecf20Sopenharmony_ci				= ODEBUG_POOL_MIN_LEVEL;
948c2ecf20Sopenharmony_cistatic const struct debug_obj_descr *descr_test  __read_mostly;
958c2ecf20Sopenharmony_cistatic struct kmem_cache	*obj_cache __read_mostly;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/*
988c2ecf20Sopenharmony_ci * Track numbers of kmem_cache_alloc()/free() calls done.
998c2ecf20Sopenharmony_ci */
1008c2ecf20Sopenharmony_cistatic int			debug_objects_allocated;
1018c2ecf20Sopenharmony_cistatic int			debug_objects_freed;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic void free_obj_work(struct work_struct *work);
1048c2ecf20Sopenharmony_cistatic DECLARE_DELAYED_WORK(debug_obj_work, free_obj_work);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic int __init enable_object_debug(char *str)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	debug_objects_enabled = 1;
1098c2ecf20Sopenharmony_ci	return 0;
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic int __init disable_object_debug(char *str)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	debug_objects_enabled = 0;
1158c2ecf20Sopenharmony_ci	return 0;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ciearly_param("debug_objects", enable_object_debug);
1198c2ecf20Sopenharmony_ciearly_param("no_debug_objects", disable_object_debug);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic const char *obj_states[ODEBUG_STATE_MAX] = {
1228c2ecf20Sopenharmony_ci	[ODEBUG_STATE_NONE]		= "none",
1238c2ecf20Sopenharmony_ci	[ODEBUG_STATE_INIT]		= "initialized",
1248c2ecf20Sopenharmony_ci	[ODEBUG_STATE_INACTIVE]		= "inactive",
1258c2ecf20Sopenharmony_ci	[ODEBUG_STATE_ACTIVE]		= "active",
1268c2ecf20Sopenharmony_ci	[ODEBUG_STATE_DESTROYED]	= "destroyed",
1278c2ecf20Sopenharmony_ci	[ODEBUG_STATE_NOTAVAILABLE]	= "not available",
1288c2ecf20Sopenharmony_ci};
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic void fill_pool(void)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	gfp_t gfp = __GFP_HIGH | __GFP_NOWARN;
1338c2ecf20Sopenharmony_ci	struct debug_obj *obj;
1348c2ecf20Sopenharmony_ci	unsigned long flags;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	if (likely(READ_ONCE(obj_pool_free) >= debug_objects_pool_min_level))
1378c2ecf20Sopenharmony_ci		return;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	/*
1408c2ecf20Sopenharmony_ci	 * Reuse objs from the global free list; they will be reinitialized
1418c2ecf20Sopenharmony_ci	 * when allocating.
1428c2ecf20Sopenharmony_ci	 *
1438c2ecf20Sopenharmony_ci	 * Both obj_nr_tofree and obj_pool_free are checked locklessly; the
1448c2ecf20Sopenharmony_ci	 * READ_ONCE()s pair with the WRITE_ONCE()s in pool_lock critical
1458c2ecf20Sopenharmony_ci	 * sections.
1468c2ecf20Sopenharmony_ci	 */
1478c2ecf20Sopenharmony_ci	while (READ_ONCE(obj_nr_tofree) && (READ_ONCE(obj_pool_free) < obj_pool_min_free)) {
1488c2ecf20Sopenharmony_ci		raw_spin_lock_irqsave(&pool_lock, flags);
1498c2ecf20Sopenharmony_ci		/*
1508c2ecf20Sopenharmony_ci		 * Recheck with the lock held as the worker thread might have
1518c2ecf20Sopenharmony_ci		 * won the race and freed the global free list already.
1528c2ecf20Sopenharmony_ci		 */
1538c2ecf20Sopenharmony_ci		while (obj_nr_tofree && (obj_pool_free < obj_pool_min_free)) {
1548c2ecf20Sopenharmony_ci			obj = hlist_entry(obj_to_free.first, typeof(*obj), node);
1558c2ecf20Sopenharmony_ci			hlist_del(&obj->node);
1568c2ecf20Sopenharmony_ci			WRITE_ONCE(obj_nr_tofree, obj_nr_tofree - 1);
1578c2ecf20Sopenharmony_ci			hlist_add_head(&obj->node, &obj_pool);
1588c2ecf20Sopenharmony_ci			WRITE_ONCE(obj_pool_free, obj_pool_free + 1);
1598c2ecf20Sopenharmony_ci		}
1608c2ecf20Sopenharmony_ci		raw_spin_unlock_irqrestore(&pool_lock, flags);
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	if (unlikely(!obj_cache))
1648c2ecf20Sopenharmony_ci		return;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	while (READ_ONCE(obj_pool_free) < debug_objects_pool_min_level) {
1678c2ecf20Sopenharmony_ci		struct debug_obj *new[ODEBUG_BATCH_SIZE];
1688c2ecf20Sopenharmony_ci		int cnt;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci		for (cnt = 0; cnt < ODEBUG_BATCH_SIZE; cnt++) {
1718c2ecf20Sopenharmony_ci			new[cnt] = kmem_cache_zalloc(obj_cache, gfp);
1728c2ecf20Sopenharmony_ci			if (!new[cnt])
1738c2ecf20Sopenharmony_ci				break;
1748c2ecf20Sopenharmony_ci		}
1758c2ecf20Sopenharmony_ci		if (!cnt)
1768c2ecf20Sopenharmony_ci			return;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci		raw_spin_lock_irqsave(&pool_lock, flags);
1798c2ecf20Sopenharmony_ci		while (cnt) {
1808c2ecf20Sopenharmony_ci			hlist_add_head(&new[--cnt]->node, &obj_pool);
1818c2ecf20Sopenharmony_ci			debug_objects_allocated++;
1828c2ecf20Sopenharmony_ci			WRITE_ONCE(obj_pool_free, obj_pool_free + 1);
1838c2ecf20Sopenharmony_ci		}
1848c2ecf20Sopenharmony_ci		raw_spin_unlock_irqrestore(&pool_lock, flags);
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/*
1898c2ecf20Sopenharmony_ci * Lookup an object in the hash bucket.
1908c2ecf20Sopenharmony_ci */
1918c2ecf20Sopenharmony_cistatic struct debug_obj *lookup_object(void *addr, struct debug_bucket *b)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	struct debug_obj *obj;
1948c2ecf20Sopenharmony_ci	int cnt = 0;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	hlist_for_each_entry(obj, &b->list, node) {
1978c2ecf20Sopenharmony_ci		cnt++;
1988c2ecf20Sopenharmony_ci		if (obj->object == addr)
1998c2ecf20Sopenharmony_ci			return obj;
2008c2ecf20Sopenharmony_ci	}
2018c2ecf20Sopenharmony_ci	if (cnt > debug_objects_maxchain)
2028c2ecf20Sopenharmony_ci		debug_objects_maxchain = cnt;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	return NULL;
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci/*
2088c2ecf20Sopenharmony_ci * Allocate a new object from the hlist
2098c2ecf20Sopenharmony_ci */
2108c2ecf20Sopenharmony_cistatic struct debug_obj *__alloc_object(struct hlist_head *list)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	struct debug_obj *obj = NULL;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	if (list->first) {
2158c2ecf20Sopenharmony_ci		obj = hlist_entry(list->first, typeof(*obj), node);
2168c2ecf20Sopenharmony_ci		hlist_del(&obj->node);
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	return obj;
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic struct debug_obj *
2238c2ecf20Sopenharmony_cialloc_object(void *addr, struct debug_bucket *b, const struct debug_obj_descr *descr)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	struct debug_percpu_free *percpu_pool = this_cpu_ptr(&percpu_obj_pool);
2268c2ecf20Sopenharmony_ci	struct debug_obj *obj;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	if (likely(obj_cache)) {
2298c2ecf20Sopenharmony_ci		obj = __alloc_object(&percpu_pool->free_objs);
2308c2ecf20Sopenharmony_ci		if (obj) {
2318c2ecf20Sopenharmony_ci			percpu_pool->obj_free--;
2328c2ecf20Sopenharmony_ci			goto init_obj;
2338c2ecf20Sopenharmony_ci		}
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	raw_spin_lock(&pool_lock);
2378c2ecf20Sopenharmony_ci	obj = __alloc_object(&obj_pool);
2388c2ecf20Sopenharmony_ci	if (obj) {
2398c2ecf20Sopenharmony_ci		obj_pool_used++;
2408c2ecf20Sopenharmony_ci		WRITE_ONCE(obj_pool_free, obj_pool_free - 1);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci		/*
2438c2ecf20Sopenharmony_ci		 * Looking ahead, allocate one batch of debug objects and
2448c2ecf20Sopenharmony_ci		 * put them into the percpu free pool.
2458c2ecf20Sopenharmony_ci		 */
2468c2ecf20Sopenharmony_ci		if (likely(obj_cache)) {
2478c2ecf20Sopenharmony_ci			int i;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci			for (i = 0; i < ODEBUG_BATCH_SIZE; i++) {
2508c2ecf20Sopenharmony_ci				struct debug_obj *obj2;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci				obj2 = __alloc_object(&obj_pool);
2538c2ecf20Sopenharmony_ci				if (!obj2)
2548c2ecf20Sopenharmony_ci					break;
2558c2ecf20Sopenharmony_ci				hlist_add_head(&obj2->node,
2568c2ecf20Sopenharmony_ci					       &percpu_pool->free_objs);
2578c2ecf20Sopenharmony_ci				percpu_pool->obj_free++;
2588c2ecf20Sopenharmony_ci				obj_pool_used++;
2598c2ecf20Sopenharmony_ci				WRITE_ONCE(obj_pool_free, obj_pool_free - 1);
2608c2ecf20Sopenharmony_ci			}
2618c2ecf20Sopenharmony_ci		}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci		if (obj_pool_used > obj_pool_max_used)
2648c2ecf20Sopenharmony_ci			obj_pool_max_used = obj_pool_used;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci		if (obj_pool_free < obj_pool_min_free)
2678c2ecf20Sopenharmony_ci			obj_pool_min_free = obj_pool_free;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci	raw_spin_unlock(&pool_lock);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ciinit_obj:
2728c2ecf20Sopenharmony_ci	if (obj) {
2738c2ecf20Sopenharmony_ci		obj->object = addr;
2748c2ecf20Sopenharmony_ci		obj->descr  = descr;
2758c2ecf20Sopenharmony_ci		obj->state  = ODEBUG_STATE_NONE;
2768c2ecf20Sopenharmony_ci		obj->astate = 0;
2778c2ecf20Sopenharmony_ci		hlist_add_head(&obj->node, &b->list);
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci	return obj;
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci/*
2838c2ecf20Sopenharmony_ci * workqueue function to free objects.
2848c2ecf20Sopenharmony_ci *
2858c2ecf20Sopenharmony_ci * To reduce contention on the global pool_lock, the actual freeing of
2868c2ecf20Sopenharmony_ci * debug objects will be delayed if the pool_lock is busy.
2878c2ecf20Sopenharmony_ci */
2888c2ecf20Sopenharmony_cistatic void free_obj_work(struct work_struct *work)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	struct hlist_node *tmp;
2918c2ecf20Sopenharmony_ci	struct debug_obj *obj;
2928c2ecf20Sopenharmony_ci	unsigned long flags;
2938c2ecf20Sopenharmony_ci	HLIST_HEAD(tofree);
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	WRITE_ONCE(obj_freeing, false);
2968c2ecf20Sopenharmony_ci	if (!raw_spin_trylock_irqsave(&pool_lock, flags))
2978c2ecf20Sopenharmony_ci		return;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	if (obj_pool_free >= debug_objects_pool_size)
3008c2ecf20Sopenharmony_ci		goto free_objs;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	/*
3038c2ecf20Sopenharmony_ci	 * The objs on the pool list might be allocated before the work is
3048c2ecf20Sopenharmony_ci	 * run, so recheck if pool list it full or not, if not fill pool
3058c2ecf20Sopenharmony_ci	 * list from the global free list. As it is likely that a workload
3068c2ecf20Sopenharmony_ci	 * may be gearing up to use more and more objects, don't free any
3078c2ecf20Sopenharmony_ci	 * of them until the next round.
3088c2ecf20Sopenharmony_ci	 */
3098c2ecf20Sopenharmony_ci	while (obj_nr_tofree && obj_pool_free < debug_objects_pool_size) {
3108c2ecf20Sopenharmony_ci		obj = hlist_entry(obj_to_free.first, typeof(*obj), node);
3118c2ecf20Sopenharmony_ci		hlist_del(&obj->node);
3128c2ecf20Sopenharmony_ci		hlist_add_head(&obj->node, &obj_pool);
3138c2ecf20Sopenharmony_ci		WRITE_ONCE(obj_pool_free, obj_pool_free + 1);
3148c2ecf20Sopenharmony_ci		WRITE_ONCE(obj_nr_tofree, obj_nr_tofree - 1);
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pool_lock, flags);
3178c2ecf20Sopenharmony_ci	return;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_cifree_objs:
3208c2ecf20Sopenharmony_ci	/*
3218c2ecf20Sopenharmony_ci	 * Pool list is already full and there are still objs on the free
3228c2ecf20Sopenharmony_ci	 * list. Move remaining free objs to a temporary list to free the
3238c2ecf20Sopenharmony_ci	 * memory outside the pool_lock held region.
3248c2ecf20Sopenharmony_ci	 */
3258c2ecf20Sopenharmony_ci	if (obj_nr_tofree) {
3268c2ecf20Sopenharmony_ci		hlist_move_list(&obj_to_free, &tofree);
3278c2ecf20Sopenharmony_ci		debug_objects_freed += obj_nr_tofree;
3288c2ecf20Sopenharmony_ci		WRITE_ONCE(obj_nr_tofree, 0);
3298c2ecf20Sopenharmony_ci	}
3308c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pool_lock, flags);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(obj, tmp, &tofree, node) {
3338c2ecf20Sopenharmony_ci		hlist_del(&obj->node);
3348c2ecf20Sopenharmony_ci		kmem_cache_free(obj_cache, obj);
3358c2ecf20Sopenharmony_ci	}
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic void __free_object(struct debug_obj *obj)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	struct debug_obj *objs[ODEBUG_BATCH_SIZE];
3418c2ecf20Sopenharmony_ci	struct debug_percpu_free *percpu_pool;
3428c2ecf20Sopenharmony_ci	int lookahead_count = 0;
3438c2ecf20Sopenharmony_ci	unsigned long flags;
3448c2ecf20Sopenharmony_ci	bool work;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	local_irq_save(flags);
3478c2ecf20Sopenharmony_ci	if (!obj_cache)
3488c2ecf20Sopenharmony_ci		goto free_to_obj_pool;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	/*
3518c2ecf20Sopenharmony_ci	 * Try to free it into the percpu pool first.
3528c2ecf20Sopenharmony_ci	 */
3538c2ecf20Sopenharmony_ci	percpu_pool = this_cpu_ptr(&percpu_obj_pool);
3548c2ecf20Sopenharmony_ci	if (percpu_pool->obj_free < ODEBUG_POOL_PERCPU_SIZE) {
3558c2ecf20Sopenharmony_ci		hlist_add_head(&obj->node, &percpu_pool->free_objs);
3568c2ecf20Sopenharmony_ci		percpu_pool->obj_free++;
3578c2ecf20Sopenharmony_ci		local_irq_restore(flags);
3588c2ecf20Sopenharmony_ci		return;
3598c2ecf20Sopenharmony_ci	}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	/*
3628c2ecf20Sopenharmony_ci	 * As the percpu pool is full, look ahead and pull out a batch
3638c2ecf20Sopenharmony_ci	 * of objects from the percpu pool and free them as well.
3648c2ecf20Sopenharmony_ci	 */
3658c2ecf20Sopenharmony_ci	for (; lookahead_count < ODEBUG_BATCH_SIZE; lookahead_count++) {
3668c2ecf20Sopenharmony_ci		objs[lookahead_count] = __alloc_object(&percpu_pool->free_objs);
3678c2ecf20Sopenharmony_ci		if (!objs[lookahead_count])
3688c2ecf20Sopenharmony_ci			break;
3698c2ecf20Sopenharmony_ci		percpu_pool->obj_free--;
3708c2ecf20Sopenharmony_ci	}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cifree_to_obj_pool:
3738c2ecf20Sopenharmony_ci	raw_spin_lock(&pool_lock);
3748c2ecf20Sopenharmony_ci	work = (obj_pool_free > debug_objects_pool_size) && obj_cache &&
3758c2ecf20Sopenharmony_ci	       (obj_nr_tofree < ODEBUG_FREE_WORK_MAX);
3768c2ecf20Sopenharmony_ci	obj_pool_used--;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	if (work) {
3798c2ecf20Sopenharmony_ci		WRITE_ONCE(obj_nr_tofree, obj_nr_tofree + 1);
3808c2ecf20Sopenharmony_ci		hlist_add_head(&obj->node, &obj_to_free);
3818c2ecf20Sopenharmony_ci		if (lookahead_count) {
3828c2ecf20Sopenharmony_ci			WRITE_ONCE(obj_nr_tofree, obj_nr_tofree + lookahead_count);
3838c2ecf20Sopenharmony_ci			obj_pool_used -= lookahead_count;
3848c2ecf20Sopenharmony_ci			while (lookahead_count) {
3858c2ecf20Sopenharmony_ci				hlist_add_head(&objs[--lookahead_count]->node,
3868c2ecf20Sopenharmony_ci					       &obj_to_free);
3878c2ecf20Sopenharmony_ci			}
3888c2ecf20Sopenharmony_ci		}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci		if ((obj_pool_free > debug_objects_pool_size) &&
3918c2ecf20Sopenharmony_ci		    (obj_nr_tofree < ODEBUG_FREE_WORK_MAX)) {
3928c2ecf20Sopenharmony_ci			int i;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci			/*
3958c2ecf20Sopenharmony_ci			 * Free one more batch of objects from obj_pool.
3968c2ecf20Sopenharmony_ci			 */
3978c2ecf20Sopenharmony_ci			for (i = 0; i < ODEBUG_BATCH_SIZE; i++) {
3988c2ecf20Sopenharmony_ci				obj = __alloc_object(&obj_pool);
3998c2ecf20Sopenharmony_ci				hlist_add_head(&obj->node, &obj_to_free);
4008c2ecf20Sopenharmony_ci				WRITE_ONCE(obj_pool_free, obj_pool_free - 1);
4018c2ecf20Sopenharmony_ci				WRITE_ONCE(obj_nr_tofree, obj_nr_tofree + 1);
4028c2ecf20Sopenharmony_ci			}
4038c2ecf20Sopenharmony_ci		}
4048c2ecf20Sopenharmony_ci	} else {
4058c2ecf20Sopenharmony_ci		WRITE_ONCE(obj_pool_free, obj_pool_free + 1);
4068c2ecf20Sopenharmony_ci		hlist_add_head(&obj->node, &obj_pool);
4078c2ecf20Sopenharmony_ci		if (lookahead_count) {
4088c2ecf20Sopenharmony_ci			WRITE_ONCE(obj_pool_free, obj_pool_free + lookahead_count);
4098c2ecf20Sopenharmony_ci			obj_pool_used -= lookahead_count;
4108c2ecf20Sopenharmony_ci			while (lookahead_count) {
4118c2ecf20Sopenharmony_ci				hlist_add_head(&objs[--lookahead_count]->node,
4128c2ecf20Sopenharmony_ci					       &obj_pool);
4138c2ecf20Sopenharmony_ci			}
4148c2ecf20Sopenharmony_ci		}
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci	raw_spin_unlock(&pool_lock);
4178c2ecf20Sopenharmony_ci	local_irq_restore(flags);
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci/*
4218c2ecf20Sopenharmony_ci * Put the object back into the pool and schedule work to free objects
4228c2ecf20Sopenharmony_ci * if necessary.
4238c2ecf20Sopenharmony_ci */
4248c2ecf20Sopenharmony_cistatic void free_object(struct debug_obj *obj)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	__free_object(obj);
4278c2ecf20Sopenharmony_ci	if (!READ_ONCE(obj_freeing) && READ_ONCE(obj_nr_tofree)) {
4288c2ecf20Sopenharmony_ci		WRITE_ONCE(obj_freeing, true);
4298c2ecf20Sopenharmony_ci		schedule_delayed_work(&debug_obj_work, ODEBUG_FREE_WORK_DELAY);
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU
4348c2ecf20Sopenharmony_cistatic int object_cpu_offline(unsigned int cpu)
4358c2ecf20Sopenharmony_ci{
4368c2ecf20Sopenharmony_ci	struct debug_percpu_free *percpu_pool;
4378c2ecf20Sopenharmony_ci	struct hlist_node *tmp;
4388c2ecf20Sopenharmony_ci	struct debug_obj *obj;
4398c2ecf20Sopenharmony_ci	unsigned long flags;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	/* Remote access is safe as the CPU is dead already */
4428c2ecf20Sopenharmony_ci	percpu_pool = per_cpu_ptr(&percpu_obj_pool, cpu);
4438c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(obj, tmp, &percpu_pool->free_objs, node) {
4448c2ecf20Sopenharmony_ci		hlist_del(&obj->node);
4458c2ecf20Sopenharmony_ci		kmem_cache_free(obj_cache, obj);
4468c2ecf20Sopenharmony_ci	}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pool_lock, flags);
4498c2ecf20Sopenharmony_ci	obj_pool_used -= percpu_pool->obj_free;
4508c2ecf20Sopenharmony_ci	debug_objects_freed += percpu_pool->obj_free;
4518c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pool_lock, flags);
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	percpu_pool->obj_free = 0;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	return 0;
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci#endif
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci/*
4608c2ecf20Sopenharmony_ci * We run out of memory. That means we probably have tons of objects
4618c2ecf20Sopenharmony_ci * allocated.
4628c2ecf20Sopenharmony_ci */
4638c2ecf20Sopenharmony_cistatic void debug_objects_oom(void)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	struct debug_bucket *db = obj_hash;
4668c2ecf20Sopenharmony_ci	struct hlist_node *tmp;
4678c2ecf20Sopenharmony_ci	HLIST_HEAD(freelist);
4688c2ecf20Sopenharmony_ci	struct debug_obj *obj;
4698c2ecf20Sopenharmony_ci	unsigned long flags;
4708c2ecf20Sopenharmony_ci	int i;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	pr_warn("Out of memory. ODEBUG disabled\n");
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	for (i = 0; i < ODEBUG_HASH_SIZE; i++, db++) {
4758c2ecf20Sopenharmony_ci		raw_spin_lock_irqsave(&db->lock, flags);
4768c2ecf20Sopenharmony_ci		hlist_move_list(&db->list, &freelist);
4778c2ecf20Sopenharmony_ci		raw_spin_unlock_irqrestore(&db->lock, flags);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci		/* Now free them */
4808c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(obj, tmp, &freelist, node) {
4818c2ecf20Sopenharmony_ci			hlist_del(&obj->node);
4828c2ecf20Sopenharmony_ci			free_object(obj);
4838c2ecf20Sopenharmony_ci		}
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci/*
4888c2ecf20Sopenharmony_ci * We use the pfn of the address for the hash. That way we can check
4898c2ecf20Sopenharmony_ci * for freed objects simply by checking the affected bucket.
4908c2ecf20Sopenharmony_ci */
4918c2ecf20Sopenharmony_cistatic struct debug_bucket *get_bucket(unsigned long addr)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci	unsigned long hash;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	hash = hash_long((addr >> ODEBUG_CHUNK_SHIFT), ODEBUG_HASH_BITS);
4968c2ecf20Sopenharmony_ci	return &obj_hash[hash];
4978c2ecf20Sopenharmony_ci}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_cistatic void debug_print_object(struct debug_obj *obj, char *msg)
5008c2ecf20Sopenharmony_ci{
5018c2ecf20Sopenharmony_ci	const struct debug_obj_descr *descr = obj->descr;
5028c2ecf20Sopenharmony_ci	static int limit;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	/*
5058c2ecf20Sopenharmony_ci	 * Don't report if lookup_object_or_alloc() by the current thread
5068c2ecf20Sopenharmony_ci	 * failed because lookup_object_or_alloc()/debug_objects_oom() by a
5078c2ecf20Sopenharmony_ci	 * concurrent thread turned off debug_objects_enabled and cleared
5088c2ecf20Sopenharmony_ci	 * the hash buckets.
5098c2ecf20Sopenharmony_ci	 */
5108c2ecf20Sopenharmony_ci	if (!debug_objects_enabled)
5118c2ecf20Sopenharmony_ci		return;
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	if (limit < 5 && descr != descr_test) {
5148c2ecf20Sopenharmony_ci		void *hint = descr->debug_hint ?
5158c2ecf20Sopenharmony_ci			descr->debug_hint(obj->object) : NULL;
5168c2ecf20Sopenharmony_ci		limit++;
5178c2ecf20Sopenharmony_ci		WARN(1, KERN_ERR "ODEBUG: %s %s (active state %u) "
5188c2ecf20Sopenharmony_ci				 "object type: %s hint: %pS\n",
5198c2ecf20Sopenharmony_ci			msg, obj_states[obj->state], obj->astate,
5208c2ecf20Sopenharmony_ci			descr->name, hint);
5218c2ecf20Sopenharmony_ci	}
5228c2ecf20Sopenharmony_ci	debug_objects_warnings++;
5238c2ecf20Sopenharmony_ci}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci/*
5268c2ecf20Sopenharmony_ci * Try to repair the damage, so we have a better chance to get useful
5278c2ecf20Sopenharmony_ci * debug output.
5288c2ecf20Sopenharmony_ci */
5298c2ecf20Sopenharmony_cistatic bool
5308c2ecf20Sopenharmony_cidebug_object_fixup(bool (*fixup)(void *addr, enum debug_obj_state state),
5318c2ecf20Sopenharmony_ci		   void * addr, enum debug_obj_state state)
5328c2ecf20Sopenharmony_ci{
5338c2ecf20Sopenharmony_ci	if (fixup && fixup(addr, state)) {
5348c2ecf20Sopenharmony_ci		debug_objects_fixups++;
5358c2ecf20Sopenharmony_ci		return true;
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci	return false;
5388c2ecf20Sopenharmony_ci}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_cistatic void debug_object_is_on_stack(void *addr, int onstack)
5418c2ecf20Sopenharmony_ci{
5428c2ecf20Sopenharmony_ci	int is_on_stack;
5438c2ecf20Sopenharmony_ci	static int limit;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	if (limit > 4)
5468c2ecf20Sopenharmony_ci		return;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	is_on_stack = object_is_on_stack(addr);
5498c2ecf20Sopenharmony_ci	if (is_on_stack == onstack)
5508c2ecf20Sopenharmony_ci		return;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	limit++;
5538c2ecf20Sopenharmony_ci	if (is_on_stack)
5548c2ecf20Sopenharmony_ci		pr_warn("object %p is on stack %p, but NOT annotated.\n", addr,
5558c2ecf20Sopenharmony_ci			 task_stack_page(current));
5568c2ecf20Sopenharmony_ci	else
5578c2ecf20Sopenharmony_ci		pr_warn("object %p is NOT on stack %p, but annotated.\n", addr,
5588c2ecf20Sopenharmony_ci			 task_stack_page(current));
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	WARN_ON(1);
5618c2ecf20Sopenharmony_ci}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_cistatic struct debug_obj *lookup_object_or_alloc(void *addr, struct debug_bucket *b,
5648c2ecf20Sopenharmony_ci						const struct debug_obj_descr *descr,
5658c2ecf20Sopenharmony_ci						bool onstack, bool alloc_ifstatic)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	struct debug_obj *obj = lookup_object(addr, b);
5688c2ecf20Sopenharmony_ci	enum debug_obj_state state = ODEBUG_STATE_NONE;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	if (likely(obj))
5718c2ecf20Sopenharmony_ci		return obj;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	/*
5748c2ecf20Sopenharmony_ci	 * debug_object_init() unconditionally allocates untracked
5758c2ecf20Sopenharmony_ci	 * objects. It does not matter whether it is a static object or
5768c2ecf20Sopenharmony_ci	 * not.
5778c2ecf20Sopenharmony_ci	 *
5788c2ecf20Sopenharmony_ci	 * debug_object_assert_init() and debug_object_activate() allow
5798c2ecf20Sopenharmony_ci	 * allocation only if the descriptor callback confirms that the
5808c2ecf20Sopenharmony_ci	 * object is static and considered initialized. For non-static
5818c2ecf20Sopenharmony_ci	 * objects the allocation needs to be done from the fixup callback.
5828c2ecf20Sopenharmony_ci	 */
5838c2ecf20Sopenharmony_ci	if (unlikely(alloc_ifstatic)) {
5848c2ecf20Sopenharmony_ci		if (!descr->is_static_object || !descr->is_static_object(addr))
5858c2ecf20Sopenharmony_ci			return ERR_PTR(-ENOENT);
5868c2ecf20Sopenharmony_ci		/* Statically allocated objects are considered initialized */
5878c2ecf20Sopenharmony_ci		state = ODEBUG_STATE_INIT;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	obj = alloc_object(addr, b, descr);
5918c2ecf20Sopenharmony_ci	if (likely(obj)) {
5928c2ecf20Sopenharmony_ci		obj->state = state;
5938c2ecf20Sopenharmony_ci		debug_object_is_on_stack(addr, onstack);
5948c2ecf20Sopenharmony_ci		return obj;
5958c2ecf20Sopenharmony_ci	}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	/* Out of memory. Do the cleanup outside of the locked region */
5988c2ecf20Sopenharmony_ci	debug_objects_enabled = 0;
5998c2ecf20Sopenharmony_ci	return NULL;
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_cistatic void debug_objects_fill_pool(void)
6038c2ecf20Sopenharmony_ci{
6048c2ecf20Sopenharmony_ci	/*
6058c2ecf20Sopenharmony_ci	 * On RT enabled kernels the pool refill must happen in preemptible
6068c2ecf20Sopenharmony_ci	 * context:
6078c2ecf20Sopenharmony_ci	 */
6088c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_PREEMPT_RT) || preemptible())
6098c2ecf20Sopenharmony_ci		fill_pool();
6108c2ecf20Sopenharmony_ci}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_cistatic void
6138c2ecf20Sopenharmony_ci__debug_object_init(void *addr, const struct debug_obj_descr *descr, int onstack)
6148c2ecf20Sopenharmony_ci{
6158c2ecf20Sopenharmony_ci	struct debug_obj *obj, o;
6168c2ecf20Sopenharmony_ci	struct debug_bucket *db;
6178c2ecf20Sopenharmony_ci	unsigned long flags;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	debug_objects_fill_pool();
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	db = get_bucket((unsigned long) addr);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&db->lock, flags);
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	obj = lookup_object_or_alloc(addr, db, descr, onstack, false);
6268c2ecf20Sopenharmony_ci	if (unlikely(!obj)) {
6278c2ecf20Sopenharmony_ci		raw_spin_unlock_irqrestore(&db->lock, flags);
6288c2ecf20Sopenharmony_ci		debug_objects_oom();
6298c2ecf20Sopenharmony_ci		return;
6308c2ecf20Sopenharmony_ci	}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	switch (obj->state) {
6338c2ecf20Sopenharmony_ci	case ODEBUG_STATE_NONE:
6348c2ecf20Sopenharmony_ci	case ODEBUG_STATE_INIT:
6358c2ecf20Sopenharmony_ci	case ODEBUG_STATE_INACTIVE:
6368c2ecf20Sopenharmony_ci		obj->state = ODEBUG_STATE_INIT;
6378c2ecf20Sopenharmony_ci		raw_spin_unlock_irqrestore(&db->lock, flags);
6388c2ecf20Sopenharmony_ci		return;
6398c2ecf20Sopenharmony_ci	default:
6408c2ecf20Sopenharmony_ci		break;
6418c2ecf20Sopenharmony_ci	}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	o = *obj;
6448c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&db->lock, flags);
6458c2ecf20Sopenharmony_ci	debug_print_object(&o, "init");
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	if (o.state == ODEBUG_STATE_ACTIVE)
6488c2ecf20Sopenharmony_ci		debug_object_fixup(descr->fixup_init, addr, o.state);
6498c2ecf20Sopenharmony_ci}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci/**
6528c2ecf20Sopenharmony_ci * debug_object_init - debug checks when an object is initialized
6538c2ecf20Sopenharmony_ci * @addr:	address of the object
6548c2ecf20Sopenharmony_ci * @descr:	pointer to an object specific debug description structure
6558c2ecf20Sopenharmony_ci */
6568c2ecf20Sopenharmony_civoid debug_object_init(void *addr, const struct debug_obj_descr *descr)
6578c2ecf20Sopenharmony_ci{
6588c2ecf20Sopenharmony_ci	if (!debug_objects_enabled)
6598c2ecf20Sopenharmony_ci		return;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	__debug_object_init(addr, descr, 0);
6628c2ecf20Sopenharmony_ci}
6638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(debug_object_init);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci/**
6668c2ecf20Sopenharmony_ci * debug_object_init_on_stack - debug checks when an object on stack is
6678c2ecf20Sopenharmony_ci *				initialized
6688c2ecf20Sopenharmony_ci * @addr:	address of the object
6698c2ecf20Sopenharmony_ci * @descr:	pointer to an object specific debug description structure
6708c2ecf20Sopenharmony_ci */
6718c2ecf20Sopenharmony_civoid debug_object_init_on_stack(void *addr, const struct debug_obj_descr *descr)
6728c2ecf20Sopenharmony_ci{
6738c2ecf20Sopenharmony_ci	if (!debug_objects_enabled)
6748c2ecf20Sopenharmony_ci		return;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	__debug_object_init(addr, descr, 1);
6778c2ecf20Sopenharmony_ci}
6788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(debug_object_init_on_stack);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci/**
6818c2ecf20Sopenharmony_ci * debug_object_activate - debug checks when an object is activated
6828c2ecf20Sopenharmony_ci * @addr:	address of the object
6838c2ecf20Sopenharmony_ci * @descr:	pointer to an object specific debug description structure
6848c2ecf20Sopenharmony_ci * Returns 0 for success, -EINVAL for check failed.
6858c2ecf20Sopenharmony_ci */
6868c2ecf20Sopenharmony_ciint debug_object_activate(void *addr, const struct debug_obj_descr *descr)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr };
6898c2ecf20Sopenharmony_ci	struct debug_bucket *db;
6908c2ecf20Sopenharmony_ci	struct debug_obj *obj;
6918c2ecf20Sopenharmony_ci	unsigned long flags;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	if (!debug_objects_enabled)
6948c2ecf20Sopenharmony_ci		return 0;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	debug_objects_fill_pool();
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	db = get_bucket((unsigned long) addr);
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&db->lock, flags);
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	obj = lookup_object_or_alloc(addr, db, descr, false, true);
7038c2ecf20Sopenharmony_ci	if (unlikely(!obj)) {
7048c2ecf20Sopenharmony_ci		raw_spin_unlock_irqrestore(&db->lock, flags);
7058c2ecf20Sopenharmony_ci		debug_objects_oom();
7068c2ecf20Sopenharmony_ci		return 0;
7078c2ecf20Sopenharmony_ci	} else if (likely(!IS_ERR(obj))) {
7088c2ecf20Sopenharmony_ci		switch (obj->state) {
7098c2ecf20Sopenharmony_ci		case ODEBUG_STATE_ACTIVE:
7108c2ecf20Sopenharmony_ci		case ODEBUG_STATE_DESTROYED:
7118c2ecf20Sopenharmony_ci			o = *obj;
7128c2ecf20Sopenharmony_ci			break;
7138c2ecf20Sopenharmony_ci		case ODEBUG_STATE_INIT:
7148c2ecf20Sopenharmony_ci		case ODEBUG_STATE_INACTIVE:
7158c2ecf20Sopenharmony_ci			obj->state = ODEBUG_STATE_ACTIVE;
7168c2ecf20Sopenharmony_ci			fallthrough;
7178c2ecf20Sopenharmony_ci		default:
7188c2ecf20Sopenharmony_ci			raw_spin_unlock_irqrestore(&db->lock, flags);
7198c2ecf20Sopenharmony_ci			return 0;
7208c2ecf20Sopenharmony_ci		}
7218c2ecf20Sopenharmony_ci	}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&db->lock, flags);
7248c2ecf20Sopenharmony_ci	debug_print_object(&o, "activate");
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	switch (o.state) {
7278c2ecf20Sopenharmony_ci	case ODEBUG_STATE_ACTIVE:
7288c2ecf20Sopenharmony_ci	case ODEBUG_STATE_NOTAVAILABLE:
7298c2ecf20Sopenharmony_ci		if (debug_object_fixup(descr->fixup_activate, addr, o.state))
7308c2ecf20Sopenharmony_ci			return 0;
7318c2ecf20Sopenharmony_ci		fallthrough;
7328c2ecf20Sopenharmony_ci	default:
7338c2ecf20Sopenharmony_ci		return -EINVAL;
7348c2ecf20Sopenharmony_ci	}
7358c2ecf20Sopenharmony_ci}
7368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(debug_object_activate);
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci/**
7398c2ecf20Sopenharmony_ci * debug_object_deactivate - debug checks when an object is deactivated
7408c2ecf20Sopenharmony_ci * @addr:	address of the object
7418c2ecf20Sopenharmony_ci * @descr:	pointer to an object specific debug description structure
7428c2ecf20Sopenharmony_ci */
7438c2ecf20Sopenharmony_civoid debug_object_deactivate(void *addr, const struct debug_obj_descr *descr)
7448c2ecf20Sopenharmony_ci{
7458c2ecf20Sopenharmony_ci	struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr };
7468c2ecf20Sopenharmony_ci	struct debug_bucket *db;
7478c2ecf20Sopenharmony_ci	struct debug_obj *obj;
7488c2ecf20Sopenharmony_ci	unsigned long flags;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	if (!debug_objects_enabled)
7518c2ecf20Sopenharmony_ci		return;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	db = get_bucket((unsigned long) addr);
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&db->lock, flags);
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	obj = lookup_object(addr, db);
7588c2ecf20Sopenharmony_ci	if (obj) {
7598c2ecf20Sopenharmony_ci		switch (obj->state) {
7608c2ecf20Sopenharmony_ci		case ODEBUG_STATE_DESTROYED:
7618c2ecf20Sopenharmony_ci			break;
7628c2ecf20Sopenharmony_ci		case ODEBUG_STATE_INIT:
7638c2ecf20Sopenharmony_ci		case ODEBUG_STATE_INACTIVE:
7648c2ecf20Sopenharmony_ci		case ODEBUG_STATE_ACTIVE:
7658c2ecf20Sopenharmony_ci			if (obj->astate)
7668c2ecf20Sopenharmony_ci				break;
7678c2ecf20Sopenharmony_ci			obj->state = ODEBUG_STATE_INACTIVE;
7688c2ecf20Sopenharmony_ci			fallthrough;
7698c2ecf20Sopenharmony_ci		default:
7708c2ecf20Sopenharmony_ci			raw_spin_unlock_irqrestore(&db->lock, flags);
7718c2ecf20Sopenharmony_ci			return;
7728c2ecf20Sopenharmony_ci		}
7738c2ecf20Sopenharmony_ci		o = *obj;
7748c2ecf20Sopenharmony_ci	}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&db->lock, flags);
7778c2ecf20Sopenharmony_ci	debug_print_object(&o, "deactivate");
7788c2ecf20Sopenharmony_ci}
7798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(debug_object_deactivate);
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci/**
7828c2ecf20Sopenharmony_ci * debug_object_destroy - debug checks when an object is destroyed
7838c2ecf20Sopenharmony_ci * @addr:	address of the object
7848c2ecf20Sopenharmony_ci * @descr:	pointer to an object specific debug description structure
7858c2ecf20Sopenharmony_ci */
7868c2ecf20Sopenharmony_civoid debug_object_destroy(void *addr, const struct debug_obj_descr *descr)
7878c2ecf20Sopenharmony_ci{
7888c2ecf20Sopenharmony_ci	struct debug_obj *obj, o;
7898c2ecf20Sopenharmony_ci	struct debug_bucket *db;
7908c2ecf20Sopenharmony_ci	unsigned long flags;
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	if (!debug_objects_enabled)
7938c2ecf20Sopenharmony_ci		return;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	db = get_bucket((unsigned long) addr);
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&db->lock, flags);
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	obj = lookup_object(addr, db);
8008c2ecf20Sopenharmony_ci	if (!obj) {
8018c2ecf20Sopenharmony_ci		raw_spin_unlock_irqrestore(&db->lock, flags);
8028c2ecf20Sopenharmony_ci		return;
8038c2ecf20Sopenharmony_ci	}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	switch (obj->state) {
8068c2ecf20Sopenharmony_ci	case ODEBUG_STATE_ACTIVE:
8078c2ecf20Sopenharmony_ci	case ODEBUG_STATE_DESTROYED:
8088c2ecf20Sopenharmony_ci		break;
8098c2ecf20Sopenharmony_ci	case ODEBUG_STATE_NONE:
8108c2ecf20Sopenharmony_ci	case ODEBUG_STATE_INIT:
8118c2ecf20Sopenharmony_ci	case ODEBUG_STATE_INACTIVE:
8128c2ecf20Sopenharmony_ci		obj->state = ODEBUG_STATE_DESTROYED;
8138c2ecf20Sopenharmony_ci		fallthrough;
8148c2ecf20Sopenharmony_ci	default:
8158c2ecf20Sopenharmony_ci		raw_spin_unlock_irqrestore(&db->lock, flags);
8168c2ecf20Sopenharmony_ci		return;
8178c2ecf20Sopenharmony_ci	}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	o = *obj;
8208c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&db->lock, flags);
8218c2ecf20Sopenharmony_ci	debug_print_object(&o, "destroy");
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	if (o.state == ODEBUG_STATE_ACTIVE)
8248c2ecf20Sopenharmony_ci		debug_object_fixup(descr->fixup_destroy, addr, o.state);
8258c2ecf20Sopenharmony_ci}
8268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(debug_object_destroy);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci/**
8298c2ecf20Sopenharmony_ci * debug_object_free - debug checks when an object is freed
8308c2ecf20Sopenharmony_ci * @addr:	address of the object
8318c2ecf20Sopenharmony_ci * @descr:	pointer to an object specific debug description structure
8328c2ecf20Sopenharmony_ci */
8338c2ecf20Sopenharmony_civoid debug_object_free(void *addr, const struct debug_obj_descr *descr)
8348c2ecf20Sopenharmony_ci{
8358c2ecf20Sopenharmony_ci	struct debug_obj *obj, o;
8368c2ecf20Sopenharmony_ci	struct debug_bucket *db;
8378c2ecf20Sopenharmony_ci	unsigned long flags;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	if (!debug_objects_enabled)
8408c2ecf20Sopenharmony_ci		return;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	db = get_bucket((unsigned long) addr);
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&db->lock, flags);
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	obj = lookup_object(addr, db);
8478c2ecf20Sopenharmony_ci	if (!obj) {
8488c2ecf20Sopenharmony_ci		raw_spin_unlock_irqrestore(&db->lock, flags);
8498c2ecf20Sopenharmony_ci		return;
8508c2ecf20Sopenharmony_ci	}
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	switch (obj->state) {
8538c2ecf20Sopenharmony_ci	case ODEBUG_STATE_ACTIVE:
8548c2ecf20Sopenharmony_ci		break;
8558c2ecf20Sopenharmony_ci	default:
8568c2ecf20Sopenharmony_ci		hlist_del(&obj->node);
8578c2ecf20Sopenharmony_ci		raw_spin_unlock_irqrestore(&db->lock, flags);
8588c2ecf20Sopenharmony_ci		free_object(obj);
8598c2ecf20Sopenharmony_ci		return;
8608c2ecf20Sopenharmony_ci	}
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	o = *obj;
8638c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&db->lock, flags);
8648c2ecf20Sopenharmony_ci	debug_print_object(&o, "free");
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	debug_object_fixup(descr->fixup_free, addr, o.state);
8678c2ecf20Sopenharmony_ci}
8688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(debug_object_free);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci/**
8718c2ecf20Sopenharmony_ci * debug_object_assert_init - debug checks when object should be init-ed
8728c2ecf20Sopenharmony_ci * @addr:	address of the object
8738c2ecf20Sopenharmony_ci * @descr:	pointer to an object specific debug description structure
8748c2ecf20Sopenharmony_ci */
8758c2ecf20Sopenharmony_civoid debug_object_assert_init(void *addr, const struct debug_obj_descr *descr)
8768c2ecf20Sopenharmony_ci{
8778c2ecf20Sopenharmony_ci	struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr };
8788c2ecf20Sopenharmony_ci	struct debug_bucket *db;
8798c2ecf20Sopenharmony_ci	struct debug_obj *obj;
8808c2ecf20Sopenharmony_ci	unsigned long flags;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	if (!debug_objects_enabled)
8838c2ecf20Sopenharmony_ci		return;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	debug_objects_fill_pool();
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	db = get_bucket((unsigned long) addr);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&db->lock, flags);
8908c2ecf20Sopenharmony_ci	obj = lookup_object_or_alloc(addr, db, descr, false, true);
8918c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&db->lock, flags);
8928c2ecf20Sopenharmony_ci	if (likely(!IS_ERR_OR_NULL(obj)))
8938c2ecf20Sopenharmony_ci		return;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	/* If NULL the allocation has hit OOM */
8968c2ecf20Sopenharmony_ci	if (!obj) {
8978c2ecf20Sopenharmony_ci		debug_objects_oom();
8988c2ecf20Sopenharmony_ci		return;
8998c2ecf20Sopenharmony_ci	}
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	/* Object is neither tracked nor static. It's not initialized. */
9028c2ecf20Sopenharmony_ci	debug_print_object(&o, "assert_init");
9038c2ecf20Sopenharmony_ci	debug_object_fixup(descr->fixup_assert_init, addr, ODEBUG_STATE_NOTAVAILABLE);
9048c2ecf20Sopenharmony_ci}
9058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(debug_object_assert_init);
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci/**
9088c2ecf20Sopenharmony_ci * debug_object_active_state - debug checks object usage state machine
9098c2ecf20Sopenharmony_ci * @addr:	address of the object
9108c2ecf20Sopenharmony_ci * @descr:	pointer to an object specific debug description structure
9118c2ecf20Sopenharmony_ci * @expect:	expected state
9128c2ecf20Sopenharmony_ci * @next:	state to move to if expected state is found
9138c2ecf20Sopenharmony_ci */
9148c2ecf20Sopenharmony_civoid
9158c2ecf20Sopenharmony_cidebug_object_active_state(void *addr, const struct debug_obj_descr *descr,
9168c2ecf20Sopenharmony_ci			  unsigned int expect, unsigned int next)
9178c2ecf20Sopenharmony_ci{
9188c2ecf20Sopenharmony_ci	struct debug_obj o = { .object = addr, .state = ODEBUG_STATE_NOTAVAILABLE, .descr = descr };
9198c2ecf20Sopenharmony_ci	struct debug_bucket *db;
9208c2ecf20Sopenharmony_ci	struct debug_obj *obj;
9218c2ecf20Sopenharmony_ci	unsigned long flags;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	if (!debug_objects_enabled)
9248c2ecf20Sopenharmony_ci		return;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	db = get_bucket((unsigned long) addr);
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&db->lock, flags);
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	obj = lookup_object(addr, db);
9318c2ecf20Sopenharmony_ci	if (obj) {
9328c2ecf20Sopenharmony_ci		switch (obj->state) {
9338c2ecf20Sopenharmony_ci		case ODEBUG_STATE_ACTIVE:
9348c2ecf20Sopenharmony_ci			if (obj->astate != expect)
9358c2ecf20Sopenharmony_ci				break;
9368c2ecf20Sopenharmony_ci			obj->astate = next;
9378c2ecf20Sopenharmony_ci			raw_spin_unlock_irqrestore(&db->lock, flags);
9388c2ecf20Sopenharmony_ci			return;
9398c2ecf20Sopenharmony_ci		default:
9408c2ecf20Sopenharmony_ci			break;
9418c2ecf20Sopenharmony_ci		}
9428c2ecf20Sopenharmony_ci		o = *obj;
9438c2ecf20Sopenharmony_ci	}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&db->lock, flags);
9468c2ecf20Sopenharmony_ci	debug_print_object(&o, "active_state");
9478c2ecf20Sopenharmony_ci}
9488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(debug_object_active_state);
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_OBJECTS_FREE
9518c2ecf20Sopenharmony_cistatic void __debug_check_no_obj_freed(const void *address, unsigned long size)
9528c2ecf20Sopenharmony_ci{
9538c2ecf20Sopenharmony_ci	unsigned long flags, oaddr, saddr, eaddr, paddr, chunks;
9548c2ecf20Sopenharmony_ci	int cnt, objs_checked = 0;
9558c2ecf20Sopenharmony_ci	struct debug_obj *obj, o;
9568c2ecf20Sopenharmony_ci	struct debug_bucket *db;
9578c2ecf20Sopenharmony_ci	struct hlist_node *tmp;
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	saddr = (unsigned long) address;
9608c2ecf20Sopenharmony_ci	eaddr = saddr + size;
9618c2ecf20Sopenharmony_ci	paddr = saddr & ODEBUG_CHUNK_MASK;
9628c2ecf20Sopenharmony_ci	chunks = ((eaddr - paddr) + (ODEBUG_CHUNK_SIZE - 1));
9638c2ecf20Sopenharmony_ci	chunks >>= ODEBUG_CHUNK_SHIFT;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	for (;chunks > 0; chunks--, paddr += ODEBUG_CHUNK_SIZE) {
9668c2ecf20Sopenharmony_ci		db = get_bucket(paddr);
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_cirepeat:
9698c2ecf20Sopenharmony_ci		cnt = 0;
9708c2ecf20Sopenharmony_ci		raw_spin_lock_irqsave(&db->lock, flags);
9718c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(obj, tmp, &db->list, node) {
9728c2ecf20Sopenharmony_ci			cnt++;
9738c2ecf20Sopenharmony_ci			oaddr = (unsigned long) obj->object;
9748c2ecf20Sopenharmony_ci			if (oaddr < saddr || oaddr >= eaddr)
9758c2ecf20Sopenharmony_ci				continue;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci			switch (obj->state) {
9788c2ecf20Sopenharmony_ci			case ODEBUG_STATE_ACTIVE:
9798c2ecf20Sopenharmony_ci				o = *obj;
9808c2ecf20Sopenharmony_ci				raw_spin_unlock_irqrestore(&db->lock, flags);
9818c2ecf20Sopenharmony_ci				debug_print_object(&o, "free");
9828c2ecf20Sopenharmony_ci				debug_object_fixup(o.descr->fixup_free, (void *)oaddr, o.state);
9838c2ecf20Sopenharmony_ci				goto repeat;
9848c2ecf20Sopenharmony_ci			default:
9858c2ecf20Sopenharmony_ci				hlist_del(&obj->node);
9868c2ecf20Sopenharmony_ci				__free_object(obj);
9878c2ecf20Sopenharmony_ci				break;
9888c2ecf20Sopenharmony_ci			}
9898c2ecf20Sopenharmony_ci		}
9908c2ecf20Sopenharmony_ci		raw_spin_unlock_irqrestore(&db->lock, flags);
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci		if (cnt > debug_objects_maxchain)
9938c2ecf20Sopenharmony_ci			debug_objects_maxchain = cnt;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci		objs_checked += cnt;
9968c2ecf20Sopenharmony_ci	}
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	if (objs_checked > debug_objects_maxchecked)
9998c2ecf20Sopenharmony_ci		debug_objects_maxchecked = objs_checked;
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	/* Schedule work to actually kmem_cache_free() objects */
10028c2ecf20Sopenharmony_ci	if (!READ_ONCE(obj_freeing) && READ_ONCE(obj_nr_tofree)) {
10038c2ecf20Sopenharmony_ci		WRITE_ONCE(obj_freeing, true);
10048c2ecf20Sopenharmony_ci		schedule_delayed_work(&debug_obj_work, ODEBUG_FREE_WORK_DELAY);
10058c2ecf20Sopenharmony_ci	}
10068c2ecf20Sopenharmony_ci}
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_civoid debug_check_no_obj_freed(const void *address, unsigned long size)
10098c2ecf20Sopenharmony_ci{
10108c2ecf20Sopenharmony_ci	if (debug_objects_enabled)
10118c2ecf20Sopenharmony_ci		__debug_check_no_obj_freed(address, size);
10128c2ecf20Sopenharmony_ci}
10138c2ecf20Sopenharmony_ci#endif
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_cistatic int debug_stats_show(struct seq_file *m, void *v)
10188c2ecf20Sopenharmony_ci{
10198c2ecf20Sopenharmony_ci	int cpu, obj_percpu_free = 0;
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	for_each_possible_cpu(cpu)
10228c2ecf20Sopenharmony_ci		obj_percpu_free += per_cpu(percpu_obj_pool.obj_free, cpu);
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	seq_printf(m, "max_chain     :%d\n", debug_objects_maxchain);
10258c2ecf20Sopenharmony_ci	seq_printf(m, "max_checked   :%d\n", debug_objects_maxchecked);
10268c2ecf20Sopenharmony_ci	seq_printf(m, "warnings      :%d\n", debug_objects_warnings);
10278c2ecf20Sopenharmony_ci	seq_printf(m, "fixups        :%d\n", debug_objects_fixups);
10288c2ecf20Sopenharmony_ci	seq_printf(m, "pool_free     :%d\n", READ_ONCE(obj_pool_free) + obj_percpu_free);
10298c2ecf20Sopenharmony_ci	seq_printf(m, "pool_pcp_free :%d\n", obj_percpu_free);
10308c2ecf20Sopenharmony_ci	seq_printf(m, "pool_min_free :%d\n", obj_pool_min_free);
10318c2ecf20Sopenharmony_ci	seq_printf(m, "pool_used     :%d\n", obj_pool_used - obj_percpu_free);
10328c2ecf20Sopenharmony_ci	seq_printf(m, "pool_max_used :%d\n", obj_pool_max_used);
10338c2ecf20Sopenharmony_ci	seq_printf(m, "on_free_list  :%d\n", READ_ONCE(obj_nr_tofree));
10348c2ecf20Sopenharmony_ci	seq_printf(m, "objs_allocated:%d\n", debug_objects_allocated);
10358c2ecf20Sopenharmony_ci	seq_printf(m, "objs_freed    :%d\n", debug_objects_freed);
10368c2ecf20Sopenharmony_ci	return 0;
10378c2ecf20Sopenharmony_ci}
10388c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(debug_stats);
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_cistatic int __init debug_objects_init_debugfs(void)
10418c2ecf20Sopenharmony_ci{
10428c2ecf20Sopenharmony_ci	struct dentry *dbgdir;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	if (!debug_objects_enabled)
10458c2ecf20Sopenharmony_ci		return 0;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	dbgdir = debugfs_create_dir("debug_objects", NULL);
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	debugfs_create_file("stats", 0444, dbgdir, NULL, &debug_stats_fops);
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	return 0;
10528c2ecf20Sopenharmony_ci}
10538c2ecf20Sopenharmony_ci__initcall(debug_objects_init_debugfs);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci#else
10568c2ecf20Sopenharmony_cistatic inline void debug_objects_init_debugfs(void) { }
10578c2ecf20Sopenharmony_ci#endif
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_OBJECTS_SELFTEST
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci/* Random data structure for the self test */
10628c2ecf20Sopenharmony_cistruct self_test {
10638c2ecf20Sopenharmony_ci	unsigned long	dummy1[6];
10648c2ecf20Sopenharmony_ci	int		static_init;
10658c2ecf20Sopenharmony_ci	unsigned long	dummy2[3];
10668c2ecf20Sopenharmony_ci};
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_cistatic __initconst const struct debug_obj_descr descr_type_test;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_cistatic bool __init is_static_object(void *addr)
10718c2ecf20Sopenharmony_ci{
10728c2ecf20Sopenharmony_ci	struct self_test *obj = addr;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	return obj->static_init;
10758c2ecf20Sopenharmony_ci}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci/*
10788c2ecf20Sopenharmony_ci * fixup_init is called when:
10798c2ecf20Sopenharmony_ci * - an active object is initialized
10808c2ecf20Sopenharmony_ci */
10818c2ecf20Sopenharmony_cistatic bool __init fixup_init(void *addr, enum debug_obj_state state)
10828c2ecf20Sopenharmony_ci{
10838c2ecf20Sopenharmony_ci	struct self_test *obj = addr;
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	switch (state) {
10868c2ecf20Sopenharmony_ci	case ODEBUG_STATE_ACTIVE:
10878c2ecf20Sopenharmony_ci		debug_object_deactivate(obj, &descr_type_test);
10888c2ecf20Sopenharmony_ci		debug_object_init(obj, &descr_type_test);
10898c2ecf20Sopenharmony_ci		return true;
10908c2ecf20Sopenharmony_ci	default:
10918c2ecf20Sopenharmony_ci		return false;
10928c2ecf20Sopenharmony_ci	}
10938c2ecf20Sopenharmony_ci}
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci/*
10968c2ecf20Sopenharmony_ci * fixup_activate is called when:
10978c2ecf20Sopenharmony_ci * - an active object is activated
10988c2ecf20Sopenharmony_ci * - an unknown non-static object is activated
10998c2ecf20Sopenharmony_ci */
11008c2ecf20Sopenharmony_cistatic bool __init fixup_activate(void *addr, enum debug_obj_state state)
11018c2ecf20Sopenharmony_ci{
11028c2ecf20Sopenharmony_ci	struct self_test *obj = addr;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	switch (state) {
11058c2ecf20Sopenharmony_ci	case ODEBUG_STATE_NOTAVAILABLE:
11068c2ecf20Sopenharmony_ci		return true;
11078c2ecf20Sopenharmony_ci	case ODEBUG_STATE_ACTIVE:
11088c2ecf20Sopenharmony_ci		debug_object_deactivate(obj, &descr_type_test);
11098c2ecf20Sopenharmony_ci		debug_object_activate(obj, &descr_type_test);
11108c2ecf20Sopenharmony_ci		return true;
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	default:
11138c2ecf20Sopenharmony_ci		return false;
11148c2ecf20Sopenharmony_ci	}
11158c2ecf20Sopenharmony_ci}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci/*
11188c2ecf20Sopenharmony_ci * fixup_destroy is called when:
11198c2ecf20Sopenharmony_ci * - an active object is destroyed
11208c2ecf20Sopenharmony_ci */
11218c2ecf20Sopenharmony_cistatic bool __init fixup_destroy(void *addr, enum debug_obj_state state)
11228c2ecf20Sopenharmony_ci{
11238c2ecf20Sopenharmony_ci	struct self_test *obj = addr;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	switch (state) {
11268c2ecf20Sopenharmony_ci	case ODEBUG_STATE_ACTIVE:
11278c2ecf20Sopenharmony_ci		debug_object_deactivate(obj, &descr_type_test);
11288c2ecf20Sopenharmony_ci		debug_object_destroy(obj, &descr_type_test);
11298c2ecf20Sopenharmony_ci		return true;
11308c2ecf20Sopenharmony_ci	default:
11318c2ecf20Sopenharmony_ci		return false;
11328c2ecf20Sopenharmony_ci	}
11338c2ecf20Sopenharmony_ci}
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci/*
11368c2ecf20Sopenharmony_ci * fixup_free is called when:
11378c2ecf20Sopenharmony_ci * - an active object is freed
11388c2ecf20Sopenharmony_ci */
11398c2ecf20Sopenharmony_cistatic bool __init fixup_free(void *addr, enum debug_obj_state state)
11408c2ecf20Sopenharmony_ci{
11418c2ecf20Sopenharmony_ci	struct self_test *obj = addr;
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	switch (state) {
11448c2ecf20Sopenharmony_ci	case ODEBUG_STATE_ACTIVE:
11458c2ecf20Sopenharmony_ci		debug_object_deactivate(obj, &descr_type_test);
11468c2ecf20Sopenharmony_ci		debug_object_free(obj, &descr_type_test);
11478c2ecf20Sopenharmony_ci		return true;
11488c2ecf20Sopenharmony_ci	default:
11498c2ecf20Sopenharmony_ci		return false;
11508c2ecf20Sopenharmony_ci	}
11518c2ecf20Sopenharmony_ci}
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_cistatic int __init
11548c2ecf20Sopenharmony_cicheck_results(void *addr, enum debug_obj_state state, int fixups, int warnings)
11558c2ecf20Sopenharmony_ci{
11568c2ecf20Sopenharmony_ci	struct debug_bucket *db;
11578c2ecf20Sopenharmony_ci	struct debug_obj *obj;
11588c2ecf20Sopenharmony_ci	unsigned long flags;
11598c2ecf20Sopenharmony_ci	int res = -EINVAL;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	db = get_bucket((unsigned long) addr);
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&db->lock, flags);
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	obj = lookup_object(addr, db);
11668c2ecf20Sopenharmony_ci	if (!obj && state != ODEBUG_STATE_NONE) {
11678c2ecf20Sopenharmony_ci		WARN(1, KERN_ERR "ODEBUG: selftest object not found\n");
11688c2ecf20Sopenharmony_ci		goto out;
11698c2ecf20Sopenharmony_ci	}
11708c2ecf20Sopenharmony_ci	if (obj && obj->state != state) {
11718c2ecf20Sopenharmony_ci		WARN(1, KERN_ERR "ODEBUG: selftest wrong state: %d != %d\n",
11728c2ecf20Sopenharmony_ci		       obj->state, state);
11738c2ecf20Sopenharmony_ci		goto out;
11748c2ecf20Sopenharmony_ci	}
11758c2ecf20Sopenharmony_ci	if (fixups != debug_objects_fixups) {
11768c2ecf20Sopenharmony_ci		WARN(1, KERN_ERR "ODEBUG: selftest fixups failed %d != %d\n",
11778c2ecf20Sopenharmony_ci		       fixups, debug_objects_fixups);
11788c2ecf20Sopenharmony_ci		goto out;
11798c2ecf20Sopenharmony_ci	}
11808c2ecf20Sopenharmony_ci	if (warnings != debug_objects_warnings) {
11818c2ecf20Sopenharmony_ci		WARN(1, KERN_ERR "ODEBUG: selftest warnings failed %d != %d\n",
11828c2ecf20Sopenharmony_ci		       warnings, debug_objects_warnings);
11838c2ecf20Sopenharmony_ci		goto out;
11848c2ecf20Sopenharmony_ci	}
11858c2ecf20Sopenharmony_ci	res = 0;
11868c2ecf20Sopenharmony_ciout:
11878c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&db->lock, flags);
11888c2ecf20Sopenharmony_ci	if (res)
11898c2ecf20Sopenharmony_ci		debug_objects_enabled = 0;
11908c2ecf20Sopenharmony_ci	return res;
11918c2ecf20Sopenharmony_ci}
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_cistatic __initconst const struct debug_obj_descr descr_type_test = {
11948c2ecf20Sopenharmony_ci	.name			= "selftest",
11958c2ecf20Sopenharmony_ci	.is_static_object	= is_static_object,
11968c2ecf20Sopenharmony_ci	.fixup_init		= fixup_init,
11978c2ecf20Sopenharmony_ci	.fixup_activate		= fixup_activate,
11988c2ecf20Sopenharmony_ci	.fixup_destroy		= fixup_destroy,
11998c2ecf20Sopenharmony_ci	.fixup_free		= fixup_free,
12008c2ecf20Sopenharmony_ci};
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_cistatic __initdata struct self_test obj = { .static_init = 0 };
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_cistatic void __init debug_objects_selftest(void)
12058c2ecf20Sopenharmony_ci{
12068c2ecf20Sopenharmony_ci	int fixups, oldfixups, warnings, oldwarnings;
12078c2ecf20Sopenharmony_ci	unsigned long flags;
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	local_irq_save(flags);
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	fixups = oldfixups = debug_objects_fixups;
12128c2ecf20Sopenharmony_ci	warnings = oldwarnings = debug_objects_warnings;
12138c2ecf20Sopenharmony_ci	descr_test = &descr_type_test;
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	debug_object_init(&obj, &descr_type_test);
12168c2ecf20Sopenharmony_ci	if (check_results(&obj, ODEBUG_STATE_INIT, fixups, warnings))
12178c2ecf20Sopenharmony_ci		goto out;
12188c2ecf20Sopenharmony_ci	debug_object_activate(&obj, &descr_type_test);
12198c2ecf20Sopenharmony_ci	if (check_results(&obj, ODEBUG_STATE_ACTIVE, fixups, warnings))
12208c2ecf20Sopenharmony_ci		goto out;
12218c2ecf20Sopenharmony_ci	debug_object_activate(&obj, &descr_type_test);
12228c2ecf20Sopenharmony_ci	if (check_results(&obj, ODEBUG_STATE_ACTIVE, ++fixups, ++warnings))
12238c2ecf20Sopenharmony_ci		goto out;
12248c2ecf20Sopenharmony_ci	debug_object_deactivate(&obj, &descr_type_test);
12258c2ecf20Sopenharmony_ci	if (check_results(&obj, ODEBUG_STATE_INACTIVE, fixups, warnings))
12268c2ecf20Sopenharmony_ci		goto out;
12278c2ecf20Sopenharmony_ci	debug_object_destroy(&obj, &descr_type_test);
12288c2ecf20Sopenharmony_ci	if (check_results(&obj, ODEBUG_STATE_DESTROYED, fixups, warnings))
12298c2ecf20Sopenharmony_ci		goto out;
12308c2ecf20Sopenharmony_ci	debug_object_init(&obj, &descr_type_test);
12318c2ecf20Sopenharmony_ci	if (check_results(&obj, ODEBUG_STATE_DESTROYED, fixups, ++warnings))
12328c2ecf20Sopenharmony_ci		goto out;
12338c2ecf20Sopenharmony_ci	debug_object_activate(&obj, &descr_type_test);
12348c2ecf20Sopenharmony_ci	if (check_results(&obj, ODEBUG_STATE_DESTROYED, fixups, ++warnings))
12358c2ecf20Sopenharmony_ci		goto out;
12368c2ecf20Sopenharmony_ci	debug_object_deactivate(&obj, &descr_type_test);
12378c2ecf20Sopenharmony_ci	if (check_results(&obj, ODEBUG_STATE_DESTROYED, fixups, ++warnings))
12388c2ecf20Sopenharmony_ci		goto out;
12398c2ecf20Sopenharmony_ci	debug_object_free(&obj, &descr_type_test);
12408c2ecf20Sopenharmony_ci	if (check_results(&obj, ODEBUG_STATE_NONE, fixups, warnings))
12418c2ecf20Sopenharmony_ci		goto out;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	obj.static_init = 1;
12448c2ecf20Sopenharmony_ci	debug_object_activate(&obj, &descr_type_test);
12458c2ecf20Sopenharmony_ci	if (check_results(&obj, ODEBUG_STATE_ACTIVE, fixups, warnings))
12468c2ecf20Sopenharmony_ci		goto out;
12478c2ecf20Sopenharmony_ci	debug_object_init(&obj, &descr_type_test);
12488c2ecf20Sopenharmony_ci	if (check_results(&obj, ODEBUG_STATE_INIT, ++fixups, ++warnings))
12498c2ecf20Sopenharmony_ci		goto out;
12508c2ecf20Sopenharmony_ci	debug_object_free(&obj, &descr_type_test);
12518c2ecf20Sopenharmony_ci	if (check_results(&obj, ODEBUG_STATE_NONE, fixups, warnings))
12528c2ecf20Sopenharmony_ci		goto out;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_OBJECTS_FREE
12558c2ecf20Sopenharmony_ci	debug_object_init(&obj, &descr_type_test);
12568c2ecf20Sopenharmony_ci	if (check_results(&obj, ODEBUG_STATE_INIT, fixups, warnings))
12578c2ecf20Sopenharmony_ci		goto out;
12588c2ecf20Sopenharmony_ci	debug_object_activate(&obj, &descr_type_test);
12598c2ecf20Sopenharmony_ci	if (check_results(&obj, ODEBUG_STATE_ACTIVE, fixups, warnings))
12608c2ecf20Sopenharmony_ci		goto out;
12618c2ecf20Sopenharmony_ci	__debug_check_no_obj_freed(&obj, sizeof(obj));
12628c2ecf20Sopenharmony_ci	if (check_results(&obj, ODEBUG_STATE_NONE, ++fixups, ++warnings))
12638c2ecf20Sopenharmony_ci		goto out;
12648c2ecf20Sopenharmony_ci#endif
12658c2ecf20Sopenharmony_ci	pr_info("selftest passed\n");
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ciout:
12688c2ecf20Sopenharmony_ci	debug_objects_fixups = oldfixups;
12698c2ecf20Sopenharmony_ci	debug_objects_warnings = oldwarnings;
12708c2ecf20Sopenharmony_ci	descr_test = NULL;
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	local_irq_restore(flags);
12738c2ecf20Sopenharmony_ci}
12748c2ecf20Sopenharmony_ci#else
12758c2ecf20Sopenharmony_cistatic inline void debug_objects_selftest(void) { }
12768c2ecf20Sopenharmony_ci#endif
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci/*
12798c2ecf20Sopenharmony_ci * Called during early boot to initialize the hash buckets and link
12808c2ecf20Sopenharmony_ci * the static object pool objects into the poll list. After this call
12818c2ecf20Sopenharmony_ci * the object tracker is fully operational.
12828c2ecf20Sopenharmony_ci */
12838c2ecf20Sopenharmony_civoid __init debug_objects_early_init(void)
12848c2ecf20Sopenharmony_ci{
12858c2ecf20Sopenharmony_ci	int i;
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	for (i = 0; i < ODEBUG_HASH_SIZE; i++)
12888c2ecf20Sopenharmony_ci		raw_spin_lock_init(&obj_hash[i].lock);
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	for (i = 0; i < ODEBUG_POOL_SIZE; i++)
12918c2ecf20Sopenharmony_ci		hlist_add_head(&obj_static_pool[i].node, &obj_pool);
12928c2ecf20Sopenharmony_ci}
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci/*
12958c2ecf20Sopenharmony_ci * Convert the statically allocated objects to dynamic ones:
12968c2ecf20Sopenharmony_ci */
12978c2ecf20Sopenharmony_cistatic int __init debug_objects_replace_static_objects(void)
12988c2ecf20Sopenharmony_ci{
12998c2ecf20Sopenharmony_ci	struct debug_bucket *db = obj_hash;
13008c2ecf20Sopenharmony_ci	struct hlist_node *tmp;
13018c2ecf20Sopenharmony_ci	struct debug_obj *obj, *new;
13028c2ecf20Sopenharmony_ci	HLIST_HEAD(objects);
13038c2ecf20Sopenharmony_ci	int i, cnt = 0;
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	for (i = 0; i < ODEBUG_POOL_SIZE; i++) {
13068c2ecf20Sopenharmony_ci		obj = kmem_cache_zalloc(obj_cache, GFP_KERNEL);
13078c2ecf20Sopenharmony_ci		if (!obj)
13088c2ecf20Sopenharmony_ci			goto free;
13098c2ecf20Sopenharmony_ci		hlist_add_head(&obj->node, &objects);
13108c2ecf20Sopenharmony_ci	}
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	debug_objects_allocated += i;
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	/*
13158c2ecf20Sopenharmony_ci	 * debug_objects_mem_init() is now called early that only one CPU is up
13168c2ecf20Sopenharmony_ci	 * and interrupts have been disabled, so it is safe to replace the
13178c2ecf20Sopenharmony_ci	 * active object references.
13188c2ecf20Sopenharmony_ci	 */
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	/* Remove the statically allocated objects from the pool */
13218c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(obj, tmp, &obj_pool, node)
13228c2ecf20Sopenharmony_ci		hlist_del(&obj->node);
13238c2ecf20Sopenharmony_ci	/* Move the allocated objects to the pool */
13248c2ecf20Sopenharmony_ci	hlist_move_list(&objects, &obj_pool);
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	/* Replace the active object references */
13278c2ecf20Sopenharmony_ci	for (i = 0; i < ODEBUG_HASH_SIZE; i++, db++) {
13288c2ecf20Sopenharmony_ci		hlist_move_list(&db->list, &objects);
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci		hlist_for_each_entry(obj, &objects, node) {
13318c2ecf20Sopenharmony_ci			new = hlist_entry(obj_pool.first, typeof(*obj), node);
13328c2ecf20Sopenharmony_ci			hlist_del(&new->node);
13338c2ecf20Sopenharmony_ci			/* copy object data */
13348c2ecf20Sopenharmony_ci			*new = *obj;
13358c2ecf20Sopenharmony_ci			hlist_add_head(&new->node, &db->list);
13368c2ecf20Sopenharmony_ci			cnt++;
13378c2ecf20Sopenharmony_ci		}
13388c2ecf20Sopenharmony_ci	}
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	pr_debug("%d of %d active objects replaced\n",
13418c2ecf20Sopenharmony_ci		 cnt, obj_pool_used);
13428c2ecf20Sopenharmony_ci	return 0;
13438c2ecf20Sopenharmony_cifree:
13448c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(obj, tmp, &objects, node) {
13458c2ecf20Sopenharmony_ci		hlist_del(&obj->node);
13468c2ecf20Sopenharmony_ci		kmem_cache_free(obj_cache, obj);
13478c2ecf20Sopenharmony_ci	}
13488c2ecf20Sopenharmony_ci	return -ENOMEM;
13498c2ecf20Sopenharmony_ci}
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci/*
13528c2ecf20Sopenharmony_ci * Called after the kmem_caches are functional to setup a dedicated
13538c2ecf20Sopenharmony_ci * cache pool, which has the SLAB_DEBUG_OBJECTS flag set. This flag
13548c2ecf20Sopenharmony_ci * prevents that the debug code is called on kmem_cache_free() for the
13558c2ecf20Sopenharmony_ci * debug tracker objects to avoid recursive calls.
13568c2ecf20Sopenharmony_ci */
13578c2ecf20Sopenharmony_civoid __init debug_objects_mem_init(void)
13588c2ecf20Sopenharmony_ci{
13598c2ecf20Sopenharmony_ci	int cpu, extras;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	if (!debug_objects_enabled)
13628c2ecf20Sopenharmony_ci		return;
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	/*
13658c2ecf20Sopenharmony_ci	 * Initialize the percpu object pools
13668c2ecf20Sopenharmony_ci	 *
13678c2ecf20Sopenharmony_ci	 * Initialization is not strictly necessary, but was done for
13688c2ecf20Sopenharmony_ci	 * completeness.
13698c2ecf20Sopenharmony_ci	 */
13708c2ecf20Sopenharmony_ci	for_each_possible_cpu(cpu)
13718c2ecf20Sopenharmony_ci		INIT_HLIST_HEAD(&per_cpu(percpu_obj_pool.free_objs, cpu));
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	obj_cache = kmem_cache_create("debug_objects_cache",
13748c2ecf20Sopenharmony_ci				      sizeof (struct debug_obj), 0,
13758c2ecf20Sopenharmony_ci				      SLAB_DEBUG_OBJECTS | SLAB_NOLEAKTRACE,
13768c2ecf20Sopenharmony_ci				      NULL);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	if (!obj_cache || debug_objects_replace_static_objects()) {
13798c2ecf20Sopenharmony_ci		debug_objects_enabled = 0;
13808c2ecf20Sopenharmony_ci		kmem_cache_destroy(obj_cache);
13818c2ecf20Sopenharmony_ci		pr_warn("out of memory.\n");
13828c2ecf20Sopenharmony_ci		return;
13838c2ecf20Sopenharmony_ci	} else
13848c2ecf20Sopenharmony_ci		debug_objects_selftest();
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU
13878c2ecf20Sopenharmony_ci	cpuhp_setup_state_nocalls(CPUHP_DEBUG_OBJ_DEAD, "object:offline", NULL,
13888c2ecf20Sopenharmony_ci					object_cpu_offline);
13898c2ecf20Sopenharmony_ci#endif
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	/*
13928c2ecf20Sopenharmony_ci	 * Increase the thresholds for allocating and freeing objects
13938c2ecf20Sopenharmony_ci	 * according to the number of possible CPUs available in the system.
13948c2ecf20Sopenharmony_ci	 */
13958c2ecf20Sopenharmony_ci	extras = num_possible_cpus() * ODEBUG_BATCH_SIZE;
13968c2ecf20Sopenharmony_ci	debug_objects_pool_size += extras;
13978c2ecf20Sopenharmony_ci	debug_objects_pool_min_level += extras;
13988c2ecf20Sopenharmony_ci}
1399