From 172fb962d99ec4848c6b40b77081d4967c2cfdaf Mon Sep 17 00:00:00 2001 From: BlackMesa123 Date: Sun, 4 Nov 2018 14:25:20 +0100 Subject: [PATCH] mm: merge mm drivers from A750FNXXU1ARIC Signed-off-by: BlackMesa123 --- .../staging/android/ion/exynos/exynos_ion.c | 25 ++++++++ drivers/staging/android/ion/ion.c | 12 ++++ drivers/staging/android/ion/ion_priv.h | 7 +++ drivers/staging/android/ion/ion_system_heap.c | 49 ++++++++++++++++ drivers/staging/android/lowmemorykiller.c | 1 + include/linux/notifier.h | 4 ++ mm/Makefile | 2 +- mm/hpa.c | 6 ++ mm/oom_kill.c | 4 +- mm/page-writeback.c | 4 ++ mm/page_alloc.c | 4 +- mm/showmem_extra.c | 57 +++++++++++++++++++ mm/vmalloc.c | 28 +++++++++ mm/zswap.c | 21 +++++++ 14 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 mm/showmem_extra.c diff --git a/drivers/staging/android/ion/exynos/exynos_ion.c b/drivers/staging/android/ion/exynos/exynos_ion.c index f0d1d2139073..a26bd477e6c4 100644 --- a/drivers/staging/android/ion/exynos/exynos_ion.c +++ b/drivers/staging/android/ion/exynos/exynos_ion.c @@ -638,6 +638,28 @@ err: return ret; } +static int ion_system_heap_size_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + show_ion_system_heap_size((struct seq_file *)data); + return 0; +} + +static struct notifier_block ion_system_heap_nb = { + .notifier_call = ion_system_heap_size_notifier, +}; + +static int ion_system_heap_pool_size_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + show_ion_system_heap_pool_size((struct seq_file *)data); + return 0; +} + +static struct notifier_block ion_system_heap_pool_nb = { + .notifier_call = ion_system_heap_pool_size_notifier, +}; + static int __init exynos_ion_init(void) { int ret; @@ -652,6 +674,9 @@ static int __init exynos_ion_init(void) if (ret) return ret; + show_mem_extra_notifier_register(&ion_system_heap_nb); + show_mem_extra_notifier_register(&ion_system_heap_pool_nb); + return exynos_ion_populate_heaps(ion_exynos); } diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index bb5b3e181be9..8b57d92696f1 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -405,6 +405,7 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, struct sg_table *table; struct scatterlist *sg; int i, ret; + long nr_alloc_cur, nr_alloc_peak; buffer = kzalloc(sizeof(struct ion_buffer), GFP_KERNEL); if (!buffer) @@ -481,6 +482,10 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, mutex_lock(&dev->buffer_lock); ion_buffer_add(dev, buffer); mutex_unlock(&dev->buffer_lock); + nr_alloc_cur = atomic_long_add_return(len, &heap->total_allocated); + nr_alloc_peak = atomic_long_read(&heap->total_allocated_peak); + if (nr_alloc_cur > nr_alloc_peak) + atomic_long_set(&heap->total_allocated_peak, nr_alloc_cur); return buffer; err: @@ -510,6 +515,7 @@ void ion_buffer_destroy(struct ion_buffer *buffer) kfree(iovm_map); } + atomic_long_sub(buffer->size, &buffer->heap->total_allocated); buffer->heap->ops->unmap_dma(buffer->heap, buffer); buffer->heap->ops->free(buffer); vfree(buffer->pages); @@ -550,6 +556,9 @@ static int ion_buffer_put(struct ion_buffer *buffer) static void ion_buffer_add_to_handle(struct ion_buffer *buffer) { mutex_lock(&buffer->lock); + if (buffer->handle_count == 0) + atomic_long_add(buffer->size, &buffer->heap->total_handles); + buffer->handle_count++; mutex_unlock(&buffer->lock); } @@ -575,6 +584,7 @@ static void ion_buffer_remove_from_handle(struct ion_buffer *buffer) get_task_comm(buffer->task_comm, task); buffer->pid = task_pid_nr(task); } + atomic_long_sub(buffer->size, &buffer->heap->total_handles); mutex_unlock(&buffer->lock); } @@ -2054,6 +2064,8 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) seq_printf(s, "%16s %16zu\n", "total orphaned", total_orphaned_size); seq_printf(s, "%16s %16zu\n", "total ", total_size); + seq_printf(s, "%16.s %16lu\n", "peak allocated", + atomic_long_read(&heap->total_allocated_peak)); if (heap->flags & ION_HEAP_FLAG_DEFER_FREE) seq_printf(s, "%16s %16zu\n", "deferred free", heap->free_list_size); diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index 7685c6067781..07d4212bce3c 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -247,6 +247,9 @@ struct ion_heap { struct task_struct *task; int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *); + atomic_long_t total_allocated; + atomic_long_t total_allocated_peak; + atomic_long_t total_handles; }; /** @@ -605,6 +608,10 @@ struct ion_eventlog { void ION_EVENT_SHRINK(struct ion_device *dev, size_t size); void ION_EVENT_CLEAR(struct ion_buffer *buffer, ktime_t begin); + +void show_ion_system_heap_size(struct seq_file *s); +void show_ion_system_heap_pool_size(struct seq_file *s); + #else #define ION_EVENT_BEGIN() do { } while (0) #define ION_EVENT_DONE() do { } while (0) diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 931417d1f55e..ba2f3f054347 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -35,6 +35,7 @@ static gfp_t low_order_gfp_flags = (GFP_HIGHUSER | __GFP_ZERO | __GFP_NOWARN); static const unsigned int orders[] = {8, 4, 0}; static const int num_orders = ARRAY_SIZE(orders); static unsigned int fixed_max_order; +static struct ion_system_heap *system_heap; static int order_to_index(unsigned int order) { @@ -311,6 +312,49 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s, return 0; } +void show_ion_system_heap_size(struct seq_file *s) +{ + struct ion_heap *heap; + unsigned long system_byte = 0; + + if (!system_heap) { + pr_err("system_heap is not ready\n"); + return; + } + + heap = &system_heap->heap; + system_byte = (unsigned int)atomic_long_read(&heap->total_allocated); + if (s) + seq_printf(s, "SystemHeap: %8lu kB\n", system_byte >> 10); + else + pr_cont("SystemHeap:%lukB ", system_byte >> 10); +} + +void show_ion_system_heap_pool_size(struct seq_file *s) +{ + unsigned long pool_size = 0; + struct ion_page_pool *pool; + int i; + + if (!system_heap) { + pr_err("system_heap_pool is not ready\n"); + return; + } + + for (i = 0; i < num_orders * 2; i++) { + pool = system_heap->pools[i]; + pool_size += (1 << pool->order) * pool->high_count; + pool_size += (1 << pool->order) * pool->low_count; + } + + if (s) + seq_printf(s, "SystemHeapPool: %8lu kB\n", + pool_size << (PAGE_SHIFT - 10)); + else + pr_cont("SystemHeapPool:%lukB ", + pool_size << (PAGE_SHIFT - 10)); +} + static ssize_t ion_system_heap_orders_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -373,6 +417,11 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused) if (sysfs_create_file(kernel_kobj, &ion_system_heap_orders_attr.attr)) pr_err("%s: Failed to create sysfs on ION system heap", __func__); + if (!system_heap) + system_heap = heap; + else + pr_err("system_heap had been already created\n"); + return &heap->heap; destroy_pools: diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 46e7507a70de..c32ec343d55b 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -210,6 +210,7 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) cache_size, cache_limit, min_score_adj, free); + show_mem_extra_call_notifiers(); lowmem_deathpending_timeout = jiffies + HZ; rem += selected_tasksize; lowmem_lmkcount++; diff --git a/include/linux/notifier.h b/include/linux/notifier.h index d14a4c362465..498fb2f81f77 100644 --- a/include/linux/notifier.h +++ b/include/linux/notifier.h @@ -211,5 +211,9 @@ static inline int notifier_to_errno(int ret) extern struct blocking_notifier_head reboot_notifier_list; +extern int show_mem_extra_notifier_register(struct notifier_block *nb); +extern int show_mem_extra_notifier_unregister(struct notifier_block *nb); +extern void show_mem_extra_call_notifiers(void); + #endif /* __KERNEL__ */ #endif /* _LINUX_NOTIFIER_H */ diff --git a/mm/Makefile b/mm/Makefile index b208093b1a55..338c768a3cee 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -24,7 +24,7 @@ obj-y := filemap.o mempool.o oom_kill.o \ mm_init.o mmu_context.o percpu.o slab_common.o \ compaction.o vmacache.o \ interval_tree.o list_lru.o workingset.o \ - debug.o $(mmu-y) + debug.o $(mmu-y) showmem_extra.o obj-y += init-mm.o diff --git a/mm/hpa.c b/mm/hpa.c index 56d02c710128..a03bdfb10637 100644 --- a/mm/hpa.c +++ b/mm/hpa.c @@ -79,6 +79,12 @@ static int hpa_killer(void) p = find_lock_task_mm(tsk); if (!p) continue; + + if (p->state & TASK_UNINTERRUPTIBLE) { + task_unlock(p); + continue; + } + if (test_tsk_thread_flag(p, TIF_MEMDIE) && time_before_eq(jiffies, hpa_deathpending_timeout)) { diff --git a/mm/oom_kill.c b/mm/oom_kill.c index c12680993ff3..f9ccfde9a40a 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -394,8 +394,10 @@ static void dump_header(struct oom_control *oc, struct task_struct *p, dump_stack(); if (memcg) mem_cgroup_print_oom_info(memcg, p); - else + else { + show_mem_extra_call_notifiers(); show_mem(SHOW_MEM_FILTER_NODES); + } if (sysctl_oom_dump_tasks) dump_tasks(memcg, oc->nodemask); } diff --git a/mm/page-writeback.c b/mm/page-writeback.c index f7873c0d3e62..05def1ecc517 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -1740,6 +1740,10 @@ pause: pause, start_time); + /* Do not sleep if the backing device is removed */ + if (unlikely(!bdi->dev)) + return; + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) bdi->last_thresh = thresh; bdi->last_nr_dirty = dirty; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 9b043e4f834a..eaff7a6b0b75 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2760,8 +2760,10 @@ void warn_alloc_failed(gfp_t gfp_mask, unsigned int order, const char *fmt, ...) current->comm, order, gfp_mask); dump_stack(); - if (!should_suppress_show_mem()) + if (!should_suppress_show_mem()) { + show_mem_extra_call_notifiers(); show_mem(filter); + } } static inline struct page * diff --git a/mm/showmem_extra.c b/mm/showmem_extra.c new file mode 100644 index 000000000000..cc588cf0fb2d --- /dev/null +++ b/mm/showmem_extra.c @@ -0,0 +1,57 @@ +#include +#include +#include + +ATOMIC_NOTIFIER_HEAD(show_mem_extra_notifier); + +/** + * Call show_mem notifiers to print out extra memory information + * @s: seq_file into which print log out, if Null print to kernel log buffer + */ +static void __show_mem_extra_call_notifiers(struct seq_file *s) +{ + atomic_notifier_call_chain(&show_mem_extra_notifier, 0, s); + if (s == NULL) + printk("\n"); +} + +int show_mem_extra_notifier_register(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&show_mem_extra_notifier, nb); +} + +int show_mem_extra_notifier_unregister(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&show_mem_extra_notifier, nb); +} + +void show_mem_extra_call_notifiers(void) +{ + __show_mem_extra_call_notifiers(NULL); +} + +static int meminfo_extra_proc_show(struct seq_file *m, void *v) +{ + __show_mem_extra_call_notifiers(m); + return 0; +} + +static int meminfo_extra_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, meminfo_extra_proc_show, NULL); +} + +static const struct file_operations meminfo_extra_proc_fops = { + .open = meminfo_extra_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init proc_meminfo_extra_init(void) +{ + proc_create("meminfo_extra", 0444, NULL, &meminfo_extra_proc_fops); + return 0; +} +fs_initcall(proc_meminfo_extra_init); + diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 69c444996624..a2d823c21adc 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -35,6 +35,8 @@ #include #include +atomic_long_t nr_vmalloc_pages; + #include "internal.h" struct vfree_deferred { @@ -1491,6 +1493,7 @@ static void __vunmap(const void *addr, int deallocate_pages) else kfree(area->pages); } + atomic_long_sub(area->nr_pages, &nr_vmalloc_pages); kfree(area); return; @@ -1627,6 +1630,7 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask, if (gfpflags_allow_blocking(gfp_mask)) cond_resched(); } + atomic_long_add(area->nr_pages, &nr_vmalloc_pages); if (map_vm_area(area, prot, pages)) goto fail; @@ -2688,9 +2692,33 @@ static const struct file_operations proc_vmalloc_operations = { .release = seq_release_private, }; +static int vmalloc_size_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct seq_file *s; + + s = (struct seq_file *)data; + if (s != NULL) + seq_printf(s, "VmallocAPIsize: %8lu kB\n", + atomic_long_read(&nr_vmalloc_pages) + << (PAGE_SHIFT - 10)); + else + pr_cont("VmallocAPIsize:%lukB ", + atomic_long_read(&nr_vmalloc_pages) + << (PAGE_SHIFT - 10)); + return 0; +} + +static struct notifier_block vmalloc_size_nb = { + .notifier_call = vmalloc_size_notifier, +}; + static int __init proc_vmalloc_init(void) { proc_create("vmallocinfo", S_IRUSR, NULL, &proc_vmalloc_operations); + atomic_long_set(&nr_vmalloc_pages, 0); + show_mem_extra_notifier_register(&vmalloc_size_nb); + return 0; } module_init(proc_vmalloc_init); diff --git a/mm/zswap.c b/mm/zswap.c index 1afc6a45467a..53290113f18c 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -1694,6 +1694,25 @@ static int __init zswap_debugfs_init(void) static void __exit zswap_debugfs_exit(void) { } #endif +static int zswap_size_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct seq_file *s; + + s = (struct seq_file *)data; + if (s) + seq_printf(s, "ZSwapDevice: %8lu kB\n", + (unsigned long)zswap_pool_pages << (PAGE_SHIFT - 10)); + else + pr_cont("ZSwapDevice:%lukB ", + (unsigned long)zswap_pool_pages << (PAGE_SHIFT - 10)); + return 0; +} + +static struct notifier_block zswap_size_nb = { + .notifier_call = zswap_size_notifier, +}; + /********************************* * module init and exit **********************************/ @@ -1732,6 +1751,8 @@ static int __init init_zswap(void) frontswap_register_ops(&zswap_frontswap_ops); if (zswap_debugfs_init()) pr_warn("debugfs initialization failed\n"); + + show_mem_extra_notifier_register(&zswap_size_nb); return 0; pool_fail: