Merge tag 'v3.10.92' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / mm / slub.c
index a0206df88aba9e001d27248616a36aad9218df4f..01900d906cd1806a51bc0fd0a81448e44c1f7287 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
 #include <linux/stacktrace.h>
 #include <linux/prefetch.h>
 #include <linux/memcontrol.h>
+#include <linux/aee.h>
 
 #include <trace/events/kmem.h>
+#include <mach/mtk_memcfg.h>
 
 #include "internal.h"
-
+#ifdef CONFIG_ARM64
+#ifdef BUG
+#undef BUG
+#define BUG() \
+       do {    \
+               pr_alert("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
+               *(char *)0 = 0;\
+       } while(0)
+#endif 
+#endif 
 /*
  * Lock order:
  *   1. slab_mutex (Global Mutex)
@@ -196,7 +207,7 @@ struct track {
        unsigned long when;     /* When did the operation occur */
 };
 
-enum track_item { TRACK_ALLOC, TRACK_FREE };
+enum track_item { TRACK_FREE, TRACK_ALLOC };
 
 #ifdef CONFIG_SYSFS
 static int sysfs_slab_add(struct kmem_cache *);
@@ -346,6 +357,21 @@ static __always_inline void slab_unlock(struct page *page)
        __bit_spin_unlock(PG_locked, &page->flags);
 }
 
+static inline void set_page_slub_counters(struct page *page, unsigned long counters_new)
+{
+       struct page tmp;
+       tmp.counters = counters_new;
+       /*
+        * page->counters can cover frozen/inuse/objects as well
+        * as page->_count.  If we assign to ->counters directly
+        * we run the risk of losing updates to page->_count, so
+        * be careful and only assign to the fields we need.
+        */
+       page->frozen  = tmp.frozen;
+       page->inuse   = tmp.inuse;
+       page->objects = tmp.objects;
+}
+
 /* Interrupts must be disabled (for the fallback code to work right) */
 static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
                void *freelist_old, unsigned long counters_old,
@@ -366,7 +392,7 @@ static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page
                slab_lock(page);
                if (page->freelist == freelist_old && page->counters == counters_old) {
                        page->freelist = freelist_new;
-                       page->counters = counters_new;
+                       set_page_slub_counters(page, counters_new);
                        slab_unlock(page);
                        return 1;
                }
@@ -404,7 +430,7 @@ static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
                slab_lock(page);
                if (page->freelist == freelist_old && page->counters == counters_old) {
                        page->freelist = freelist_new;
-                       page->counters = counters_new;
+                       set_page_slub_counters(page, counters_new);
                        slab_unlock(page);
                        local_irq_restore(flags);
                        return 1;
@@ -618,6 +644,7 @@ static void object_err(struct kmem_cache *s, struct page *page,
 {
        slab_bug(s, "%s", reason);
        print_trailer(s, page, object);
+       BUG();
 }
 
 static void slab_err(struct kmem_cache *s, struct page *page, const char *fmt, ...)
@@ -631,6 +658,7 @@ static void slab_err(struct kmem_cache *s, struct page *page, const char *fmt, .
        slab_bug(s, "%s", buf);
        print_page_info(page);
        dump_stack();
+       BUG();
 }
 
 static void init_object(struct kmem_cache *s, void *object, u8 val)
@@ -673,7 +701,10 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page,
                                        fault, end - 1, fault[0], value);
        print_trailer(s, page, object);
 
+       /* trigger BUG before restore_bytes */
+       BUG();
        restore_bytes(s, what, value, fault, end);
+
        return 0;
 }
 
@@ -830,13 +861,18 @@ static int check_slab(struct kmem_cache *s, struct page *page)
 
        maxobj = order_objects(compound_order(page), s->size, s->reserved);
        if (page->objects > maxobj) {
+               pr_alert("page->objects: %d, maxobj: %d, comporder: %d", page->objects,
+                               maxobj, compound_order(page));
+               pr_alert("s->size %d, s->reserved: %d", s->size, s->reserved);
+               print_section("page: ", (void *)page, sizeof(struct page));
+               print_section("kmem_cache: ", (void *)s, sizeof(struct kmem_cache));
                slab_err(s, page, "objects %u > max %u",
-                       s->name, page->objects, maxobj);
+                        page->objects, maxobj);
                return 0;
        }
        if (page->inuse > page->objects) {
                slab_err(s, page, "inuse %u > max %u",
-                       s->name, page->inuse, page->objects);
+                        page->inuse, page->objects);
                return 0;
        }
        /* Slab_pad_check fixes things up after itself */
@@ -1006,7 +1042,7 @@ static inline void inc_slabs_node(struct kmem_cache *s, int node, int objects)
         * dilemma by deferring the increment of the count during
         * bootstrap (see early_kmem_cache_node_alloc).
         */
-       if (n) {
+       if (likely(n)) {
                atomic_long_inc(&n->nr_slabs);
                atomic_long_add(objects, &n->total_objects);
        }
@@ -1201,8 +1237,12 @@ static unsigned long kmem_cache_flags(unsigned long object_size,
        /*
         * Enable debugging if selected on the kernel commandline.
         */
-       if (slub_debug && (!slub_debug_slabs ||
-               !strncmp(slub_debug_slabs, name, strlen(slub_debug_slabs))))
+       if(flags & SLAB_NO_DEBUG) {
+               return flags;
+       }
+
+       if (slub_debug && (!slub_debug_slabs || (name &&
+               !strncmp(slub_debug_slabs, name, strlen(slub_debug_slabs)))))
                flags |= slub_debug;
 
        return flags;
@@ -1265,7 +1305,11 @@ static inline struct page *alloc_slab_page(gfp_t flags, int node,
        flags |= __GFP_NOTRACK;
 
        if (node == NUMA_NO_NODE)
+#ifndef CONFIG_MTK_PAGERECORDER
                return alloc_pages(flags, order);
+#else
+               return alloc_pages_nopagedebug(flags, order);
+#endif
        else
                return alloc_pages_exact_node(node, flags, order);
 }
@@ -1494,7 +1538,7 @@ static inline void remove_partial(struct kmem_cache_node *n,
  */
 static inline void *acquire_slab(struct kmem_cache *s,
                struct kmem_cache_node *n, struct page *page,
-               int mode)
+               int mode, int *objects)
 {
        void *freelist;
        unsigned long counters;
@@ -1508,6 +1552,7 @@ static inline void *acquire_slab(struct kmem_cache *s,
        freelist = page->freelist;
        counters = page->counters;
        new.counters = counters;
+       *objects = new.objects - new.inuse;
        if (mode) {
                new.inuse = page->objects;
                new.freelist = NULL;
@@ -1529,7 +1574,7 @@ static inline void *acquire_slab(struct kmem_cache *s,
        return freelist;
 }
 
-static int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain);
+static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain);
 static inline bool pfmemalloc_match(struct page *page, gfp_t gfpflags);
 
 /*
@@ -1540,6 +1585,8 @@ static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
 {
        struct page *page, *page2;
        void *object = NULL;
+       int available = 0;
+       int objects;
 
        /*
         * Racy check. If we mistakenly see no partial slabs then we
@@ -1553,22 +1600,21 @@ static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
        spin_lock(&n->list_lock);
        list_for_each_entry_safe(page, page2, &n->partial, lru) {
                void *t;
-               int available;
 
                if (!pfmemalloc_match(page, flags))
                        continue;
 
-               t = acquire_slab(s, n, page, object == NULL);
+               t = acquire_slab(s, n, page, object == NULL, &objects);
                if (!t)
                        break;
 
+               available += objects;
                if (!object) {
                        c->page = page;
                        stat(s, ALLOC_FROM_PARTIAL);
                        object = t;
-                       available =  page->objects - page->inuse;
                } else {
-                       available = put_cpu_partial(s, page, 0);
+                       put_cpu_partial(s, page, 0);
                        stat(s, CPU_PARTIAL_NODE);
                }
                if (kmem_cache_debug(s) || available > s->cpu_partial / 2)
@@ -1947,7 +1993,7 @@ static void unfreeze_partials(struct kmem_cache *s,
  * If we did not find a slot then simply move all the partials to the
  * per node partial list.
  */
-static int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
+static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
 {
        struct page *oldpage;
        int pages;
@@ -1985,7 +2031,6 @@ static int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
                page->next = oldpage;
 
        } while (this_cpu_cmpxchg(s->cpu_slab->partial, oldpage, page) != oldpage);
-       return pobjects;
 }
 
 static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
@@ -2042,7 +2087,7 @@ static void flush_all(struct kmem_cache *s)
 static inline int node_match(struct page *page, int node)
 {
 #ifdef CONFIG_NUMA
-       if (node != NUMA_NO_NODE && page_to_nid(page) != node)
+       if (!page || (node != NUMA_NO_NODE && page_to_nid(page) != node))
                return 0;
 #endif
        return 1;
@@ -2332,13 +2377,18 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s,
 
        s = memcg_kmem_get_cache(s, gfpflags);
 redo:
-
        /*
         * Must read kmem_cache cpu data via this cpu ptr. Preemption is
         * enabled. We may switch back and forth between cpus while
         * reading from one cpu area. That does not matter as long
         * as we end up on the original cpu again when doing the cmpxchg.
+        *
+        * Preemption is disabled for the retrieval of the tid because that
+        * must occur from the current processor. We cannot allow rescheduling
+        * on a different processor between the determination of the pointer
+        * and the retrieval of the tid.
         */
+       preempt_disable();
        c = __this_cpu_ptr(s->cpu_slab);
 
        /*
@@ -2348,7 +2398,7 @@ redo:
         * linked list in between.
         */
        tid = c->tid;
-       barrier();
+       preempt_enable();
 
        object = c->freelist;
        page = c->page;
@@ -2595,10 +2645,11 @@ redo:
         * data is retrieved via this pointer. If we are on the same cpu
         * during the cmpxchg then the free will succedd.
         */
+       preempt_disable();
        c = __this_cpu_ptr(s->cpu_slab);
 
        tid = c->tid;
-       barrier();
+       preempt_enable();
 
        if (likely(page == c->page)) {
                set_freepointer(s, object, c->freelist);
@@ -2776,7 +2827,7 @@ init_kmem_cache_node(struct kmem_cache_node *n)
 static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
 {
        BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE <
-                       SLUB_PAGE_SHIFT * sizeof(struct kmem_cache_cpu));
+                       KMALLOC_SHIFT_HIGH * sizeof(struct kmem_cache_cpu));
 
        /*
         * Must align to double word boundary for the double cmpxchg
@@ -2983,7 +3034,7 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order)
                s->allocflags |= __GFP_COMP;
 
        if (s->flags & SLAB_CACHE_DMA)
-               s->allocflags |= SLUB_DMA;
+               s->allocflags |= GFP_DMA;
 
        if (s->flags & SLAB_RECLAIM_ACCOUNT)
                s->allocflags |= __GFP_RECLAIMABLE;
@@ -3175,13 +3226,6 @@ int __kmem_cache_shutdown(struct kmem_cache *s)
  *             Kmalloc subsystem
  *******************************************************************/
 
-struct kmem_cache *kmalloc_caches[SLUB_PAGE_SHIFT];
-EXPORT_SYMBOL(kmalloc_caches);
-
-#ifdef CONFIG_ZONE_DMA
-static struct kmem_cache *kmalloc_dma_caches[SLUB_PAGE_SHIFT];
-#endif
-
 static int __init setup_slub_min_order(char *str)
 {
        get_option(&str, &slub_min_order);
@@ -3218,73 +3262,15 @@ static int __init setup_slub_nomerge(char *str)
 
 __setup("slub_nomerge", setup_slub_nomerge);
 
-/*
- * Conversion table for small slabs sizes / 8 to the index in the
- * kmalloc array. This is necessary for slabs < 192 since we have non power
- * of two cache sizes there. The size of larger slabs can be determined using
- * fls.
- */
-static s8 size_index[24] = {
-       3,      /* 8 */
-       4,      /* 16 */
-       5,      /* 24 */
-       5,      /* 32 */
-       6,      /* 40 */
-       6,      /* 48 */
-       6,      /* 56 */
-       6,      /* 64 */
-       1,      /* 72 */
-       1,      /* 80 */
-       1,      /* 88 */
-       1,      /* 96 */
-       7,      /* 104 */
-       7,      /* 112 */
-       7,      /* 120 */
-       7,      /* 128 */
-       2,      /* 136 */
-       2,      /* 144 */
-       2,      /* 152 */
-       2,      /* 160 */
-       2,      /* 168 */
-       2,      /* 176 */
-       2,      /* 184 */
-       2       /* 192 */
-};
-
-static inline int size_index_elem(size_t bytes)
-{
-       return (bytes - 1) / 8;
-}
-
-static struct kmem_cache *get_slab(size_t size, gfp_t flags)
-{
-       int index;
-
-       if (size <= 192) {
-               if (!size)
-                       return ZERO_SIZE_PTR;
-
-               index = size_index[size_index_elem(size)];
-       } else
-               index = fls(size - 1);
-
-#ifdef CONFIG_ZONE_DMA
-       if (unlikely((flags & SLUB_DMA)))
-               return kmalloc_dma_caches[index];
-
-#endif
-       return kmalloc_caches[index];
-}
-
 void *__kmalloc(size_t size, gfp_t flags)
 {
        struct kmem_cache *s;
        void *ret;
 
-       if (unlikely(size > SLUB_MAX_SIZE))
+       if (unlikely(size > KMALLOC_MAX_CACHE_SIZE))
                return kmalloc_large(size, flags);
 
-       s = get_slab(size, flags);
+       s = kmalloc_slab(size, flags);
 
        if (unlikely(ZERO_OR_NULL_PTR(s)))
                return s;
@@ -3317,7 +3303,7 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
        struct kmem_cache *s;
        void *ret;
 
-       if (unlikely(size > SLUB_MAX_SIZE)) {
+       if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) {
                ret = kmalloc_large_node(size, flags, node);
 
                trace_kmalloc_node(_RET_IP_, ret,
@@ -3327,7 +3313,7 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
                return ret;
        }
 
-       s = get_slab(size, flags);
+       s = kmalloc_slab(size, flags);
 
        if (unlikely(ZERO_OR_NULL_PTR(s)))
                return s;
@@ -3620,6 +3606,12 @@ static struct kmem_cache * __init bootstrap(struct kmem_cache *static_cache)
 
        memcpy(s, static_cache, kmem_cache->object_size);
 
+       /*
+        * This runs very early, and only the boot processor is supposed to be
+        * up.  Even if it weren't true, IRQs are not up so we couldn't fire
+        * IPIs around.
+        */
+       __flush_cpu_slab(s, smp_processor_id());
        for_each_node_state(node, N_NORMAL_MEMORY) {
                struct kmem_cache_node *n = get_node(s, node);
                struct page *p;
@@ -3642,8 +3634,6 @@ void __init kmem_cache_init(void)
 {
        static __initdata struct kmem_cache boot_kmem_cache,
                boot_kmem_cache_node;
-       int i;
-       int caches = 2;
 
        if (debug_guardpage_minorder())
                slub_max_order = 0;
@@ -3674,103 +3664,16 @@ void __init kmem_cache_init(void)
        kmem_cache_node = bootstrap(&boot_kmem_cache_node);
 
        /* Now we can use the kmem_cache to allocate kmalloc slabs */
-
-       /*
-        * Patch up the size_index table if we have strange large alignment
-        * requirements for the kmalloc array. This is only the case for
-        * MIPS it seems. The standard arches will not generate any code here.
-        *
-        * Largest permitted alignment is 256 bytes due to the way we
-        * handle the index determination for the smaller caches.
-        *
-        * Make sure that nothing crazy happens if someone starts tinkering
-        * around with ARCH_KMALLOC_MINALIGN
-        */
-       BUILD_BUG_ON(KMALLOC_MIN_SIZE > 256 ||
-               (KMALLOC_MIN_SIZE & (KMALLOC_MIN_SIZE - 1)));
-
-       for (i = 8; i < KMALLOC_MIN_SIZE; i += 8) {
-               int elem = size_index_elem(i);
-               if (elem >= ARRAY_SIZE(size_index))
-                       break;
-               size_index[elem] = KMALLOC_SHIFT_LOW;
-       }
-
-       if (KMALLOC_MIN_SIZE == 64) {
-               /*
-                * The 96 byte size cache is not used if the alignment
-                * is 64 byte.
-                */
-               for (i = 64 + 8; i <= 96; i += 8)
-                       size_index[size_index_elem(i)] = 7;
-       } else if (KMALLOC_MIN_SIZE == 128) {
-               /*
-                * The 192 byte sized cache is not used if the alignment
-                * is 128 byte. Redirect kmalloc to use the 256 byte cache
-                * instead.
-                */
-               for (i = 128 + 8; i <= 192; i += 8)
-                       size_index[size_index_elem(i)] = 8;
-       }
-
-       /* Caches that are not of the two-to-the-power-of size */
-       if (KMALLOC_MIN_SIZE <= 32) {
-               kmalloc_caches[1] = create_kmalloc_cache("kmalloc-96", 96, 0);
-               caches++;
-       }
-
-       if (KMALLOC_MIN_SIZE <= 64) {
-               kmalloc_caches[2] = create_kmalloc_cache("kmalloc-192", 192, 0);
-               caches++;
-       }
-
-       for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) {
-               kmalloc_caches[i] = create_kmalloc_cache("kmalloc", 1 << i, 0);
-               caches++;
-       }
-
-       slab_state = UP;
-
-       /* Provide the correct kmalloc names now that the caches are up */
-       if (KMALLOC_MIN_SIZE <= 32) {
-               kmalloc_caches[1]->name = kstrdup(kmalloc_caches[1]->name, GFP_NOWAIT);
-               BUG_ON(!kmalloc_caches[1]->name);
-       }
-
-       if (KMALLOC_MIN_SIZE <= 64) {
-               kmalloc_caches[2]->name = kstrdup(kmalloc_caches[2]->name, GFP_NOWAIT);
-               BUG_ON(!kmalloc_caches[2]->name);
-       }
-
-       for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) {
-               char *s = kasprintf(GFP_NOWAIT, "kmalloc-%d", 1 << i);
-
-               BUG_ON(!s);
-               kmalloc_caches[i]->name = s;
-       }
+       create_kmalloc_caches(0);
 
 #ifdef CONFIG_SMP
        register_cpu_notifier(&slab_notifier);
 #endif
 
-#ifdef CONFIG_ZONE_DMA
-       for (i = 0; i < SLUB_PAGE_SHIFT; i++) {
-               struct kmem_cache *s = kmalloc_caches[i];
-
-               if (s && s->size) {
-                       char *name = kasprintf(GFP_NOWAIT,
-                                "dma-kmalloc-%d", s->object_size);
-
-                       BUG_ON(!name);
-                       kmalloc_dma_caches[i] = create_kmalloc_cache(name,
-                               s->object_size, SLAB_CACHE_DMA);
-               }
-       }
-#endif
        printk(KERN_INFO
-               "SLUB: Genslabs=%d, HWalign=%d, Order=%d-%d, MinObjects=%d,"
+               "SLUB: HWalign=%d, Order=%d-%d, MinObjects=%d,"
                " CPUs=%d, Nodes=%d\n",
-               caches, cache_line_size(),
+               cache_line_size(),
                slub_min_order, slub_max_order, slub_min_objects,
                nr_cpu_ids, nr_node_ids);
 }
@@ -3933,10 +3836,10 @@ void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, unsigned long caller)
        struct kmem_cache *s;
        void *ret;
 
-       if (unlikely(size > SLUB_MAX_SIZE))
+       if (unlikely(size > KMALLOC_MAX_CACHE_SIZE))
                return kmalloc_large(size, gfpflags);
 
-       s = get_slab(size, gfpflags);
+       s = kmalloc_slab(size, gfpflags);
 
        if (unlikely(ZERO_OR_NULL_PTR(s)))
                return s;
@@ -3956,7 +3859,7 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
        struct kmem_cache *s;
        void *ret;
 
-       if (unlikely(size > SLUB_MAX_SIZE)) {
+       if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) {
                ret = kmalloc_large_node(size, gfpflags, node);
 
                trace_kmalloc_node(caller, ret,
@@ -3966,7 +3869,7 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
                return ret;
        }
 
-       s = get_slab(size, gfpflags);
+       s = kmalloc_slab(size, gfpflags);
 
        if (unlikely(ZERO_OR_NULL_PTR(s)))
                return s;
@@ -4086,9 +3989,22 @@ static long validate_slab_cache(struct kmem_cache *s)
  * and freed.
  */
 
+#ifdef CONFIG_MTK_MEMCFG
+#define MTK_MEMCFG_SLABTRACE_CNT 4
+/* MTK_MEMCFG_SLABTRACE_CNT should be always <= TRACK_ADDRS_COUNT */
+#if (MTK_MEMCFG_SLABTRACE_CNT > TRACK_ADDRS_COUNT)
+#error (MTK_MEMCFG_SLABTRACE_CNT > TRACK_ADDRS_COUNT)
+#endif 
+#endif 
+
 struct location {
        unsigned long count;
        unsigned long addr;
+#ifdef CONFIG_MTK_MEMCFG
+#ifdef CONFIG_STACKTRACE
+       unsigned long addrs[MTK_MEMCFG_SLABTRACE_CNT];  /* Called from address */
+#endif
+#endif 
        long long sum_time;
        long min_time;
        long max_time;
@@ -4107,8 +4023,13 @@ struct loc_track {
 static void free_loc_track(struct loc_track *t)
 {
        if (t->max)
+#ifndef CONFIG_MTK_PAGERECORDER
                free_pages((unsigned long)t->loc,
                        get_order(sizeof(struct location) * t->max));
+#else
+               __free_pages_nopagedebug((struct page *)t->loc,
+                       get_order(sizeof(struct location) * t->max));
+#endif
 }
 
 static int alloc_loc_track(struct loc_track *t, unsigned long max, gfp_t flags)
@@ -4118,7 +4039,11 @@ static int alloc_loc_track(struct loc_track *t, unsigned long max, gfp_t flags)
 
        order = get_order(sizeof(struct location) * max);
 
+#ifndef CONFIG_MTK_PAGERECORDER
        l = (void *)__get_free_pages(flags, order);
+#else
+       l = (void *)__get_free_pages_nopagedebug(flags, order);
+#endif 
        if (!l)
                return 0;
 
@@ -4315,7 +4240,7 @@ static void resiliency_test(void)
 {
        u8 *p;
 
-       BUILD_BUG_ON(KMALLOC_MIN_SIZE > 16 || SLUB_PAGE_SHIFT < 10);
+       BUILD_BUG_ON(KMALLOC_MIN_SIZE > 16 || KMALLOC_SHIFT_HIGH < 10);
 
        printk(KERN_ERR "SLUB resiliency testing\n");
        printk(KERN_ERR "-----------------------\n");
@@ -4426,7 +4351,13 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
 
                        page = ACCESS_ONCE(c->partial);
                        if (page) {
-                               x = page->pobjects;
+                               node = page_to_nid(page);
+                               if (flags & SO_TOTAL)
+                                       WARN_ON_ONCE(1);
+                               else if (flags & SO_OBJECTS)
+                                       WARN_ON_ONCE(1);
+                               else
+                                       x = page->pages;
                                total += x;
                                nodes[node] += x;
                        }
@@ -5445,4 +5376,192 @@ ssize_t slabinfo_write(struct file *file, const char __user *buffer,
 {
        return -EIO;
 }
+
+#ifdef CONFIG_MTK_MEMCFG
+
+static int mtk_memcfg_add_location(struct loc_track *t, struct kmem_cache *s,
+                               const struct track *track)
+{
+       long start, end, pos;
+       struct location *l;
+       unsigned long (*caddrs)[MTK_MEMCFG_SLABTRACE_CNT];      /* Called from addresses */
+       unsigned long taddrs[MTK_MEMCFG_SLABTRACE_CNT] 
+               = { [0 ... MTK_MEMCFG_SLABTRACE_CNT - 1] = 0,};         /* Called from addresses of track */
+       unsigned long age = jiffies - track->when;
+       int i, cnt;
+
+       start = -1;
+       end = t->count;
+
+       /* find the index of track->addr */
+       for (i = 0; i < TRACK_ADDRS_COUNT; i++) {
+               if ((track->addr == track->addrs[i]) ||
+                       (track->addr - 4 == track->addrs[i]))
+                       break;
+       }
+       cnt = min(MTK_MEMCFG_SLABTRACE_CNT, TRACK_ADDRS_COUNT - i);
+       memcpy(taddrs, track->addrs + i, (cnt * sizeof (unsigned long)));
+
+       for ( ; ; ) {
+               pos = start + (end - start + 1) / 2;
+
+               /*
+                * There is nothing at "end". If we end up there
+                * we need to add something to before end.
+                */
+               if (pos == end)
+                       break;
+
+               caddrs = &(t->loc[pos].addrs);
+               if (!memcmp(caddrs, taddrs, MTK_MEMCFG_SLABTRACE_CNT * sizeof (unsigned long))) {
+
+                       l = &t->loc[pos];
+                       l->count++;
+                       if (track->when) {
+                               l->sum_time += age;
+                               if (age < l->min_time)
+                                       l->min_time = age;
+                               if (age > l->max_time)
+                                       l->max_time = age;
+
+                               if (track->pid < l->min_pid)
+                                       l->min_pid = track->pid;
+                               if (track->pid > l->max_pid)
+                                       l->max_pid = track->pid;
+
+                               cpumask_set_cpu(track->cpu,
+                                               to_cpumask(l->cpus));
+                       }
+                       node_set(page_to_nid(virt_to_page(track)), l->nodes);
+                       return 1;
+               }
+
+               if (memcmp(caddrs, taddrs, MTK_MEMCFG_SLABTRACE_CNT * sizeof (unsigned long)) < 0) 
+                       end = pos;
+               else
+                       start = pos;
+       }
+
+       /*
+        * Not found. Insert new tracking element.
+        */
+       if (t->count >= t->max && !alloc_loc_track(t, 2 * t->max, GFP_ATOMIC))
+               return 0;
+
+       l = t->loc + pos;
+       if (pos < t->count)
+               memmove(l + 1, l,
+                       (t->count - pos) * sizeof(struct location));
+       t->count++;
+       l->count = 1;
+       l->addr = track->addr;
+       memcpy(l->addrs, taddrs, MTK_MEMCFG_SLABTRACE_CNT * sizeof (unsigned long));
+       l->sum_time = age;
+       l->min_time = age;
+       l->max_time = age;
+       l->min_pid = track->pid;
+       l->max_pid = track->pid;
+       cpumask_clear(to_cpumask(l->cpus));
+       cpumask_set_cpu(track->cpu, to_cpumask(l->cpus));
+       nodes_clear(l->nodes);
+       node_set(page_to_nid(virt_to_page(track)), l->nodes);
+       return 1;
+}
+
+static void mtk_memcfg_process_slab(struct loc_track *t, struct kmem_cache *s,
+               struct page *page, enum track_item alloc,
+               unsigned long *map)
+{
+       void *addr = page_address(page);
+       void *p;
+
+       bitmap_zero(map, page->objects);
+       get_map(s, page, map);
+
+       for_each_object(p, s, addr, page->objects)
+               if (!test_bit(slab_index(p, s, addr), map))
+                       mtk_memcfg_add_location(t, s, get_track(s, p, alloc));
+}
+
+static int mtk_memcfg_list_locations(struct kmem_cache *s, struct seq_file *m,
+                                       enum track_item alloc)
+{
+       unsigned long i, j;
+       struct loc_track t = { 0, 0, NULL };
+       int node;
+       unsigned long *map = kmalloc(BITS_TO_LONGS(oo_objects(s->max)) *
+                                    sizeof(unsigned long), GFP_KERNEL);
+
+       if (!map || !alloc_loc_track(&t, PAGE_SIZE / sizeof(struct location),
+                                    GFP_TEMPORARY)) {
+               kfree(map);
+               return seq_printf(m, "Out of memory\n");
+       }
+       /* Push back cpu slabs */
+       flush_all(s);
+
+       for_each_node_state(node, N_NORMAL_MEMORY) {
+               struct kmem_cache_node *n = get_node(s, node);
+               unsigned long flags;
+               struct page *page;
+
+               if (!atomic_long_read(&n->nr_slabs))
+                       continue;
+
+               spin_lock_irqsave(&n->list_lock, flags);
+               list_for_each_entry(page, &n->partial, lru)
+                       mtk_memcfg_process_slab(&t, s, page, alloc, map);
+               list_for_each_entry(page, &n->full, lru)
+                       mtk_memcfg_process_slab(&t, s, page, alloc, map);
+               spin_unlock_irqrestore(&n->list_lock, flags);
+       }
+
+       for (i = 0; i < t.count; i++) {
+               struct location *l = &t.loc[i];
+
+               seq_printf(m, "%7ld ", l->count);
+
+               if (l->addr)
+                       seq_printf(m, "%pS", (void *)l->addr);
+               else
+                       seq_printf(m, "<not-available>");
+
+               for (j = 0; j < MTK_MEMCFG_SLABTRACE_CNT; j++)
+                       if (l->addrs[j])
+                               seq_printf(m, " %p", (void *)l->addrs[j]);
+
+               seq_printf(m, "\n");
+       }
+
+       free_loc_track(&t);
+       kfree(map);
+
+       if (!t.count)
+               seq_printf(m, "No data\n");
+       return 0;
+}
+
+static int mtk_memcfg_slabtrace_show(struct seq_file *m, void *p)
+{
+       struct kmem_cache *s;
+       mutex_lock(&slab_mutex);
+       list_for_each_entry(s, &slab_caches, list) {
+               seq_printf(m, "========== kmem_cache: %s alloc_calls ==========\n", s->name);
+               if (!(s->flags & SLAB_STORE_USER)) {
+                       continue;
+               } else {
+                       mtk_memcfg_list_locations(s, m, TRACK_ALLOC);
+               }
+       }
+       mutex_unlock(&slab_mutex);
+       return 0;
+}
+
+int slabtrace_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, mtk_memcfg_slabtrace_show, NULL);
+}
+
+#endif 
+
 #endif /* CONFIG_SLABINFO */