diff options
| -rw-r--r-- | drivers/misc/mediatek/Makefile.mt6735 | 1 | ||||
| -rwxr-xr-x | drivers/misc/mediatek/mlog/Makefile | 6 | ||||
| -rw-r--r-- | drivers/misc/mediatek/mlog/mlog_dump.c | 85 | ||||
| -rw-r--r-- | drivers/misc/mediatek/mlog/mlog_internal.h | 14 | ||||
| -rw-r--r-- | drivers/misc/mediatek/mlog/mlog_logger.c | 871 | ||||
| -rw-r--r-- | drivers/staging/android/lowmemorykiller.c | 9 |
6 files changed, 986 insertions, 0 deletions
diff --git a/drivers/misc/mediatek/Makefile.mt6735 b/drivers/misc/mediatek/Makefile.mt6735 index 96ed85c98..66ce14991 100644 --- a/drivers/misc/mediatek/Makefile.mt6735 +++ b/drivers/misc/mediatek/Makefile.mt6735 @@ -88,6 +88,7 @@ obj-$(CONFIG_MTK_C2K_SUPPORT) += c2k_ccci/ obj-$(CONFIG_MTK_ECCCI_DRIVER) += eccci/ #obj-$(CONFIG_MTK_EEMCS_DRIVER) += eemcs/ obj-$(CONFIG_MTK_NFC) += nfc/ +obj-$(CONFIG_ZRAM) += mlog/ obj-$(CONFIG_MTK_IRTX_SUPPORT) += irtx/ #obj-y += cam_cal/dummy_eeprom/ diff --git a/drivers/misc/mediatek/mlog/Makefile b/drivers/misc/mediatek/mlog/Makefile new file mode 100755 index 000000000..5ed5b7065 --- /dev/null +++ b/drivers/misc/mediatek/mlog/Makefile @@ -0,0 +1,6 @@ +ccflags-$(CONFIG_ZRAM) += -I$(srctree)/drivers/staging/zram +ccflags-$(CONFIG_ZSMALLOC) += -I$(srctree)/drivers/staging/zsmalloc +ccflags-y += -I$(srctree)/drivers/staging/android/ion + +obj-y += mlog.o +mlog-y := mlog_dump.o mlog_logger.o diff --git a/drivers/misc/mediatek/mlog/mlog_dump.c b/drivers/misc/mediatek/mlog/mlog_dump.c new file mode 100644 index 000000000..d68d57cad --- /dev/null +++ b/drivers/misc/mediatek/mlog/mlog_dump.c @@ -0,0 +1,85 @@ +#include <linux/types.h> +/* #include <linux/errno.h> */ +/* #include <linux/time.h> */ +/* #include <linux/kernel.h> */ +/* #include <linux/module.h> */ +#include <linux/wait.h> +#include <linux/poll.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> + +#include "mlog_internal.h" + + +extern wait_queue_head_t mlog_wait; +extern void mlog_doopen(void); +extern int mlog_unread(void); +extern int mlog_doread(char __user *buf, size_t len); +extern int mlog_show_info(struct seq_file *m, void *v); +extern int mlog_print_fmt(struct seq_file *m); + + +static int mlog_open(struct inode *inode, struct file *file) +{ + MLOG_PRINTK("[mlog] open %d\n", mlog_unread()); + mlog_doopen(); + return 0; +} + +static int mlog_release(struct inode *inode, struct file *file) +{ + MLOG_PRINTK("[mlog] release\n"); + return 0; +} + +static ssize_t mlog_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + if (file->f_flags & O_NONBLOCK) { + if (!mlog_unread()) + return -EAGAIN; + /* MLOG_PRINTK("[mlog] read (NonBlock) %d\n", count); */ + } + return mlog_doread(buf, count); +} + +static unsigned int mlog_poll(struct file *file, poll_table *wait) +{ + /* MLOG_PRINTK("[mlog] poll\n"); */ + poll_wait(file, &mlog_wait, wait); + if (mlog_unread()) + return POLLIN | POLLRDNORM; + return 0; +} + +static const struct file_operations proc_mlog_operations = { + .read = mlog_read, + .poll = mlog_poll, + .open = mlog_open, + .release = mlog_release, + .llseek = generic_file_llseek, +}; + +static int mlog_fmt_proc_show(struct seq_file *m, void *v) +{ + return mlog_print_fmt(m); +} + +static int mlog_fmt_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, mlog_fmt_proc_show, NULL); +} + +static const struct file_operations mlog_fmt_proc_fops = { + .open = mlog_fmt_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void mlog_init_procfs(void) +{ + proc_create("mlog_fmt", 0, NULL, &mlog_fmt_proc_fops); + proc_create("mlog", 0, NULL, &proc_mlog_operations); +} diff --git a/drivers/misc/mediatek/mlog/mlog_internal.h b/drivers/misc/mediatek/mlog/mlog_internal.h new file mode 100644 index 000000000..87117ca20 --- /dev/null +++ b/drivers/misc/mediatek/mlog/mlog_internal.h @@ -0,0 +1,14 @@ +#ifndef _MLOG_INTERNAL_H +#define _MLOG_INTERNAL_H + +#include <linux/printk.h> + +#define MLOG_DEBUG + +#ifdef MLOG_DEBUG +#define MLOG_PRINTK(args...) pr_debug(args) +#else +#define MLOG_PRINTK(args...) do { } while (0) +#endif + +#endif diff --git a/drivers/misc/mediatek/mlog/mlog_logger.c b/drivers/misc/mediatek/mlog/mlog_logger.c new file mode 100644 index 000000000..4fea58343 --- /dev/null +++ b/drivers/misc/mediatek/mlog/mlog_logger.c @@ -0,0 +1,871 @@ +#include <linux/types.h> +#include <linux/module.h> +#include <linux/mm.h> +#include <linux/oom.h> +#include <linux/sched.h> +#include <linux/vmstat.h> +#include <linux/sysinfo.h> +#include <linux/swap.h> +#include <linux/cpu.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/cpumask.h> +#include <linux/cred.h> +#include <linux/rcupdate.h> +#include <linux/seq_file.h> +#include <asm/uaccess.h> +#include <linux/version.h> + +#define COLLECT_GPU_MEMINFO + +#ifdef COLLECT_GPU_MEMINFO +#include <linux/mtk_gpu_utility.h> +#endif + +#ifdef CONFIG_ZSMALLOC +#include <linux/zsmalloc.h> +#endif + +/*#ifdef CONFIG_ZRAM +#include <linux/zram_drv.h> +#endif*/ + +/* for collecting ion total memory usage*/ +#ifdef CONFIG_ION_MTK +#include <linux/ion_drv.h> +#endif + +#include "mlog_internal.h" + +#define CONFIG_MLOG_BUF_SHIFT 16 /* 64KB */ + +#define P2K(x) (((unsigned long)x) << (PAGE_SHIFT - 10)) +#define B2K(x) (((unsigned long)x) >> (10)) + + +#define MLOG_STR_LEN 16 +#define MLOG_BUF_LEN ((1 << CONFIG_MLOG_BUF_SHIFT) >> 2) +#define MLOG_BUF_MASK (mlog_buf_len-1) +#define MLOG_BUF(idx) (mlog_buffer[(idx) & MLOG_BUF_MASK]) + +#define MLOG_ID ULONG_MAX + +#define AID_ROOT 0 /* traditional unix root user */ +#define AID_SYSTEM 1000 /* system server */ + +#define M_MEMFREE (1 << 0) +#define M_SWAPFREE (1 << 1) +#define M_CACHED (1 << 2) +#define M_GPUUSE (1 << 3) +#define M_MLOCK (1 << 4) +#define M_ZRAM (1 << 5) +#define M_ACTIVE (1 << 6) +#define M_INACTIVE (1 << 7) +#define M_SHMEM (1 << 8) +#define M_GPU_PAGE_CACHE (1 << 9) +#define M_ION (1 << 10) + +#define V_PSWPIN (1 << 0) +#define V_PSWPOUT (1 << 1) +#define V_PGFMFAULT (1 << 2) +#define V_PGANFAULT (1 << 3) + +#define P_ADJ (1 << 0) +#define P_RSS (1 << 1) +#define P_RSWAP (1 << 2) +#define P_SWPIN (1 << 3) +#define P_SWPOUT (1 << 4) +#define P_FMFAULT (1 << 5) +#define P_MINFAULT (1 << 6) +#define P_MAJFAULT (1 << 7) + +#define B_NORMAL (1 << 0) +#define B_HIGH (1 << 1) + +#define P_FMT_SIZE (P_RSS | P_RSWAP) +#define P_FMT_COUNT (P_SWPIN | P_SWPOUT | P_FMFAULT | P_MINFAULT | P_MAJFAULT) + +#define M_FILTER_ALL (M_MEMFREE | M_SWAPFREE | M_CACHED | M_GPUUSE | M_GPU_PAGE_CACHE | M_MLOCK | M_ZRAM | M_ACTIVE | M_INACTIVE | M_SHMEM | M_ION) +#define V_FILTER_ALL (V_PSWPIN | V_PSWPOUT | V_PGFMFAULT | V_PGANFAULT) +#define P_FILTER_ALL (P_ADJ | P_RSS | P_RSWAP | P_SWPIN | P_SWPOUT | P_FMFAULT) +#define B_FILTER_ALL (B_NORMAL | B_HIGH) + +#define MLOG_TRIGGER_TIMER 0 +#define MLOG_TRIGGER_LMK 1 +#define MLOG_TRIGGER_LTK 2 + +extern void mlog_init_procfs(void); + +static uint meminfo_filter = M_FILTER_ALL; +static uint vmstat_filter = V_FILTER_ALL; +static uint proc_filter = P_FILTER_ALL; +static uint buddyinfo_filter = B_FILTER_ALL; + +static DEFINE_SPINLOCK(mlogbuf_lock); +DECLARE_WAIT_QUEUE_HEAD(mlog_wait); +static long mlog_buffer[MLOG_BUF_LEN]; +static int mlog_buf_len = MLOG_BUF_LEN; +static unsigned mlog_start; +static unsigned mlog_end; + +static int min_adj = -16; +static int max_adj = 16; +static int limit_pid = -1; + +static struct timer_list mlog_timer; +static unsigned long timer_intval = HZ; + +static char **strfmt_list; +static int strfmt_idx; +static int strfmt_len; +static int strfmt_proc; + +static char cr_str[] = "%c"; +static char type_str[] = "<%ld>"; +static char time_sec_str[] = "[%5lu"; +static char time_nanosec_str[] = ".%06lu]"; +static char mem_size_str[] = " %6lu"; +static char acc_count_str[] = " %7lu"; +static char pid_str[] = " [%lu]"; +static char adj_str[] = " %3ld"; + +/* +buddyinfo +Node 0, zone Normal 486 297 143 59 30 16 7 0 2 1 54 +Node 0, zone HighMem 74 18 7 65 161 67 23 10 0 1 21 +*/ + /* 0 1 2 3 4 5 6 7 8 9 10 */ +static char order_start_str[] = " [%6lu"; +static char order_middle_str[] = " %6lu"; +static char order_end_str[] = " %6lu]"; + +/* +active & inactive +Active: 211748 kB +Inactive: 257988 kB +*/ + +static void mlog_emit_32(long v) +{ + MLOG_BUF(mlog_end) = v; + mlog_end++; + if (mlog_end - mlog_start > mlog_buf_len) + mlog_start = mlog_end - mlog_buf_len; +} + +/* +static void mlog_emit_32_ex(long v) +{ + spin_lock_bh(&mlogbuf_lock); + mlog_emit_32(v); + spin_unlock_bh(&mlogbuf_lock); +} + +static void mlog_emit_64(long long v) +{ + mlog_emit_32(v >> BITS_PER_LONG); + mlog_emit_32(v & ULONG_MAX); +} +*/ + +static void mlog_reset_format(void) +{ + int len; + + spin_lock_bh(&mlogbuf_lock); + + if (meminfo_filter) + meminfo_filter = M_FILTER_ALL; + if (vmstat_filter) + vmstat_filter = V_FILTER_ALL; + if (buddyinfo_filter) + buddyinfo_filter = B_FILTER_ALL; + if (proc_filter) + proc_filter = P_FILTER_ALL; + + /* calc len */ + len = 4; /* id, type, sec, nanosec */ + + len += hweight32(meminfo_filter); + len += hweight32(vmstat_filter); + + /* buddyinfo */ + len += (2 * MAX_ORDER); + + if (proc_filter) { + len++; /* PID */ + len += hweight32(proc_filter); + } + + if (!strfmt_list || strfmt_len != len) { + if (strfmt_list) + kfree(strfmt_list); + strfmt_list = kmalloc(sizeof(char *) * len, GFP_ATOMIC); + strfmt_len = len; + BUG_ON(!strfmt_list); + } + + /* setup str format */ + len = 0; + strfmt_proc = 0; + strfmt_list[len++] = cr_str; + strfmt_list[len++] = type_str; + strfmt_list[len++] = time_sec_str; + strfmt_list[len++] = time_nanosec_str; + + if (meminfo_filter) { + int i; + for (i = 0; i < hweight32(meminfo_filter); ++i) + strfmt_list[len++] = mem_size_str; + } + + if (vmstat_filter) { + int i; + for (i = 0; i < hweight32(vmstat_filter); ++i) + strfmt_list[len++] = acc_count_str; + } + + if (buddyinfo_filter) { + int i, j; + /* normal and high zone */ + for (i = 0; i < 2; ++i) { + strfmt_list[len++] = order_start_str; + for (j = 0; j < MAX_ORDER - 2; ++j) { + strfmt_list[len++] = order_middle_str; + } + strfmt_list[len++] = order_end_str; + } + } + + if (proc_filter) { + int i; + strfmt_proc = len; + strfmt_list[len++] = pid_str; /* PID */ + strfmt_list[len++] = adj_str; /* ADJ */ + for (i = 0; i < hweight32(proc_filter & (P_FMT_SIZE)); ++i) + strfmt_list[len++] = mem_size_str; + for (i = 0; i < hweight32(proc_filter & (P_FMT_COUNT)); ++i) + strfmt_list[len++] = acc_count_str; + } + strfmt_idx = 0; + + BUG_ON(len != strfmt_len); + spin_unlock_bh(&mlogbuf_lock); + + MLOG_PRINTK("[mlog] reset format %d", strfmt_len); + for (len = 0; len < strfmt_len; ++len) { + MLOG_PRINTK(" %s", strfmt_list[len]); + } + MLOG_PRINTK("\n"); +} + +int mlog_print_fmt(struct seq_file *m) +{ + seq_puts(m, "<type> [time]"); + + if (meminfo_filter & M_MEMFREE) + seq_puts(m, " memfr"); + if (meminfo_filter & M_SWAPFREE) + seq_puts(m, " swpfr"); + if (meminfo_filter & M_CACHED) + seq_puts(m, " cache"); + if (meminfo_filter & M_GPUUSE) + seq_puts(m, " gpu"); + if (meminfo_filter & M_GPU_PAGE_CACHE) + seq_puts(m, " gpu_page_cache"); + if (meminfo_filter & M_MLOCK) + seq_puts(m, " mlock"); + if (meminfo_filter & M_ZRAM) + seq_puts(m, " zram"); + if (meminfo_filter & M_ACTIVE) + seq_puts(m, " active"); + if (meminfo_filter & M_INACTIVE) + seq_puts(m, " inactive"); + if (meminfo_filter & M_SHMEM) + seq_puts(m, " shmem"); + if (meminfo_filter & M_ION) + seq_printf(m, " ion"); + + if (vmstat_filter & V_PSWPIN) + seq_puts(m, " swpin"); + if (vmstat_filter & V_PSWPOUT) + seq_puts(m, " swpout"); + if (vmstat_filter & V_PGFMFAULT) + seq_puts(m, " fmflt"); + if (vmstat_filter & V_PGANFAULT) + seq_puts(m, " anflt"); + + if (buddyinfo_filter) { + seq_puts(m, " [normal]"); + seq_puts(m, " [high]"); + } + + if (proc_filter) { + seq_puts(m, " [pid]"); + if (proc_filter & P_ADJ) + seq_puts(m, " adj"); + if (proc_filter & P_RSS) + seq_puts(m, " rss"); + if (proc_filter & P_RSWAP) + seq_puts(m, " rswp"); + if (proc_filter & P_SWPIN) + seq_puts(m, " pswpin"); + if (proc_filter & P_SWPOUT) + seq_puts(m, " pswpout"); + if (proc_filter & P_FMFAULT) + seq_puts(m, " pfmflt"); + } + seq_puts(m, "\n"); + return 0; +} + +static void mlog_reset_buffer(void) +{ + spin_lock_bh(&mlogbuf_lock); + mlog_end = mlog_start = 0; + spin_unlock_bh(&mlogbuf_lock); + + MLOG_PRINTK("[mlog] reset buffer\n"); +} + +#ifdef CONFIG_MTKPASR +extern unsigned long mtkpasr_show_page_reserved(void); +#else +#define mtkpasr_show_page_reserved(void) (0) +#endif +static void mlog_meminfo(void) +{ + unsigned long memfree; + unsigned long swapfree; + unsigned long cached; + unsigned int gpuuse = 0; + unsigned int gpu_page_cache = 0; + unsigned long mlock; + unsigned long zram; + unsigned long active, inactive; + unsigned long shmem; + unsigned long ion = 0; + + memfree = P2K(global_page_state(NR_FREE_PAGES) + mtkpasr_show_page_reserved()); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) + swapfree = P2K(atomic_long_read(&nr_swap_pages)); + cached = P2K(global_page_state(NR_FILE_PAGES) - total_swapcache_pages()); +#else + swapfree = P2K(nr_swap_pages); + cached = P2K(global_page_state(NR_FILE_PAGES) - total_swapcache_pages); +#endif + +#ifdef COLLECT_GPU_MEMINFO + if (mtk_get_gpu_memory_usage(&gpuuse)) + gpuuse = B2K(gpuuse); + if (mtk_get_gpu_page_cache(&gpu_page_cache)) + gpu_page_cache = B2K(gpu_page_cache); +#endif + + mlock = P2K(global_page_state(NR_MLOCK)); +/*#if defined(CONFIG_ZRAM) & defined(CONFIG_ZSMALLOC) + zram = (zram_devices && zram_devices->meta) ? + B2K(zs_get_total_size_bytes(zram_devices->meta->mem_pool)) : 0; +#else*/ + zram = 0; +/*#endif*/ + + active = P2K(global_page_state(NR_ACTIVE_ANON) + global_page_state(NR_ACTIVE_FILE)); + inactive = P2K(global_page_state(NR_INACTIVE_ANON) + global_page_state(NR_INACTIVE_FILE)); + /* MLOG_PRINTK("active: %lu, inactive: %lu\n", active, inactive); */ + shmem = P2K(global_page_state(NR_SHMEM)); + +#ifdef CONFIG_ION_MTK + ion = B2K((unsigned long)ion_mm_heap_total_memory()); +#endif + + spin_lock_bh(&mlogbuf_lock); + mlog_emit_32(memfree); + mlog_emit_32(swapfree); + mlog_emit_32(cached); + mlog_emit_32(gpuuse); + mlog_emit_32(gpu_page_cache); + mlog_emit_32(mlock); + mlog_emit_32(zram); + mlog_emit_32(active); + mlog_emit_32(inactive); + mlog_emit_32(shmem); + mlog_emit_32(ion); + spin_unlock_bh(&mlogbuf_lock); +} + +static void mlog_vmstat(void) +{ + int cpu; + unsigned long v[NR_VM_EVENT_ITEMS]; + + memset(v, 0, NR_VM_EVENT_ITEMS * sizeof(unsigned long)); + + for_each_online_cpu(cpu) { + struct vm_event_state *this = &per_cpu(vm_event_states, cpu); + v[PSWPIN] += this->event[PSWPIN]; + v[PSWPOUT] += this->event[PSWPOUT]; + v[PGFMFAULT] += this->event[PGFMFAULT]; + + /* TODO: porting PGANFAULT to kernel-3.10 */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)) + v[PGANFAULT] += this->event[PGANFAULT]; +#endif + } + + spin_lock_bh(&mlogbuf_lock); + mlog_emit_32(v[PSWPIN]); + mlog_emit_32(v[PSWPOUT]); + mlog_emit_32(v[PGFMFAULT]); + + /* TODO: porting PGANFAULT to kernel-3.10 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) + mlog_emit_32(0); +#else + mlog_emit_32(v[PGANFAULT]); +#endif + spin_unlock_bh(&mlogbuf_lock); +} + +/* static void mlog_buddyinfo(void) */ +void mlog_buddyinfo(void) +{ + int i; + struct zone *zone; + struct zone *node_zones; + unsigned int order; + int zone_nr = 0; + unsigned long normal_nr_free[MAX_ORDER]; + unsigned long high_nr_free[MAX_ORDER]; + + for_each_online_node(i) { + pg_data_t *pgdat = NODE_DATA(i); + unsigned long flags; + + node_zones = pgdat->node_zones; + + /* MAX_NR_ZONES 3 */ + for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) { + if (!populated_zone(zone)) + continue; + + spin_lock_irqsave(&zone->lock, flags); + + zone_nr++; + + for (order = 0; order < MAX_ORDER; ++order) { + if (zone_nr == 1) + normal_nr_free[order] = zone->free_area[order].nr_free; + if (zone_nr == 2) + high_nr_free[order] = zone->free_area[order].nr_free; + } + spin_unlock_irqrestore(&zone->lock, flags); + } + } + + + if (zone_nr == 1) { + for (order = 0; order < MAX_ORDER; ++order) + high_nr_free[order] = 0; + } +#ifdef CONFIG_MTKPASR + if (zone_nr == 2) { + high_nr_free[MAX_ORDER - 1] += (mtkpasr_show_page_reserved() >> (MAX_ORDER - 1)); + } +#endif + + spin_lock_bh(&mlogbuf_lock); + + for (order = 0; order < MAX_ORDER; ++order) { + mlog_emit_32(normal_nr_free[order]); + } + + for (order = 0; order < MAX_ORDER; ++order) { + mlog_emit_32(high_nr_free[order]); + } + + spin_unlock_bh(&mlogbuf_lock); +} + +struct task_struct *find_trylock_task_mm(struct task_struct *t) +{ + if (spin_trylock(&t->alloc_lock)) { + if (likely(t->mm)) + return t; + task_unlock(t); + } + return NULL; +} + +/* + * it's copied from lowmemorykiller.c +*/ +#ifndef CONFIG_MEMCG +static short lowmem_oom_score_adj_to_oom_adj(short oom_score_adj) +{ + if (oom_score_adj == OOM_SCORE_ADJ_MAX) + return OOM_ADJUST_MAX; + else + return ((oom_score_adj * -OOM_DISABLE * 10) / OOM_SCORE_ADJ_MAX + 5) / 10; /* round */ +} +#endif + +static void mlog_procinfo(void) +{ + struct task_struct *tsk; + + rcu_read_lock(); + for_each_process(tsk) { + int oom_score_adj; + const struct cred *cred = NULL; + struct task_struct *real_parent; + struct task_struct *p; + pid_t ppid; + struct task_struct *t; + unsigned long swap_in, swap_out, fm_flt, min_flt, maj_flt; + unsigned long rss; + unsigned long rswap; + + if (tsk->flags & PF_KTHREAD) + continue; + + p = find_trylock_task_mm(tsk); + if (!p) + continue; + + if (!p->signal) + goto unlock_continue; + +#ifndef CONFIG_MEMCG +#ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES + oom_score_adj = lowmem_oom_score_adj_to_oom_adj(p->signal->oom_score_adj); +#else + oom_score_adj = p->signal->oom_adj; +#endif +#endif + + if (max_adj < oom_score_adj || oom_score_adj < min_adj) + goto unlock_continue; + + if (limit_pid != -1 && p->pid != limit_pid) + goto unlock_continue; + + cred = get_task_cred(p); + if (!cred) + goto unlock_continue; + + /* + * 1. mediaserver is a suspect in many ANR/FLM cases. + * 2. procesname is "mediaserver" not "/system/bin/mediaserver" + */ + if (strncmp("mediaserver", p->comm, TASK_COMM_LEN) == 0) + goto collect_proc_mem_info; + + /* skip root user */ + if (cred->uid == AID_ROOT) + goto unlock_continue; + + real_parent = rcu_dereference(p->real_parent); + if (!real_parent) + goto unlock_continue; + + ppid = real_parent->pid; + /* skip non java proc (parent is init) */ + if (ppid == 1) + goto unlock_continue; + + if (oom_score_adj == -16) { + /* only keep system server */ + if (cred->uid != AID_SYSTEM) + goto unlock_continue; + } + +collect_proc_mem_info: + /* reset data */ + swap_in = swap_out = fm_flt = min_flt = maj_flt = 0; + + /* all threads */ + t = p; + do { + /* min_flt += t->min_flt; */ + /* maj_flt += t->maj_flt; */ +/*#ifdef CONFIG_ZRAM + fm_flt += t->fm_flt; + swap_in += t->swap_in; + swap_out += t->swap_out; +#endif*/ + t = next_thread(t); +#ifdef MLOG_DEBUG +#if defined(__LP64__) || defined(_LP64) + if ((long long)t < 0xffffffc000000000) + break; +#endif +#endif + + } while (t != p); + + /* emit log */ + rss = P2K(get_mm_rss(p->mm)); + rswap = P2K(get_mm_counter(p->mm, MM_SWAPENTS)); + + spin_lock_bh(&mlogbuf_lock); + mlog_emit_32(p->pid); + mlog_emit_32(oom_score_adj); + mlog_emit_32(rss); + mlog_emit_32(rswap); + mlog_emit_32(swap_in); + mlog_emit_32(swap_out); + mlog_emit_32(fm_flt); + /* mlog_emit_32(min_flt); */ + /* mlog_emit_32(maj_flt); */ + spin_unlock_bh(&mlogbuf_lock); + + unlock_continue: + if (cred) + put_cred(cred); + + task_unlock(p); + } + rcu_read_unlock(); + +} + +void mlog(int type) +{ + /* unsigned long flag; */ + unsigned long microsec_rem; + unsigned long long t = local_clock(); +#ifdef PROFILE_MLOG_OVERHEAD + unsigned long long t1 = t; +#endif + /* MLOG_PRINTK("[mlog] log %d %d %d\n", meminfo_filter, vmstat_filter, proc_filter); */ + + /* time stamp */ + microsec_rem = do_div(t, 1000000000); + + /* spin_lock_irqsave(&mlogbuf_lock, flag); */ + + spin_lock_bh(&mlogbuf_lock); + mlog_emit_32(MLOG_ID); /* tag for correct start point */ + mlog_emit_32(type); + mlog_emit_32((unsigned long)t); + mlog_emit_32(microsec_rem / 1000); + spin_unlock_bh(&mlogbuf_lock); + + /* memory log */ + if (meminfo_filter) + mlog_meminfo(); + if (vmstat_filter) + mlog_vmstat(); + + if (buddyinfo_filter) + mlog_buddyinfo(); + + if (proc_filter) + mlog_procinfo(); + + /* spin_unlock_irqrestore(&mlogbuf_lock, flag); */ + + if (waitqueue_active(&mlog_wait)) + wake_up_interruptible(&mlog_wait); + +#ifdef PROFILE_MLOG_OVERHEAD + MLOG_PRINTK("[mlog] %llu ns\n", local_clock() - t1); +#endif +} +EXPORT_SYMBOL(mlog); + +void mlog_doopen(void) +{ + spin_lock_bh(&mlogbuf_lock); + strfmt_idx = 0; + spin_unlock_bh(&mlogbuf_lock); +} + +int mlog_unread(void) +{ + return mlog_end - mlog_start; +} + +int mlog_doread(char __user *buf, size_t len) +{ + unsigned i; + int error = -EINVAL; + char mlog_str[MLOG_STR_LEN]; + + if (!buf || len < 0) + goto out; + error = 0; + if (!len) + goto out; + if (!access_ok(VERIFY_WRITE, buf, len)) { + error = -EFAULT; + goto out; + } + /* MLOG_PRINTK("[mlog] wait %d %d\n", mlog_start, mlog_end); */ + error = wait_event_interruptible(mlog_wait, (mlog_start - mlog_end)); + if (error) + goto out; + i = 0; + spin_lock_bh(&mlogbuf_lock); + + /* MLOG_PRINTK("[mlog] doread %d %d\n", mlog_start, mlog_end); */ + while (!error && (mlog_start != mlog_end) && i < len - MLOG_STR_LEN) { + int size; + int v; + + /* retrieve value */ + v = MLOG_BUF(mlog_start); + mlog_start++; + + if (unlikely((v == MLOG_ID) ^ (strfmt_idx == 0))) { + /* find first valid log */ + if (strfmt_idx == 0) { + continue; + } + strfmt_idx = 0; + } + if (strfmt_idx == 0) { + v = '\n'; + } + /* MLOG_PRINTK("[mlog] %d: %s\n", strfmt_idx, strfmt_list[strfmt_idx]); */ + size = snprintf(mlog_str, MLOG_STR_LEN, strfmt_list[strfmt_idx++], v); + + if (strfmt_idx >= strfmt_len) + strfmt_idx = strfmt_proc; + + spin_unlock_bh(&mlogbuf_lock); + if (__copy_to_user(buf, mlog_str, size)) + error = -EFAULT; + else { + buf += size; + i += size; + } + + cond_resched(); + spin_lock_bh(&mlogbuf_lock); + } + + spin_unlock_bh(&mlogbuf_lock); + if (!error) + error = i; + out: + /* MLOG_PRINTK("[mlog] doread end %d\n", error); */ + return error; +} + + +static void mlog_timer_handler(unsigned long data) +{ + mlog(MLOG_TRIGGER_TIMER); + + mod_timer(&mlog_timer, round_jiffies(jiffies + timer_intval)); +} + +static void mlog_init_logger(void) +{ + spin_lock_init(&mlogbuf_lock); + mlog_reset_format(); + mlog_reset_buffer(); + + setup_timer(&mlog_timer, mlog_timer_handler, 0); + mlog_timer.expires = jiffies + timer_intval; + + add_timer(&mlog_timer); +} + +static void mlog_exit_logger(void) +{ + if (strfmt_list) { + kfree(strfmt_list); + strfmt_list = NULL; + } +} + +static int __init mlog_init(void) +{ + mlog_init_logger(); + mlog_init_procfs(); + return 0; +} + +static void __exit mlog_exit(void) +{ + mlog_exit_logger(); +} + +module_param(min_adj, int, S_IRUGO | S_IWUSR); +module_param(max_adj, int, S_IRUGO | S_IWUSR); +module_param(limit_pid, int, S_IRUGO | S_IWUSR); + +static int do_filter_handler(const char *val, const struct kernel_param *kp) +{ + const int ret = param_set_uint(val, kp); + mlog_reset_format(); + mlog_reset_buffer(); + return ret; +} + +static const struct kernel_param_ops param_ops_change_filter = { + .set = &do_filter_handler, + .get = ¶m_get_uint, + .free = NULL, +}; + +static int do_time_intval_handler(const char *val, const struct kernel_param *kp) +{ + const int ret = param_set_uint(val, kp); + mod_timer(&mlog_timer, jiffies + ret); + return ret; +} + +static const struct kernel_param_ops param_ops_change_time_intval = { + .set = &do_time_intval_handler, + .get = ¶m_get_uint, + .free = NULL, +}; + +param_check_uint(meminfo_filter, &meminfo_filter); +module_param_cb(meminfo_filter, ¶m_ops_change_filter, &meminfo_filter, S_IRUGO | S_IWUSR); +__MODULE_PARM_TYPE(meminfo_filter, uint); + +param_check_uint(vmstat_filter, &vmstat_filter); +module_param_cb(vmstat_filter, ¶m_ops_change_filter, &vmstat_filter, S_IRUGO | S_IWUSR); +__MODULE_PARM_TYPE(vmstat_filter, uint); + +param_check_uint(proc_filter, &proc_filter); +module_param_cb(proc_filter, ¶m_ops_change_filter, &proc_filter, S_IRUGO | S_IWUSR); +__MODULE_PARM_TYPE(proc_filter, uint); + +param_check_ulong(timer_intval, &timer_intval); +module_param_cb(timer_intval, ¶m_ops_change_time_intval, &timer_intval, S_IRUGO | S_IWUSR); +__MODULE_PARM_TYPE(timer_intval, ulong); + +static uint do_mlog; + +static int do_mlog_handler(const char *val, const struct kernel_param *kp) +{ + const int ret = param_set_uint(val, kp); + mlog(do_mlog); + /* MLOG_PRINTK("[mlog] do_mlog %d\n", do_mlog); */ + return ret; +} + +static const struct kernel_param_ops param_ops_do_mlog = { + .set = &do_mlog_handler, + .get = ¶m_get_uint, + .free = NULL, +}; + +param_check_uint(do_mlog, &do_mlog); +module_param_cb(do_mlog, ¶m_ops_do_mlog, &do_mlog, S_IRUGO | S_IWUSR); +__MODULE_PARM_TYPE(do_mlog, uint); + +module_init(mlog_init); +module_exit(mlog_exit); + +/* TODO module license & information */ + +MODULE_DESCRIPTION("MEDIATEK Memory Log Driver"); +MODULE_AUTHOR("Jimmy Su<jimmy.su@mediatek.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 433122a61..805d50bed 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -47,6 +47,10 @@ /* From page_alloc.c, for urgent allocations in preemptible situation */ extern void show_free_areas_minimum(void); +/*#ifdef CONFIG_ZRAM +extern void mlog(int type); +#endif*/ + static uint32_t lowmem_debug_level = 1; static short lowmem_adj[6] = { @@ -204,6 +208,11 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) min_score_adj, free); lowmem_deathpending_timeout = jiffies + HZ; + +/*#ifdef CONFIG_ZRAM + mlog(1); +#endif*/ + set_tsk_thread_flag(selected, TIF_MEMDIE); send_sig(SIGKILL, selected, 0); rem -= selected_tasksize; |
