[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit
Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/os/linux/linux-3.4.x/mm/mem_tracker.c b/ap/os/linux/linux-3.4.x/mm/mem_tracker.c
new file mode 100755
index 0000000..3963763
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/mm/mem_tracker.c
@@ -0,0 +1,407 @@
+/*
+ * linux/mm/mem_tracker.c
+ *
+ * Copyright (C) 1993 Linus Torvalds
+ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
+ * vmalloc/vfree, Tigran Aivazian <tigran@veritas.com>, May 2000
+ * Major rework to support vmap/vunmap, Christoph Hellwig, SGI, August 2002
+ * Numa awareness, Christoph Lameter, SGI, June 2005
+ */
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/kallsyms.h>
+#include <linux/list.h>
+#include <linux/pfn.h>
+#include <linux/atomic.h>
+#include <asm/stacktrace.h>
+#include <mach/iomap.h>
+#include <linux/kprobes.h>
+#include <asm/traps.h>
+#include <linux/mem_tracker_def.h>
+
+/*******************************************************************************
+* ºê¶¨Òå *
+*******************************************************************************/
+#ifdef CONFIG_KALLSYMS
+#define MEM_TRACKER_MAX_STACK_LEN (100) /*Õ»º¯Êý¹ì¼£µÄ×Ö·û¸öÊýÉÏÏÞ£»*/
+#endif
+#define MEM_TRACKER_MAX_STACK_LEVEL (6) /*Õ»µÄ²ãÊý*/
+#define MEM_TRACKER_NOT_TRACE_LEVEL (2)
+#define MEM_TRACKER_ALLOCED 0x00
+#define MEM_TRACKER_FREED 0x02
+
+/*******************************************************************************
+* Êý¾ÝÀàÐͶ¨Òå *
+*******************************************************************************/
+struct heap_record {
+ struct list_head node;
+ void *addr; /*ÉêÇë³öµÄÄÚ´æµØÖ·*/
+ unsigned int employ:8;
+ unsigned int size:24; /*¼Ç¼ÉêÇëµÄÄڴ泤¶È*/
+ char task_name[TASK_COMM_LEN];
+#ifdef CONFIG_KALLSYMS
+ char stack_frame[MEM_TRACKER_MAX_STACK_LEVEL][MEM_TRACKER_MAX_STACK_LEN];
+ /*º¯Êý»ØËݹ켣*/
+#else
+ unsigned long stack_frame[MEM_TRACKER_MAX_STACK_LEVEL];
+#endif
+};
+
+/*******************************************************************************
+* º¯ÊýÉùÃ÷ *
+*******************************************************************************/
+/*******************************************************************************
+* È«¾Ö±äÁ¿¶¨Òå *
+*******************************************************************************/
+int kmem_node_max;
+int node_list_max;
+static spinlock_t buddy_track_lock;
+static spinlock_t kmem_track_lock;
+
+
+/*ÕýÔÚʹÓõÄÊý¾ÝÁ´±í*/
+static LIST_HEAD(buddy_employ_head);
+static LIST_HEAD(kmem_employ_head);
+
+/*ÒѾÊͷŵÄÊý¾ÝÁ´±í*/
+static LIST_HEAD(buddy_free_head);
+static LIST_HEAD(kmem_free_head);
+
+/*******************************************************************************
+* ¾Ö²¿º¯ÊýʵÏÖ *
+*******************************************************************************/
+static void memset_tracker(struct heap_record * node)
+{
+ node->size = 0;
+ node->addr = NULL;
+
+ memset(node->task_name,0, TASK_COMM_LEN);
+ memset(node->stack_frame, 0, sizeof(node->stack_frame));
+}
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö: ¶Ôµ±Ç°Õ»½øÐлØËÝ£¬½«º¯Êý¹ì¼£±£´æ
+* ²ÎÊý˵Ã÷:
+* (´«Èë²ÎÊý) my_frame:¹ì¼£ÐÅÏ¢±£´æµÄµØÖ·
+*
+* (´«³ö²ÎÊý) void
+* ·µ »Ø Öµ: void
+* ÆäËü˵Ã÷: ÎÞ
+*******************************************************************************/
+#ifdef CONFIG_KALLSYMS
+void get_stack_process(unsigned char *my_frame)
+#else
+void get_stack_process(unsigned long *my_frame)
+#endif
+{
+ int urc;
+ int i = 0;
+#ifdef CONFIG_KALLSYMS
+ char mytmp[MEM_TRACKER_MAX_STACK_LEN] = {0};
+#endif
+ struct stackframe frame;
+ register unsigned long current_sp asm ("sp");
+
+#ifndef CONFIG_KALLSYMS
+ memset(my_frame, 0, MEM_TRACKER_MAX_STACK_LEVEL * sizeof(unsigned long));
+#endif
+
+ frame.fp = (unsigned long)__builtin_frame_address(0);
+ frame.lr = (unsigned long)__builtin_return_address(0);
+ frame.sp = current_sp;
+ frame.pc = (unsigned long)get_stack_process;
+
+ while (1) {
+ urc = unwind_frame(&frame);
+ /*Èô»ØËݽáÊø£¬ÔòÁ¢¼´Í˳ö*/
+ if (urc < 0)
+ return;
+
+ /*ΪÁ˽ÚÊ¡Äڴ棬×îÉϲãµÄ2¸öº¯Êý²»¸ú×Ù*/
+ if (++i >= MEM_TRACKER_NOT_TRACE_LEVEL) {
+#ifdef CONFIG_KALLSYMS
+ snprintf(mytmp, MEM_TRACKER_MAX_STACK_LEN - 1, "<%ps>", (void *)frame.pc);
+ strcpy(my_frame + ((i - MEM_TRACKER_NOT_TRACE_LEVEL) * MEM_TRACKER_MAX_STACK_LEN), mytmp);
+#else
+ my_frame[i - MEM_TRACKER_NOT_TRACE_LEVEL] = (unsigned long)frame.pc;
+#endif
+ if (i - MEM_TRACKER_NOT_TRACE_LEVEL >= MEM_TRACKER_MAX_STACK_LEVEL - 1)
+ return;
+ }
+ }
+}
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö: »ñÈ¡×îºóÒ»¸ö½Úµã
+* ²ÎÊý˵Ã÷:
+* (´«Èë²ÎÊý) head:Á´±íÍ·
+* (´«³ö²ÎÊý) track¸ú×ÙÐÅÏ¢
+* ·µ »Ø Öµ: void
+* ÆäËü˵Ã÷: ÎÞ
+*******************************************************************************/
+static struct list_head *list_get_last_node(struct list_head *head)
+{
+ struct heap_record *h = NULL;
+ struct list_head *tail_node = NULL;
+
+ if (list_empty(head))
+ return NULL;
+
+ tail_node = head->prev;
+
+ h = container_of(tail_node, struct heap_record, node);
+
+ if(h->employ == MEM_TRACKER_FREED)
+ list_del(head->prev);
+ else
+ panic("[MEM_TRACKER]list error");
+
+ return tail_node;
+}
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö: ÄÚ´æ¸ú×Ù³õʼ»¯
+* ²ÎÊý˵Ã÷:
+* (´«Èë²ÎÊý) void
+* (´«³ö²ÎÊý) void
+* ·µ »Ø Öµ: void
+* ÆäËü˵Ã÷: ΪʵÏÖÄÚ´æ¹ì¼£¸ú×Ùʱ²»Õ¼ÓÃÏÖÓÐÄڴ棬ʹÓÃ64MÒÔºóµÄÄÚ´æ
+*******************************************************************************/
+void mem_trace_init(void)
+{
+ int index;
+ unsigned long flags;
+ struct heap_record *record = NULL;
+ void __iomem *base = NULL;
+
+ spin_lock_init(&buddy_track_lock);
+
+ spin_lock_irqsave(&buddy_track_lock, flags);
+
+ base = ZX_MEM_TRACKER_BASE;
+ node_list_max = ZX_MEM_TRACKER_SIZE / sizeof(struct heap_record);
+
+ /* ³õʼ»¯¿ÕÏÐÄÚ´æ½ÚµãÁ´±í */
+ for (index = 0; index < node_list_max; index++)
+ {
+ record = (struct heap_record *)(base + index * sizeof(struct heap_record));
+ record->employ = MEM_TRACKER_FREED;
+ list_add(&record->node, &buddy_free_head);
+ }
+
+ spin_unlock_irqrestore(&buddy_track_lock, flags);
+}
+
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö: kmallocÄÚ´æ¸ú×Ù³õʼ»¯
+* ²ÎÊý˵Ã÷:
+* (´«Èë²ÎÊý) void
+* (´«³ö²ÎÊý) void
+* ·µ »Ø Öµ: void
+* ÆäËü˵Ã÷: ΪʵÏÖÄÚ´æ¹ì¼£¸ú×Ùʱ²»Õ¼ÓÃÏÖÓÐÄڴ棬ʹÓÃ64MÒÔºóµÄÄÚ´æ
+*******************************************************************************/
+void kmalloc_trace_init(void)
+{
+ int index;
+ unsigned long flags;
+ struct heap_record *record = NULL;
+ void __iomem *base = NULL;
+
+ spin_lock_init(&kmem_track_lock);
+ spin_lock_irqsave(&kmem_track_lock, flags);
+
+ base = ZX_KMALLOC_TRACKER_BASE;
+ kmem_node_max = ZX_KMALLOC_TRACKER_SIZE / sizeof(struct heap_record);
+
+ /* ³õʼ»¯¿ÕÏÐÄÚ´æ½ÚµãÁ´±í */
+ for (index = 0; index < kmem_node_max; index++)
+ {
+ record = (struct heap_record *)(base + index * sizeof(struct heap_record));
+ record->employ = MEM_TRACKER_FREED;
+ list_add(&record->node, &kmem_free_head);
+ }
+
+ spin_unlock_irqrestore(&kmem_track_lock, flags);
+}
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö: ÑéÖ¤entry½ÚµãºÏ·¨ÐÔ
+* ²ÎÊý˵Ã÷:
+* (´«Èë²ÎÊý) void
+* (´«³ö²ÎÊý) void
+* ·µ »Ø Öµ: void
+* ÆäËü˵Ã÷: ΪʵÏÖÄÚ´æ¹ì¼£¸ú×Ùʱ²»Õ¼ÓÃÏÖÓÐÄڴ棬ʹÓÃ64MÒÔºóµÄÄÚ´æ
+*******************************************************************************/
+int check_node_entry(const int entry)
+{
+ void __iomem *base = NULL;
+ long limit = 0;
+
+ base = ZX_KMALLOC_TRACKER_BASE;
+ limit = ZX_KMALLOC_TRACKER_SIZE + (int)base;
+
+ if ((entry >= base) && (entry < limit))
+ return MEM_TRUE;
+
+ return MEM_FALSE;
+}
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö: ÉêÇëÄÚ´æµãµ÷Óøýӿڣ¬¼Ç¼ÄÚ´æÉêÇë¹ì¼£
+* ²ÎÊý˵Ã÷:
+* (´«Èë²ÎÊý) addr:ÄÚ´æµØÖ·
+* order:Äڴ泤¶È,orderΪµ¥Î»£¬2µÄorder´Î·½¸öÒ³
+* (´«³ö²ÎÊý) void
+* ·µ »Ø Öµ: void
+* ÆäËü˵Ã÷: ÎÞ
+*******************************************************************************/
+void mem_alloc_tracker(void *addr, int order)
+{
+ unsigned long spin_flag;
+ struct heap_record *section = NULL;
+ struct list_head *head_ptr = NULL;
+ struct page *page_addr = NULL;
+
+ if(!addr)
+ panic("[MEM_TRACKER] input item error\n");
+
+ page_addr = (struct page *)(addr);
+
+ spin_lock_irqsave(&buddy_track_lock, spin_flag);
+ if (!(head_ptr = list_get_last_node(&buddy_free_head)))
+ {
+ printk("[MEM_TRACKER]buddy free_link_node have no node!!!\n");
+ spin_unlock_irqrestore(&buddy_track_lock, spin_flag);
+ return;
+ }
+ spin_unlock_irqrestore(&buddy_track_lock, spin_flag);
+ section = container_of(head_ptr, struct heap_record, node);
+
+ /*³õʼ»¯½ÚµãÐÅÏ¢*/
+ memset_tracker(section);
+ section->addr = addr;
+ section->size = (1 << order) * PAGE_SIZE;
+ section->employ = MEM_TRACKER_ALLOCED;
+ memcpy(section->task_name, current->comm, TASK_COMM_LEN);
+
+ /*»ñȡջ¹ì¼£*/
+ get_stack_process(section->stack_frame);
+ page_addr->mem_track_entry = section;
+
+ /*¼ÓÈëÒÑÉêÇëÄÚ´æ½Úµã¼Ç¼Á´±í*/
+ spin_lock_irqsave(&buddy_track_lock, spin_flag);
+ list_add(§ion->node, &buddy_employ_head);
+ spin_unlock_irqrestore(&buddy_track_lock,spin_flag);
+}
+EXPORT_SYMBOL(mem_alloc_tracker);
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö: kmallocÉêÇëÄÚ´æµãµ÷Óøýӿڣ¬¼Ç¼ÄÚ´æÉêÇë¹ì¼£
+* ²ÎÊý˵Ã÷:
+* (´«Èë²ÎÊý) addr:ÄÚ´æµØÖ·
+* len:Äڴ泤¶È
+* (´«³ö²ÎÊý) void
+* ·µ »Ø Öµ: void
+* ÆäËü˵Ã÷: ÎÞ
+*******************************************************************************/
+void kmalloc_alloc_tracker(void *addr, int len)
+{
+ unsigned long spin_flag;
+ struct heap_record *section = NULL;
+ struct list_head *head_ptr = NULL;
+ struct list_head *free_node_head = NULL;
+ struct list_head *employ_node_head = NULL;
+ struct page *page_addr = NULL;
+
+ if(!addr)
+ panic("[MEM_TRACKER] input item error\n");
+
+ free_node_head = &kmem_free_head;
+ employ_node_head = &kmem_employ_head;
+
+ spin_lock_irqsave(&kmem_track_lock, spin_flag);
+
+ if (!(head_ptr = list_get_last_node(free_node_head)))
+ {
+ printk("[MEM_TRACKER]kmalloc free_link_node have no node!!!\n");
+ spin_unlock_irqrestore(&kmem_track_lock, spin_flag);
+ return;
+ }
+ spin_unlock_irqrestore(&kmem_track_lock, spin_flag);
+
+ section = container_of(head_ptr, struct heap_record, node);
+
+ /*³õʼ»¯½ÚµãÐÅÏ¢*/
+ memset_tracker(section);
+ section->addr = KMALLOC_SETUP(addr);
+ section->size = len;
+ section->employ = MEM_TRACKER_ALLOCED;
+ memcpy(section->task_name, current->comm, TASK_COMM_LEN);
+
+ /*»ñȡջ¹ì¼£*/
+ get_stack_process(section->stack_frame);
+ KMALLOC_SET_ENTRY(addr, section);
+
+ if(MEM_FALSE == check_node_entry(section))
+ panic("error");
+
+ /*¼ÓÈëÒÑÉêÇëÄÚ´æ½Úµã¼Ç¼Á´±í*/
+ spin_lock_irqsave(&kmem_track_lock, spin_flag);
+ list_add(§ion->node, employ_node_head);
+
+ spin_unlock_irqrestore(&kmem_track_lock,spin_flag);
+}
+EXPORT_SYMBOL(kmalloc_alloc_tracker);
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö: ÊÍ·ÅÄÚ´æµãµ÷ÓøýӿÚ
+* ²ÎÊý˵Ã÷:
+* (´«Èë²ÎÊý) entry:ÄÚ´æµØÖ·
+* (´«³ö²ÎÊý) void
+* ·µ »Ø Öµ: void
+* ÆäËü˵Ã÷: ÎÞ
+*******************************************************************************/
+void mem_free_tracker(void *entry, int type)
+{
+ unsigned long spin_flag;
+ spinlock_t *mem_lock = NULL;
+ struct list_head *free_node_head = NULL;
+ struct heap_record *free_node = (struct heap_record *)entry;
+
+ if (entry == NULL)
+ return;
+
+ if (type == MEM_TRACKER_TYPE_BUDDY)
+ {
+ mem_lock = &buddy_track_lock;
+ free_node_head = &buddy_free_head;
+ }
+ else if (type == MEM_TRACKER_TYPE_KMALLOC)
+ {
+ mem_lock = &kmem_track_lock;
+ free_node_head = &kmem_free_head;
+ }
+ else
+ panic("mem_tracker type error\n");
+
+ spin_lock_irqsave(mem_lock, spin_flag);
+
+ if (free_node->employ == MEM_TRACKER_ALLOCED)
+ {
+ free_node->employ = MEM_TRACKER_FREED;
+ list_move(&free_node->node, free_node_head);
+ }
+ else
+ {
+ printk("[MEM_TRACKER]error: employ is 0x%x employ_node MEM_TRACKER_FREED !!\n", free_node->employ);
+ }
+
+ spin_unlock_irqrestore(mem_lock, spin_flag);
+}
+EXPORT_SYMBOL(mem_free_tracker);
+
+
+