blob: c823e9c631325f94f4727261bfcf7e81d2c0b030 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/*
2 * linux/mm/mem_tracker.c
3 *
4 * Copyright (C) 1993 Linus Torvalds
5 * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
6 * vmalloc/vfree, Tigran Aivazian <tigran@veritas.com>, May 2000
7 * Major rework to support vmap/vunmap, Christoph Hellwig, SGI, August 2002
8 * Numa awareness, Christoph Lameter, SGI, June 2005
9 */
10#include <linux/mm.h>
11#include <linux/sched.h>
12#include <linux/spinlock.h>
13#include <linux/interrupt.h>
14#include <linux/kallsyms.h>
15#include <linux/list.h>
16#include <linux/pfn.h>
17#include <linux/atomic.h>
18#include <asm/stacktrace.h>
19#include <mach/iomap.h>
20#include <linux/kprobes.h>
21#include <asm/traps.h>
22#include <linux/mem_tracker_def.h>
23
24/*******************************************************************************
25* ºê¶¨Òå *
26*******************************************************************************/
xf.libe704612024-05-28 19:09:12 -070027#undef CONFIG_KALLSYMS
28
lh9ed821d2023-04-07 01:36:19 -070029#ifdef CONFIG_KALLSYMS
30#define MEM_TRACKER_MAX_STACK_LEN (100) /*Õ»º¯Êý¹ì¼£µÄ×Ö·û¸öÊýÉÏÏÞ£»*/
31#endif
32#define MEM_TRACKER_MAX_STACK_LEVEL (6) /*Õ»µÄ²ãÊý*/
33#define MEM_TRACKER_NOT_TRACE_LEVEL (2)
34#define MEM_TRACKER_ALLOCED 0x00
35#define MEM_TRACKER_FREED 0x02
36
37/*******************************************************************************
38* Êý¾ÝÀàÐͶ¨Òå *
39*******************************************************************************/
40struct heap_record {
41 struct list_head node;
42 void *addr; /*ÉêÇë³öµÄÄÚ´æµØÖ·*/
43 unsigned int employ:8;
44 unsigned int size:24; /*¼Ç¼ÉêÇëµÄÄڴ泤¶È*/
45 char task_name[TASK_COMM_LEN];
46#ifdef CONFIG_KALLSYMS
47 char stack_frame[MEM_TRACKER_MAX_STACK_LEVEL][MEM_TRACKER_MAX_STACK_LEN];
48 /*º¯Êý»ØËݹ켣*/
49#else
50 unsigned long stack_frame[MEM_TRACKER_MAX_STACK_LEVEL];
51#endif
52};
53
54/*******************************************************************************
55* º¯ÊýÉùÃ÷ *
56*******************************************************************************/
57/*******************************************************************************
58* È«¾Ö±äÁ¿¶¨Òå *
59*******************************************************************************/
60int kmem_node_max;
61int node_list_max;
62static spinlock_t buddy_track_lock;
63static spinlock_t kmem_track_lock;
64
65
66/*ÕýÔÚʹÓõÄÊý¾ÝÁ´±í*/
67static LIST_HEAD(buddy_employ_head);
68static LIST_HEAD(kmem_employ_head);
69
70/*ÒѾ­ÊͷŵÄÊý¾ÝÁ´±í*/
71static LIST_HEAD(buddy_free_head);
72static LIST_HEAD(kmem_free_head);
73
74/*******************************************************************************
75* ¾Ö²¿º¯ÊýʵÏÖ *
76*******************************************************************************/
77static void memset_tracker(struct heap_record * node)
78{
79 node->size = 0;
80 node->addr = NULL;
81
82 memset(node->task_name,0, TASK_COMM_LEN);
83 memset(node->stack_frame, 0, sizeof(node->stack_frame));
84}
85
86/*******************************************************************************
87* ¹¦ÄÜÃèÊö: ¶Ôµ±Ç°Õ»½øÐлØËÝ£¬½«º¯Êý¹ì¼£±£´æ
88* ²ÎÊý˵Ã÷:
89* (´«Èë²ÎÊý) my_frame:¹ì¼£ÐÅÏ¢±£´æµÄµØÖ·
90*
91* (´«³ö²ÎÊý) void
92* ·µ »Ø Öµ: void
93* ÆäËü˵Ã÷: ÎÞ
94*******************************************************************************/
95#ifdef CONFIG_KALLSYMS
96void get_stack_process(unsigned char *my_frame)
97#else
98void get_stack_process(unsigned long *my_frame)
99#endif
100{
101 int urc;
102 int i = 0;
103#ifdef CONFIG_KALLSYMS
104 char mytmp[MEM_TRACKER_MAX_STACK_LEN] = {0};
105#endif
106 struct stackframe frame;
107 register unsigned long current_sp asm ("sp");
108
109#ifndef CONFIG_KALLSYMS
110 memset(my_frame, 0, MEM_TRACKER_MAX_STACK_LEVEL * sizeof(unsigned long));
111#endif
112
113 frame.fp = (unsigned long)__builtin_frame_address(0);
114 frame.lr = (unsigned long)__builtin_return_address(0);
115 frame.sp = current_sp;
116 frame.pc = (unsigned long)get_stack_process;
117
118 while (1) {
119 urc = unwind_frame(&frame);
120 /*Èô»ØËݽáÊø£¬ÔòÁ¢¼´Í˳ö*/
121 if (urc < 0)
122 return;
123
124 /*ΪÁ˽ÚÊ¡Äڴ棬×îÉϲãµÄ2¸öº¯Êý²»¸ú×Ù*/
125 if (++i >= MEM_TRACKER_NOT_TRACE_LEVEL) {
126#ifdef CONFIG_KALLSYMS
127 snprintf(mytmp, MEM_TRACKER_MAX_STACK_LEN - 1, "<%ps>", (void *)frame.pc);
128 strcpy(my_frame + ((i - MEM_TRACKER_NOT_TRACE_LEVEL) * MEM_TRACKER_MAX_STACK_LEN), mytmp);
129#else
130 my_frame[i - MEM_TRACKER_NOT_TRACE_LEVEL] = (unsigned long)frame.pc;
131#endif
132 if (i - MEM_TRACKER_NOT_TRACE_LEVEL >= MEM_TRACKER_MAX_STACK_LEVEL - 1)
133 return;
134 }
135 }
136}
137
138/*******************************************************************************
139* ¹¦ÄÜÃèÊö: »ñÈ¡×îºóÒ»¸ö½Úµã
140* ²ÎÊý˵Ã÷:
141* (´«Èë²ÎÊý) head:Á´±íÍ·
142* (´«³ö²ÎÊý) track¸ú×ÙÐÅÏ¢
143* ·µ »Ø Öµ: void
144* ÆäËü˵Ã÷: ÎÞ
145*******************************************************************************/
146static struct list_head *list_get_last_node(struct list_head *head)
147{
148 struct heap_record *h = NULL;
149 struct list_head *tail_node = NULL;
150
151 if (list_empty(head))
152 return NULL;
153
154 tail_node = head->prev;
155
156 h = container_of(tail_node, struct heap_record, node);
157
158 if(h->employ == MEM_TRACKER_FREED)
159 list_del(head->prev);
160 else
161 panic("[MEM_TRACKER]list error");
162
163 return tail_node;
164}
165
166/*******************************************************************************
167* ¹¦ÄÜÃèÊö: ÄÚ´æ¸ú×Ù³õʼ»¯
168* ²ÎÊý˵Ã÷:
169* (´«Èë²ÎÊý) void
170* (´«³ö²ÎÊý) void
171* ·µ »Ø Öµ: void
172* ÆäËü˵Ã÷: ΪʵÏÖÄÚ´æ¹ì¼£¸ú×Ùʱ²»Õ¼ÓÃÏÖÓÐÄڴ棬ʹÓÃ64MÒÔºóµÄÄÚ´æ
173*******************************************************************************/
174void mem_trace_init(void)
175{
176 int index;
177 unsigned long flags;
178 struct heap_record *record = NULL;
179 void __iomem *base = NULL;
180
181 spin_lock_init(&buddy_track_lock);
182
183 spin_lock_irqsave(&buddy_track_lock, flags);
184
185 base = ZX_MEM_TRACKER_BASE;
186 node_list_max = ZX_MEM_TRACKER_SIZE / sizeof(struct heap_record);
187
188 /* ³õʼ»¯¿ÕÏÐÄÚ´æ½ÚµãÁ´±í */
189 for (index = 0; index < node_list_max; index++)
190 {
191 record = (struct heap_record *)(base + index * sizeof(struct heap_record));
192 record->employ = MEM_TRACKER_FREED;
193 list_add(&record->node, &buddy_free_head);
194 }
195
196 spin_unlock_irqrestore(&buddy_track_lock, flags);
197}
198
199
200/*******************************************************************************
201* ¹¦ÄÜÃèÊö: kmallocÄÚ´æ¸ú×Ù³õʼ»¯
202* ²ÎÊý˵Ã÷:
203* (´«Èë²ÎÊý) void
204* (´«³ö²ÎÊý) void
205* ·µ »Ø Öµ: void
206* ÆäËü˵Ã÷: ΪʵÏÖÄÚ´æ¹ì¼£¸ú×Ùʱ²»Õ¼ÓÃÏÖÓÐÄڴ棬ʹÓÃ64MÒÔºóµÄÄÚ´æ
207*******************************************************************************/
208void kmalloc_trace_init(void)
209{
210 int index;
211 unsigned long flags;
212 struct heap_record *record = NULL;
213 void __iomem *base = NULL;
214
215 spin_lock_init(&kmem_track_lock);
216 spin_lock_irqsave(&kmem_track_lock, flags);
217
218 base = ZX_KMALLOC_TRACKER_BASE;
219 kmem_node_max = ZX_KMALLOC_TRACKER_SIZE / sizeof(struct heap_record);
220
221 /* ³õʼ»¯¿ÕÏÐÄÚ´æ½ÚµãÁ´±í */
222 for (index = 0; index < kmem_node_max; index++)
223 {
224 record = (struct heap_record *)(base + index * sizeof(struct heap_record));
225 record->employ = MEM_TRACKER_FREED;
226 list_add(&record->node, &kmem_free_head);
227 }
228
229 spin_unlock_irqrestore(&kmem_track_lock, flags);
230}
231
232/*******************************************************************************
233* ¹¦ÄÜÃèÊö: ÑéÖ¤entry½ÚµãºÏ·¨ÐÔ
234* ²ÎÊý˵Ã÷:
235* (´«Èë²ÎÊý) void
236* (´«³ö²ÎÊý) void
237* ·µ »Ø Öµ: void
238* ÆäËü˵Ã÷: ΪʵÏÖÄÚ´æ¹ì¼£¸ú×Ùʱ²»Õ¼ÓÃÏÖÓÐÄڴ棬ʹÓÃ64MÒÔºóµÄÄÚ´æ
239*******************************************************************************/
240int check_node_entry(const int entry)
241{
242 void __iomem *base = NULL;
243 long limit = 0;
244
245 base = ZX_KMALLOC_TRACKER_BASE;
246 limit = ZX_KMALLOC_TRACKER_SIZE + (int)base;
247
248 if ((entry >= base) && (entry < limit))
249 return MEM_TRUE;
250
251 return MEM_FALSE;
252}
253
254/*******************************************************************************
255* ¹¦ÄÜÃèÊö: ÉêÇëÄÚ´æµãµ÷Óøýӿڣ¬¼Ç¼ÄÚ´æÉêÇë¹ì¼£
256* ²ÎÊý˵Ã÷:
257* (´«Èë²ÎÊý) addr:ÄÚ´æµØÖ·
258* order:Äڴ泤¶È,orderΪµ¥Î»£¬2µÄorder´Î·½¸öÒ³
259* (´«³ö²ÎÊý) void
260* ·µ »Ø Öµ: void
261* ÆäËü˵Ã÷: ÎÞ
262*******************************************************************************/
263void mem_alloc_tracker(void *addr, int order)
264{
265 unsigned long spin_flag;
266 struct heap_record *section = NULL;
267 struct list_head *head_ptr = NULL;
268 struct page *page_addr = NULL;
269
270 if(!addr)
271 panic("[MEM_TRACKER] input item error\n");
272
273 page_addr = (struct page *)(addr);
274
275 spin_lock_irqsave(&buddy_track_lock, spin_flag);
276 if (!(head_ptr = list_get_last_node(&buddy_free_head)))
277 {
278 printk("[MEM_TRACKER]buddy free_link_node have no node!!!\n");
279 spin_unlock_irqrestore(&buddy_track_lock, spin_flag);
280 return;
281 }
282 spin_unlock_irqrestore(&buddy_track_lock, spin_flag);
283 section = container_of(head_ptr, struct heap_record, node);
284
285 /*³õʼ»¯½ÚµãÐÅÏ¢*/
286 memset_tracker(section);
287 section->addr = addr;
288 section->size = (1 << order) * PAGE_SIZE;
289 section->employ = MEM_TRACKER_ALLOCED;
290 memcpy(section->task_name, current->comm, TASK_COMM_LEN);
291
292 /*»ñȡջ¹ì¼£*/
293 get_stack_process(section->stack_frame);
294 page_addr->mem_track_entry = section;
295
296 /*¼ÓÈëÒÑÉêÇëÄÚ´æ½Úµã¼Ç¼Á´±í*/
297 spin_lock_irqsave(&buddy_track_lock, spin_flag);
298 list_add(&section->node, &buddy_employ_head);
299 spin_unlock_irqrestore(&buddy_track_lock,spin_flag);
300}
301EXPORT_SYMBOL(mem_alloc_tracker);
302
303/*******************************************************************************
304* ¹¦ÄÜÃèÊö: kmallocÉêÇëÄÚ´æµãµ÷Óøýӿڣ¬¼Ç¼ÄÚ´æÉêÇë¹ì¼£
305* ²ÎÊý˵Ã÷:
306* (´«Èë²ÎÊý) addr:ÄÚ´æµØÖ·
307* len:Äڴ泤¶È
308* (´«³ö²ÎÊý) void
309* ·µ »Ø Öµ: void
310* ÆäËü˵Ã÷: ÎÞ
311*******************************************************************************/
312void kmalloc_alloc_tracker(void *addr, int len)
313{
314 unsigned long spin_flag;
315 struct heap_record *section = NULL;
316 struct list_head *head_ptr = NULL;
317 struct list_head *free_node_head = NULL;
318 struct list_head *employ_node_head = NULL;
319 struct page *page_addr = NULL;
320
321 if(!addr)
322 panic("[MEM_TRACKER] input item error\n");
323
324 free_node_head = &kmem_free_head;
325 employ_node_head = &kmem_employ_head;
326
327 spin_lock_irqsave(&kmem_track_lock, spin_flag);
328
329 if (!(head_ptr = list_get_last_node(free_node_head)))
330 {
331 printk("[MEM_TRACKER]kmalloc free_link_node have no node!!!\n");
332 spin_unlock_irqrestore(&kmem_track_lock, spin_flag);
333 return;
334 }
335 spin_unlock_irqrestore(&kmem_track_lock, spin_flag);
336
337 section = container_of(head_ptr, struct heap_record, node);
338
339 /*³õʼ»¯½ÚµãÐÅÏ¢*/
340 memset_tracker(section);
341 section->addr = KMALLOC_SETUP(addr);
342 section->size = len;
343 section->employ = MEM_TRACKER_ALLOCED;
344 memcpy(section->task_name, current->comm, TASK_COMM_LEN);
345
346 /*»ñȡջ¹ì¼£*/
347 get_stack_process(section->stack_frame);
348 KMALLOC_SET_ENTRY(addr, section);
349
350 if(MEM_FALSE == check_node_entry(section))
351 panic("error");
352
353 /*¼ÓÈëÒÑÉêÇëÄÚ´æ½Úµã¼Ç¼Á´±í*/
354 spin_lock_irqsave(&kmem_track_lock, spin_flag);
355 list_add(&section->node, employ_node_head);
356
357 spin_unlock_irqrestore(&kmem_track_lock,spin_flag);
358}
359EXPORT_SYMBOL(kmalloc_alloc_tracker);
360
361/*******************************************************************************
362* ¹¦ÄÜÃèÊö: ÊÍ·ÅÄÚ´æµãµ÷ÓøýӿÚ
363* ²ÎÊý˵Ã÷:
364* (´«Èë²ÎÊý) entry:ÄÚ´æµØÖ·
365* (´«³ö²ÎÊý) void
366* ·µ »Ø Öµ: void
367* ÆäËü˵Ã÷: ÎÞ
368*******************************************************************************/
369void mem_free_tracker(void *entry, int type)
370{
371 unsigned long spin_flag;
372 spinlock_t *mem_lock = NULL;
373 struct list_head *free_node_head = NULL;
374 struct heap_record *free_node = (struct heap_record *)entry;
375
376 if (entry == NULL)
377 return;
378
379 if (type == MEM_TRACKER_TYPE_BUDDY)
380 {
381 mem_lock = &buddy_track_lock;
382 free_node_head = &buddy_free_head;
383 }
384 else if (type == MEM_TRACKER_TYPE_KMALLOC)
385 {
386 mem_lock = &kmem_track_lock;
387 free_node_head = &kmem_free_head;
388 }
389 else
390 panic("mem_tracker type error\n");
391
392 spin_lock_irqsave(mem_lock, spin_flag);
393
394 if (free_node->employ == MEM_TRACKER_ALLOCED)
395 {
396 free_node->employ = MEM_TRACKER_FREED;
397 list_move(&free_node->node, free_node_head);
398 }
399 else
400 {
401 printk("[MEM_TRACKER]error: employ is 0x%x employ_node MEM_TRACKER_FREED !!\n", free_node->employ);
402 }
403
404 spin_unlock_irqrestore(mem_lock, spin_flag);
405}
406EXPORT_SYMBOL(mem_free_tracker);
407
408
409