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