xref: /wlan-driver/qca-wifi-host-cmn/qdf/src/qdf_talloc.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2018, 2021 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name /**
21*5113495bSYour Name  * DOC: qdf_talloc.c
22*5113495bSYour Name  *
23*5113495bSYour Name  * OS-independent talloc implementation
24*5113495bSYour Name  */
25*5113495bSYour Name 
26*5113495bSYour Name #ifdef WLAN_TALLOC_DEBUG
27*5113495bSYour Name 
28*5113495bSYour Name #include "i_qdf_talloc.h"
29*5113495bSYour Name #include "qdf_hashtable.h"
30*5113495bSYour Name #include "qdf_list.h"
31*5113495bSYour Name #include "qdf_mc_timer.h"
32*5113495bSYour Name #include "qdf_mem.h"
33*5113495bSYour Name #include "qdf_module.h"
34*5113495bSYour Name #include "qdf_status.h"
35*5113495bSYour Name #include "qdf_str.h"
36*5113495bSYour Name #include "qdf_talloc.h"
37*5113495bSYour Name 
38*5113495bSYour Name #define QDF_TALLOC_MAX_BYTES __page_size
39*5113495bSYour Name #define QDF_TALLOC_SLEEP_TIMEOUT_MS 300
40*5113495bSYour Name #define QDF_TALLOC_FUNC_NAME_SIZE 48
41*5113495bSYour Name #define QDF_TALLOC_HT_BITS 8 /* 256 buckets */
42*5113495bSYour Name 
43*5113495bSYour Name static void
__qdf_talloc_log_nomem(const size_t size,const char * func,const uint16_t line)44*5113495bSYour Name __qdf_talloc_log_nomem(const size_t size, const char *func, const uint16_t line)
45*5113495bSYour Name {
46*5113495bSYour Name 	qdf_nofl_info("Failed to alloc %zuB; via %s():%d", size, func, line);
47*5113495bSYour Name }
48*5113495bSYour Name 
49*5113495bSYour Name static void *
__qdf_zalloc_auto(const size_t size,const char * func,const uint16_t line)50*5113495bSYour Name __qdf_zalloc_auto(const size_t size, const char *func, const uint16_t line)
51*5113495bSYour Name {
52*5113495bSYour Name 	unsigned long start, duration;
53*5113495bSYour Name 	void *ptr;
54*5113495bSYour Name 
55*5113495bSYour Name 	start = qdf_mc_timer_get_system_time();
56*5113495bSYour Name 	ptr = __zalloc_auto(size);
57*5113495bSYour Name 	duration = qdf_mc_timer_get_system_time() - start;
58*5113495bSYour Name 
59*5113495bSYour Name 	if (duration > QDF_TALLOC_SLEEP_TIMEOUT_MS)
60*5113495bSYour Name 		qdf_nofl_info("Alloc slept; %lums, %zuB; via %s():%d",
61*5113495bSYour Name 			      duration, size, func, line);
62*5113495bSYour Name 
63*5113495bSYour Name 	if (!ptr) {
64*5113495bSYour Name 		__qdf_talloc_log_nomem(size, func, line);
65*5113495bSYour Name 		return NULL;
66*5113495bSYour Name 	}
67*5113495bSYour Name 
68*5113495bSYour Name 	qdf_mem_kmalloc_inc(__qdf_alloc_size(ptr));
69*5113495bSYour Name 
70*5113495bSYour Name 	return ptr;
71*5113495bSYour Name }
72*5113495bSYour Name 
73*5113495bSYour Name static void *
__qdf_zalloc_atomic(const size_t size,const char * func,const uint16_t line)74*5113495bSYour Name __qdf_zalloc_atomic(const size_t size, const char *func, const uint16_t line)
75*5113495bSYour Name {
76*5113495bSYour Name 	void *ptr;
77*5113495bSYour Name 
78*5113495bSYour Name 	ptr = __zalloc_atomic(size);
79*5113495bSYour Name 	if (!ptr) {
80*5113495bSYour Name 		__qdf_talloc_log_nomem(size, func, line);
81*5113495bSYour Name 		return NULL;
82*5113495bSYour Name 	}
83*5113495bSYour Name 
84*5113495bSYour Name 	qdf_mem_kmalloc_inc(__qdf_alloc_size(ptr));
85*5113495bSYour Name 
86*5113495bSYour Name 	return ptr;
87*5113495bSYour Name }
88*5113495bSYour Name 
__qdf_free(const void * ptr)89*5113495bSYour Name static void __qdf_free(const void *ptr)
90*5113495bSYour Name {
91*5113495bSYour Name 	qdf_mem_kmalloc_dec(__qdf_alloc_size(ptr));
92*5113495bSYour Name 
93*5113495bSYour Name 	__k_free(ptr);
94*5113495bSYour Name }
95*5113495bSYour Name 
96*5113495bSYour Name static qdf_ht_declare(__qdf_talloc_meta_ht, QDF_TALLOC_HT_BITS);
97*5113495bSYour Name static qdf_spinlock_t __qdf_talloc_meta_lock;
98*5113495bSYour Name 
99*5113495bSYour Name /**
100*5113495bSYour Name  * struct qdf_talloc_parent_meta - parent/children metadata for memory tracking
101*5113495bSYour Name  * @entry: entry for membership in the parent hashtable
102*5113495bSYour Name  * @key: parent
103*5113495bSYour Name  * @children: list of associated children
104*5113495bSYour Name  */
105*5113495bSYour Name struct qdf_talloc_parent_meta {
106*5113495bSYour Name 	struct qdf_ht_entry entry;
107*5113495bSYour Name 	uintptr_t key;
108*5113495bSYour Name 	qdf_list_t children;
109*5113495bSYour Name };
110*5113495bSYour Name 
111*5113495bSYour Name static struct qdf_talloc_parent_meta *
qdf_talloc_parent_meta_alloc(const void * parent,const char * func,const uint16_t line)112*5113495bSYour Name qdf_talloc_parent_meta_alloc(const void *parent,
113*5113495bSYour Name 			     const char *func, const uint16_t line)
114*5113495bSYour Name {
115*5113495bSYour Name 	struct qdf_talloc_parent_meta *pmeta;
116*5113495bSYour Name 
117*5113495bSYour Name 	pmeta = __qdf_zalloc_atomic(sizeof(*pmeta), func, line);
118*5113495bSYour Name 	if (!pmeta)
119*5113495bSYour Name 		return NULL;
120*5113495bSYour Name 
121*5113495bSYour Name 	pmeta->key = (uintptr_t)parent;
122*5113495bSYour Name 	qdf_list_create(&pmeta->children, 0);
123*5113495bSYour Name 	qdf_ht_add(__qdf_talloc_meta_ht, &pmeta->entry, pmeta->key);
124*5113495bSYour Name 
125*5113495bSYour Name 	return pmeta;
126*5113495bSYour Name }
127*5113495bSYour Name 
qdf_talloc_parent_meta_free(struct qdf_talloc_parent_meta * pmeta)128*5113495bSYour Name static void qdf_talloc_parent_meta_free(struct qdf_talloc_parent_meta *pmeta)
129*5113495bSYour Name {
130*5113495bSYour Name 	qdf_ht_remove(&pmeta->entry);
131*5113495bSYour Name 	qdf_list_destroy(&pmeta->children);
132*5113495bSYour Name 	__k_free(pmeta);
133*5113495bSYour Name }
134*5113495bSYour Name 
135*5113495bSYour Name static struct qdf_talloc_parent_meta *
qdf_talloc_parent_meta_lookup(const void * parent)136*5113495bSYour Name qdf_talloc_parent_meta_lookup(const void *parent)
137*5113495bSYour Name {
138*5113495bSYour Name 	struct qdf_talloc_parent_meta *pmeta;
139*5113495bSYour Name 	uintptr_t key = (uintptr_t)parent;
140*5113495bSYour Name 
141*5113495bSYour Name 	qdf_ht_get(__qdf_talloc_meta_ht, pmeta, entry, key, key);
142*5113495bSYour Name 
143*5113495bSYour Name 	return pmeta;
144*5113495bSYour Name }
145*5113495bSYour Name 
146*5113495bSYour Name /**
147*5113495bSYour Name  * struct qdf_talloc_child_meta - talloc child debug information
148*5113495bSYour Name  * @parent: parent pointer used during allocation for leak tracking
149*5113495bSYour Name  * @node: list node for membership in @parent's children list
150*5113495bSYour Name  * @func: name of the function that requested the allocation
151*5113495bSYour Name  * @line: line number of the call site in @func
152*5113495bSYour Name  * @size: size of the allocation in bytes
153*5113495bSYour Name  * @guard: a known value, used to detect out-of-bounds access
154*5113495bSYour Name  */
155*5113495bSYour Name struct qdf_talloc_child_meta {
156*5113495bSYour Name 	const void *parent;
157*5113495bSYour Name 	qdf_list_node_t node;
158*5113495bSYour Name 	char func[QDF_TALLOC_FUNC_NAME_SIZE];
159*5113495bSYour Name 	uint16_t line;
160*5113495bSYour Name 	uint32_t size;
161*5113495bSYour Name 	uint32_t guard;
162*5113495bSYour Name };
163*5113495bSYour Name 
164*5113495bSYour Name /**
165*5113495bSYour Name  * struct qdf_talloc_header - talloc debug header information
166*5113495bSYour Name  * @meta: child allocation metadata
167*5113495bSYour Name  * @guard: a known value, used to detect out-of-bounds access
168*5113495bSYour Name  */
169*5113495bSYour Name struct qdf_talloc_header {
170*5113495bSYour Name 	struct qdf_talloc_child_meta meta;
171*5113495bSYour Name 	uint32_t guard;
172*5113495bSYour Name };
173*5113495bSYour Name 
174*5113495bSYour Name /**
175*5113495bSYour Name  * struct qdf_talloc_trailer - talloc debug trailer information
176*5113495bSYour Name  * @guard: a known value, used to detect out-of-bounds access
177*5113495bSYour Name  */
178*5113495bSYour Name struct qdf_talloc_trailer {
179*5113495bSYour Name 	uint32_t guard;
180*5113495bSYour Name };
181*5113495bSYour Name 
182*5113495bSYour Name static uint32_t QDF_TALLOC_GUARD = 0xaabbeeff;
183*5113495bSYour Name 
184*5113495bSYour Name #define QDF_TALLOC_DEBUG_SIZE \
185*5113495bSYour Name 	(sizeof(struct qdf_talloc_header) + sizeof(struct qdf_talloc_trailer))
186*5113495bSYour Name 
qdf_talloc_header(void * ptr)187*5113495bSYour Name static struct qdf_talloc_header *qdf_talloc_header(void *ptr)
188*5113495bSYour Name {
189*5113495bSYour Name 	return (struct qdf_talloc_header *)ptr - 1;
190*5113495bSYour Name }
191*5113495bSYour Name 
qdf_talloc_ptr(struct qdf_talloc_header * header)192*5113495bSYour Name static void *qdf_talloc_ptr(struct qdf_talloc_header *header)
193*5113495bSYour Name {
194*5113495bSYour Name 	return header + 1;
195*5113495bSYour Name }
196*5113495bSYour Name 
197*5113495bSYour Name static struct qdf_talloc_trailer *
qdf_talloc_trailer(struct qdf_talloc_header * header)198*5113495bSYour Name qdf_talloc_trailer(struct qdf_talloc_header *header)
199*5113495bSYour Name {
200*5113495bSYour Name 	void *ptr = qdf_talloc_ptr(header);
201*5113495bSYour Name 	size_t size = header->meta.size;
202*5113495bSYour Name 
203*5113495bSYour Name 	return (struct qdf_talloc_trailer *)((uint8_t *)ptr + size);
204*5113495bSYour Name }
205*5113495bSYour Name 
qdf_talloc_meta_init(struct qdf_talloc_header * header,const void * parent,const size_t size,const char * func,const uint16_t line)206*5113495bSYour Name static void qdf_talloc_meta_init(struct qdf_talloc_header *header,
207*5113495bSYour Name 				 const void *parent, const size_t size,
208*5113495bSYour Name 				 const char *func, const uint16_t line)
209*5113495bSYour Name {
210*5113495bSYour Name 	struct qdf_talloc_trailer *trailer;
211*5113495bSYour Name 
212*5113495bSYour Name 	/* copy the function name to support multi-*.ko configurations */
213*5113495bSYour Name 	qdf_str_lcopy(header->meta.func, func, sizeof(header->meta.func));
214*5113495bSYour Name 	header->meta.parent = parent;
215*5113495bSYour Name 	header->meta.line = line;
216*5113495bSYour Name 	header->meta.size = size;
217*5113495bSYour Name 	header->guard = QDF_TALLOC_GUARD;
218*5113495bSYour Name 
219*5113495bSYour Name 	trailer = qdf_talloc_trailer(header);
220*5113495bSYour Name 	trailer->guard = QDF_TALLOC_GUARD;
221*5113495bSYour Name }
222*5113495bSYour Name 
qdf_talloc_meta_assert_valid(struct qdf_talloc_header * header,const char * func,const uint16_t line)223*5113495bSYour Name static bool qdf_talloc_meta_assert_valid(struct qdf_talloc_header *header,
224*5113495bSYour Name 					 const char *func, const uint16_t line)
225*5113495bSYour Name {
226*5113495bSYour Name 	struct qdf_talloc_trailer *trailer = qdf_talloc_trailer(header);
227*5113495bSYour Name 	bool is_valid = true;
228*5113495bSYour Name 
229*5113495bSYour Name 	if (header->guard != QDF_TALLOC_GUARD) {
230*5113495bSYour Name 		qdf_nofl_alert("Corrupted header guard 0x%x (expected 0x%x)",
231*5113495bSYour Name 			       header->guard, QDF_TALLOC_GUARD);
232*5113495bSYour Name 		is_valid = false;
233*5113495bSYour Name 	}
234*5113495bSYour Name 
235*5113495bSYour Name 	if (header->meta.size > QDF_TALLOC_MAX_BYTES) {
236*5113495bSYour Name 		qdf_nofl_alert("Corrupted allocation size %u (expected <= %zu)",
237*5113495bSYour Name 			       header->meta.size, QDF_TALLOC_MAX_BYTES);
238*5113495bSYour Name 		is_valid = false;
239*5113495bSYour Name 	}
240*5113495bSYour Name 
241*5113495bSYour Name 	if (!qdf_list_node_in_any_list(&header->meta.node)) {
242*5113495bSYour Name 		qdf_nofl_alert("Corrupted header node or double free");
243*5113495bSYour Name 		is_valid = false;
244*5113495bSYour Name 	}
245*5113495bSYour Name 
246*5113495bSYour Name 	if (trailer->guard != QDF_TALLOC_GUARD) {
247*5113495bSYour Name 		qdf_nofl_alert("Corrupted trailer guard 0x%x (expected 0x%x)",
248*5113495bSYour Name 			       trailer->guard, QDF_TALLOC_GUARD);
249*5113495bSYour Name 		is_valid = false;
250*5113495bSYour Name 	}
251*5113495bSYour Name 
252*5113495bSYour Name 	if (!is_valid)
253*5113495bSYour Name 		QDF_DEBUG_PANIC("Fatal memory error detected @ %s():%d",
254*5113495bSYour Name 				func, line);
255*5113495bSYour Name 
256*5113495bSYour Name 	return is_valid;
257*5113495bSYour Name }
258*5113495bSYour Name 
qdf_leaks_print_header(void)259*5113495bSYour Name static void qdf_leaks_print_header(void)
260*5113495bSYour Name {
261*5113495bSYour Name 	qdf_nofl_alert("-----------------------------------------------------");
262*5113495bSYour Name 	qdf_nofl_alert(" size      function():line");
263*5113495bSYour Name 	qdf_nofl_alert("-----------------------------------------------------");
264*5113495bSYour Name }
265*5113495bSYour Name 
qdf_leaks_print(const struct qdf_talloc_parent_meta * pmeta)266*5113495bSYour Name static uint32_t qdf_leaks_print(const struct qdf_talloc_parent_meta *pmeta)
267*5113495bSYour Name {
268*5113495bSYour Name 	struct qdf_talloc_child_meta *cmeta;
269*5113495bSYour Name 	uint32_t count = 0;
270*5113495bSYour Name 
271*5113495bSYour Name 	qdf_list_for_each(&pmeta->children, cmeta, node) {
272*5113495bSYour Name 		qdf_nofl_alert("%6uB @ %s():%u",
273*5113495bSYour Name 			       cmeta->size, cmeta->func, cmeta->line);
274*5113495bSYour Name 		count++;
275*5113495bSYour Name 	}
276*5113495bSYour Name 
277*5113495bSYour Name 	return count;
278*5113495bSYour Name }
279*5113495bSYour Name 
280*5113495bSYour Name #define qdf_leaks_panic(count, func, line) \
281*5113495bSYour Name 	QDF_DEBUG_PANIC("%u fatal memory leaks detected @ %s():%u", \
282*5113495bSYour Name 			count, func, line)
283*5113495bSYour Name 
qdf_talloc_feature_init(void)284*5113495bSYour Name QDF_STATUS qdf_talloc_feature_init(void)
285*5113495bSYour Name {
286*5113495bSYour Name 	qdf_spinlock_create(&__qdf_talloc_meta_lock);
287*5113495bSYour Name 	qdf_ht_init(__qdf_talloc_meta_ht);
288*5113495bSYour Name 
289*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
290*5113495bSYour Name }
291*5113495bSYour Name qdf_export_symbol(qdf_talloc_feature_init);
292*5113495bSYour Name 
qdf_talloc_feature_deinit(void)293*5113495bSYour Name void qdf_talloc_feature_deinit(void)
294*5113495bSYour Name {
295*5113495bSYour Name 	qdf_spin_lock_bh(&__qdf_talloc_meta_lock);
296*5113495bSYour Name 
297*5113495bSYour Name 	if (!qdf_ht_empty(__qdf_talloc_meta_ht)) {
298*5113495bSYour Name 		struct qdf_talloc_parent_meta *pmeta;
299*5113495bSYour Name 		uint32_t count = 0;
300*5113495bSYour Name 		int i;
301*5113495bSYour Name 
302*5113495bSYour Name 		qdf_leaks_print_header();
303*5113495bSYour Name 
304*5113495bSYour Name 		qdf_ht_for_each(__qdf_talloc_meta_ht, i, pmeta, entry)
305*5113495bSYour Name 			count += qdf_leaks_print(pmeta);
306*5113495bSYour Name 
307*5113495bSYour Name 		qdf_leaks_panic(count, __func__, __LINE__);
308*5113495bSYour Name 	}
309*5113495bSYour Name 
310*5113495bSYour Name 	qdf_spin_unlock_bh(&__qdf_talloc_meta_lock);
311*5113495bSYour Name 
312*5113495bSYour Name 	qdf_ht_deinit(__qdf_talloc_meta_ht);
313*5113495bSYour Name 	qdf_spinlock_destroy(&__qdf_talloc_meta_lock);
314*5113495bSYour Name }
315*5113495bSYour Name qdf_export_symbol(qdf_talloc_feature_deinit);
316*5113495bSYour Name 
qdf_talloc_meta_insert(struct qdf_talloc_header * header,const char * func,const uint16_t line)317*5113495bSYour Name static QDF_STATUS qdf_talloc_meta_insert(struct qdf_talloc_header *header,
318*5113495bSYour Name 					 const char *func, const uint16_t line)
319*5113495bSYour Name {
320*5113495bSYour Name 	struct qdf_talloc_child_meta *cmeta = &header->meta;
321*5113495bSYour Name 	struct qdf_talloc_parent_meta *pmeta;
322*5113495bSYour Name 
323*5113495bSYour Name 	pmeta = qdf_talloc_parent_meta_lookup(cmeta->parent);
324*5113495bSYour Name 	if (!pmeta)
325*5113495bSYour Name 		pmeta = qdf_talloc_parent_meta_alloc(cmeta->parent, func, line);
326*5113495bSYour Name 	if (!pmeta)
327*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
328*5113495bSYour Name 
329*5113495bSYour Name 	qdf_list_insert_back(&pmeta->children, &cmeta->node);
330*5113495bSYour Name 
331*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
332*5113495bSYour Name }
333*5113495bSYour Name 
__qdf_talloc_fl(const void * parent,const size_t size,const char * func,const uint16_t line)334*5113495bSYour Name void *__qdf_talloc_fl(const void *parent, const size_t size,
335*5113495bSYour Name 		      const char *func, const uint16_t line)
336*5113495bSYour Name {
337*5113495bSYour Name 	QDF_STATUS status;
338*5113495bSYour Name 	struct qdf_talloc_header *header;
339*5113495bSYour Name 
340*5113495bSYour Name 	QDF_BUG(parent);
341*5113495bSYour Name 	if (!parent)
342*5113495bSYour Name 		return NULL;
343*5113495bSYour Name 
344*5113495bSYour Name 	QDF_BUG(size <= QDF_TALLOC_MAX_BYTES);
345*5113495bSYour Name 	if (size > QDF_TALLOC_MAX_BYTES)
346*5113495bSYour Name 		return NULL;
347*5113495bSYour Name 
348*5113495bSYour Name 	header = __qdf_zalloc_auto(size + QDF_TALLOC_DEBUG_SIZE, func, line);
349*5113495bSYour Name 	if (!header)
350*5113495bSYour Name 		return NULL;
351*5113495bSYour Name 
352*5113495bSYour Name 	qdf_talloc_meta_init(header, parent, size, func, line);
353*5113495bSYour Name 
354*5113495bSYour Name 	qdf_spin_lock_bh(&__qdf_talloc_meta_lock);
355*5113495bSYour Name 	status = qdf_talloc_meta_insert(header, func, line);
356*5113495bSYour Name 	qdf_spin_unlock_bh(&__qdf_talloc_meta_lock);
357*5113495bSYour Name 
358*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
359*5113495bSYour Name 		__qdf_free(header);
360*5113495bSYour Name 		return NULL;
361*5113495bSYour Name 	}
362*5113495bSYour Name 
363*5113495bSYour Name 	return qdf_talloc_ptr(header);
364*5113495bSYour Name }
365*5113495bSYour Name qdf_export_symbol(__qdf_talloc_fl);
366*5113495bSYour Name 
367*5113495bSYour Name static void
__qdf_talloc_assert_no_children(const void * parent,const char * func,const uint16_t line)368*5113495bSYour Name __qdf_talloc_assert_no_children(const void *parent,
369*5113495bSYour Name 				const char *func, const uint16_t line)
370*5113495bSYour Name {
371*5113495bSYour Name 	struct qdf_talloc_parent_meta *pmeta;
372*5113495bSYour Name 	uint32_t count;
373*5113495bSYour Name 
374*5113495bSYour Name 	pmeta = qdf_talloc_parent_meta_lookup(parent);
375*5113495bSYour Name 	if (!pmeta)
376*5113495bSYour Name 		return;
377*5113495bSYour Name 
378*5113495bSYour Name 	qdf_leaks_print_header();
379*5113495bSYour Name 	count = qdf_leaks_print(pmeta);
380*5113495bSYour Name 	qdf_leaks_panic(count, func, line);
381*5113495bSYour Name }
382*5113495bSYour Name 
qdf_talloc_meta_remove(struct qdf_talloc_header * header,const char * func,const uint16_t line)383*5113495bSYour Name static void qdf_talloc_meta_remove(struct qdf_talloc_header *header,
384*5113495bSYour Name 				   const char *func, const uint16_t line)
385*5113495bSYour Name {
386*5113495bSYour Name 	struct qdf_talloc_child_meta *cmeta = &header->meta;
387*5113495bSYour Name 	struct qdf_talloc_parent_meta *pmeta;
388*5113495bSYour Name 
389*5113495bSYour Name 	__qdf_talloc_assert_no_children(qdf_talloc_ptr(header), func, line);
390*5113495bSYour Name 
391*5113495bSYour Name 	pmeta = qdf_talloc_parent_meta_lookup(cmeta->parent);
392*5113495bSYour Name 	if (!pmeta) {
393*5113495bSYour Name 		QDF_DEBUG_PANIC("double-free or free-no-allocate @ %s():%u",
394*5113495bSYour Name 				func, line);
395*5113495bSYour Name 		return;
396*5113495bSYour Name 	}
397*5113495bSYour Name 
398*5113495bSYour Name 	qdf_list_remove_node(&pmeta->children, &cmeta->node);
399*5113495bSYour Name 
400*5113495bSYour Name 	if (qdf_list_empty(&pmeta->children))
401*5113495bSYour Name 		qdf_talloc_parent_meta_free(pmeta);
402*5113495bSYour Name }
403*5113495bSYour Name 
__qdf_tfree_fl(void * ptr,const char * func,const uint16_t line)404*5113495bSYour Name void __qdf_tfree_fl(void *ptr, const char *func, const uint16_t line)
405*5113495bSYour Name {
406*5113495bSYour Name 	struct qdf_talloc_header *header;
407*5113495bSYour Name 
408*5113495bSYour Name 	QDF_BUG(ptr);
409*5113495bSYour Name 	if (!ptr)
410*5113495bSYour Name 		return;
411*5113495bSYour Name 
412*5113495bSYour Name 	header = qdf_talloc_header(ptr);
413*5113495bSYour Name 	qdf_talloc_meta_assert_valid(header, func, line);
414*5113495bSYour Name 
415*5113495bSYour Name 	qdf_spin_lock_bh(&__qdf_talloc_meta_lock);
416*5113495bSYour Name 	qdf_talloc_meta_remove(header, func, line);
417*5113495bSYour Name 	qdf_spin_unlock_bh(&__qdf_talloc_meta_lock);
418*5113495bSYour Name 
419*5113495bSYour Name 	__qdf_free(header);
420*5113495bSYour Name }
421*5113495bSYour Name qdf_export_symbol(__qdf_tfree_fl);
422*5113495bSYour Name 
qdf_talloc_assert_no_children_fl(const void * parent,const char * func,const uint16_t line)423*5113495bSYour Name void qdf_talloc_assert_no_children_fl(const void *parent,
424*5113495bSYour Name 				      const char *func, const uint16_t line)
425*5113495bSYour Name {
426*5113495bSYour Name 	qdf_spin_lock_bh(&__qdf_talloc_meta_lock);
427*5113495bSYour Name 	__qdf_talloc_assert_no_children(parent, func, line);
428*5113495bSYour Name 	qdf_spin_unlock_bh(&__qdf_talloc_meta_lock);
429*5113495bSYour Name }
430*5113495bSYour Name qdf_export_symbol(qdf_talloc_assert_no_children_fl);
431*5113495bSYour Name 
432*5113495bSYour Name #endif /* WLAN_TALLOC_DEBUG */
433*5113495bSYour Name 
434