diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 10b4be1f3e78e47e8809c4504fd51d8776700364..764e9d9c0830c152de4c78f1f56a3d8f6e40c7a1 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "ashmem.h" #define ASHMEM_NAME_PREFIX "dev/ashmem/" @@ -104,6 +105,16 @@ static struct kmem_cache *ashmem_range_cachep __read_mostly; */ static struct lock_class_key backing_shmem_inode_class; +void ashmem_mutex_lock(void) +{ + mutex_lock(&ashmem_mutex); +} + +void ashmem_mutex_unlock(void) +{ + mutex_unlock(&ashmem_mutex); +} + static inline unsigned long range_size(struct ashmem_range *range) { return range->pgend - range->pgstart + 1; @@ -913,12 +924,35 @@ static const struct file_operations ashmem_fops = { #endif }; +int is_ashmem_file(struct file *file) +{ + return file->f_op == &ashmem_fops; +} + static struct miscdevice ashmem_misc = { .minor = MISC_DYNAMIC_MINOR, .name = "ashmem", .fops = &ashmem_fops, }; +size_t get_ashmem_size_by_file(struct file *f) +{ + struct ashmem_area *asma = f->private_data; + + if (asma) + return asma->size; + return 0; +} + +char *get_ashmem_name_by_file(struct file *f) +{ + struct ashmem_area *asma = f->private_data; + + if (asma) + return asma->name; + return NULL; +} + static int __init ashmem_init(void) { int ret = -ENOMEM; @@ -950,7 +984,7 @@ static int __init ashmem_init(void) pr_err("failed to register shrinker!\n"); goto out_demisc; } - + init_ashmem_process_info(); pr_info("initialized\n"); return 0; diff --git a/drivers/staging/android/ashmem.h b/drivers/staging/android/ashmem.h index 1a478173cd21431b0c4b11ea85240efcb4b39653..601441d87f1f994a8c231070100b6519f292e794 100644 --- a/drivers/staging/android/ashmem.h +++ b/drivers/staging/android/ashmem.h @@ -21,4 +21,9 @@ #define COMPAT_ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned int) #endif +int is_ashmem_file(struct file *file); +size_t get_ashmem_size_by_file(struct file *f); +char *get_ashmem_name_by_file(struct file *f); +void ashmem_mutex_lock(void); +void ashmem_mutex_unlock(void); #endif /* _LINUX_ASHMEM_H */ diff --git a/include/linux/memcheck.h b/include/linux/memcheck.h new file mode 100644 index 0000000000000000000000000000000000000000..7f5fe3a854db0506804b60c6c09e73dd49e4d23d --- /dev/null +++ b/include/linux/memcheck.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * include/linux/memcheck.h + * + * Copyright (c) 2022 Huawei Technologies Co., Ltd. + */ +#ifndef _MEMCHECK_H +#define _MEMCHECK_H + +#ifdef CONFIG_MEMTRACE_ASHMEM +void init_ashmem_process_info(void); +#else +static inline void init_ashmem_process_info(void) {} +#endif + +#endif /* _MEMCHECK_H */ + diff --git a/mm/Kconfig b/mm/Kconfig index 68aaed4cdc9f564fb863bade741bbfd1f216c560..c35f9f8a0857050b4974e7d58b4e3169a4de37ca 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -938,5 +938,14 @@ config LMKD_DBG default n help print processes info when lmk happen per several seconds +# +# Show the process ashmem for debug +# +config MEMTRACE_ASHMEM + bool "Ashmem Process Info Show" + depends on ASHMEM + default n + help + Enable the Ashmem Process Info Show endmenu diff --git a/mm/Makefile b/mm/Makefile index 6b18976373687a56aef52f9bb434153869d44e5b..4c0ca82c4a64b8a088014094b7da85f62fbbb48f 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -66,6 +66,7 @@ ifdef CONFIG_MMU obj-$(CONFIG_ADVISE_SYSCALLS) += madvise.o endif +obj-$(CONFIG_MEMTRACE_ASHMEM) += memtrace_ashmem.o obj-$(CONFIG_LMKD_DBG) += lmkd_dbg_trigger.o obj-$(CONFIG_LOWMEM) += lowmem_dbg.o obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o swap_slots.o diff --git a/mm/memtrace_ashmem.c b/mm/memtrace_ashmem.c new file mode 100644 index 0000000000000000000000000000000000000000..9d61f32d4f7840f3a9ff93e750e0bac26a3d4acd --- /dev/null +++ b/mm/memtrace_ashmem.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mm/memtrace_ashmem.c + * + * Copyright (c) 2022 Huawei Technologies Co., Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include "../drivers/staging/android/ashmem.h" + +static int ashmem_debug_process_info_open(struct inode *inode, + struct file *file); + +struct ashmem_debug_process_info_args { + struct seq_file *seq; + struct task_struct *tsk; +}; + +static const struct proc_ops debug_process_ashmem_info_fops = { + .proc_open = ashmem_debug_process_info_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int ashmem_debug_process_info_cb(const void *data, + struct file *f, unsigned int fd) +{ + const struct ashmem_debug_process_info_args *args = data; + struct task_struct *tsk = args->tsk; + + if (!is_ashmem_file(f)) + return 0; + seq_printf(args->seq, + "%s %u %u %s %zu\n", + tsk->comm, tsk->pid, fd, + get_ashmem_name_by_file(f), + get_ashmem_size_by_file(f)); + return 0; +} + +static int ashmem_debug_process_info_show(struct seq_file *s, void *d) +{ + struct task_struct *tsk = NULL; + struct ashmem_debug_process_info_args cb_args; + + seq_puts(s, "Process ashmem detail info:\n"); + seq_puts(s, "----------------------------------------------------\n"); + seq_printf(s, "%s %s %s %s %s\n", + "Process name", "Process ID", + "fd", "ashmem_name", "size"); + + ashmem_mutex_lock(); + rcu_read_lock(); + for_each_process(tsk) { + if (tsk->flags & PF_KTHREAD) + continue; + cb_args.seq = s; + cb_args.tsk = tsk; + + task_lock(tsk); + iterate_fd(tsk->files, 0, + ashmem_debug_process_info_cb, (void *)&cb_args); + task_unlock(tsk); + } + rcu_read_unlock(); + ashmem_mutex_unlock(); + seq_puts(s, "----------------------------------------------------\n"); + return 0; +} + +static int ashmem_debug_process_info_open(struct inode *inode, + struct file *file) +{ + return single_open(file, ashmem_debug_process_info_show, + inode->i_private); +} + +void init_ashmem_process_info(void) +{ + struct proc_dir_entry *entry = NULL; + + entry = proc_create_data("ashmem_process_info", 0444, + NULL, &debug_process_ashmem_info_fops, NULL); + if (!entry) + pr_err("Failed to create ashmem debug info\n"); +} +