From 339496262c89789ad62c42f808db9d1d05488f5a Mon Sep 17 00:00:00 2001 From: lijiawei Date: Mon, 25 Apr 2022 13:23:57 +0800 Subject: [PATCH] dmabuf: add dmabuf process info for debug ohos inclusion category:feature issue: #I54AWN CVE: NA ------------------------------- add node to show dmabuf objects usage of all processes. Signed-off-by: lijiawei --- drivers/dma-buf/Kconfig | 13 ++ drivers/dma-buf/Makefile | 2 + drivers/dma-buf/dma-buf-process-info.c | 165 +++++++++++++++++++++++++ drivers/dma-buf/dma-buf-process-info.h | 83 +++++++++++++ drivers/dma-buf/dma-buf.c | 31 ++++- include/linux/dma-buf.h | 18 +++ 6 files changed, 308 insertions(+), 4 deletions(-) create mode 100644 drivers/dma-buf/dma-buf-process-info.c create mode 100644 drivers/dma-buf/dma-buf-process-info.h diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig index 3280ca972502..594b77d8923c 100644 --- a/drivers/dma-buf/Kconfig +++ b/drivers/dma-buf/Kconfig @@ -56,6 +56,19 @@ config DMABUF_SELFTESTS default n depends on DMA_SHARED_BUFFER +config DMABUF_PROCESS_INFO + bool "Show dmabuf usage of all processes" + default n + depends on DMA_SHARED_BUFFER + depends on PROC_FS || DEBUG_FS + help + Choose this option to show dmabuf objects usage of all processes. + Firstly, with this option, when a process creates a dmabuf object, + its pid and task_comm will be recorded in the dmabuf. + Secondly, this option creates dma_buf/process_bufinfo file in + debugfs (if DEBUG_FS enabled) and process_dmabuf_info file in procfs + (if PROC_FS enabled) to show dmabuf objects usage of all processes. + menuconfig DMABUF_HEAPS bool "DMA-BUF Userland Memory Heaps" select DMA_SHARED_BUFFER diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index 40d81f23cacf..cfbc5e3da600 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -14,3 +14,5 @@ dmabuf_selftests-y := \ st-dma-fence-chain.o obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o + +obj-$(CONFIG_DMABUF_PROCESS_INFO) += dma-buf-process-info.o diff --git a/drivers/dma-buf/dma-buf-process-info.c b/drivers/dma-buf/dma-buf-process-info.c new file mode 100644 index 000000000000..ff528d0ca758 --- /dev/null +++ b/drivers/dma-buf/dma-buf-process-info.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DMA-BUF: dmabuf usage of all processes statistics. + * + * Copyright (c) 2022 Huawei Device Co., Ltd. + */ + +#include +#include +#include +#include +#include + +#include "dma-buf-process-info.h" + +static struct proc_dir_entry *proc_dmabuf_entry; + +struct dmabuf_task_info_args { + struct seq_file *seq; + struct task_struct *tsk; + size_t tsk_dmabuf_bytes; +}; + +void init_dma_buf_task_info(struct dma_buf *buf) +{ + struct task_struct *tsk = NULL; + + if (IS_ERR_OR_NULL(buf)) + return; + + get_task_struct(current->group_leader); + task_lock(current->group_leader); + tsk = current->group_leader; + buf->exp_pid = task_pid_nr(tsk); + if (tsk->flags & PF_KTHREAD) + tsk = NULL; + task_unlock(current->group_leader); + put_task_struct(current->group_leader); + + if (tsk) + get_task_comm(buf->exp_task_comm, tsk); + else /* kernel task */ + strncpy(buf->exp_task_comm, "[kernel task]", + sizeof(buf->exp_task_comm)); +} + +pid_t dma_buf_exp_pid(const struct dma_buf *buf) +{ + if (IS_ERR_OR_NULL(buf)) + return 0; + + return buf->exp_pid; +} + +const char *dma_buf_exp_task_comm(const struct dma_buf *buf) +{ + if (IS_ERR_OR_NULL(buf)) + return NULL; + + return buf->exp_task_comm; +} + +static int dma_buf_single_file_show(const void *data, struct file *f, + unsigned int fd) +{ + struct dmabuf_task_info_args *tsk_info = NULL; + struct task_struct *tsk = NULL; + struct dma_buf *buf = NULL; + + tsk_info = (struct dmabuf_task_info_args *)data; + if (IS_ERR_OR_NULL(tsk_info) || IS_ERR_OR_NULL(tsk_info->seq)) + return 0; + + tsk = tsk_info->tsk; + buf = get_dma_buf_from_file(f); + if (IS_ERR_OR_NULL(tsk) || IS_ERR_OR_NULL(buf)) + return 0; + + tsk_info->tsk_dmabuf_bytes += buf->size; + + spin_lock(&buf->name_lock); + seq_printf(tsk_info->seq, + "%-16s %-16d %-16u %-16zu %-16lu %-16d %-16s %s \t %s\n", + tsk->comm, + tsk->pid, + fd, + buf->size, + file_inode(buf->file)->i_ino, + buf->exp_pid, + buf->exp_task_comm, + buf->name ?: "NULL", + buf->exp_name ?: "NULL"); + spin_unlock(&buf->name_lock); + + return 0; +} + +static int dma_buf_process_info_show(struct seq_file *s, void *unused) +{ + struct dmabuf_task_info_args task_info = { NULL, NULL, 0 }; + struct task_struct *tsk = NULL; + + seq_puts(s, "Dma-buf objects usage of processes:\n"); + seq_printf(s, "%-16s %-16s %-16s %-16s %-16s %-16s %-16s %s \t %s\n", + "Process", "pid", "fd", "size_bytes", "ino", "exp_pid", + "exp_task_comm", "buf_name", "exp_name"); + + task_info.seq = s; + + rcu_read_lock(); + for_each_process(tsk) { + task_info.tsk = tsk; + task_info.tsk_dmabuf_bytes = 0; + + task_lock(tsk); + iterate_fd(tsk->files, 0, dma_buf_single_file_show, + (void *)&task_info); + if (task_info.tsk_dmabuf_bytes) + seq_printf(s, "Total dmabuf size of %s: %zu bytes\n", + tsk->comm, task_info.tsk_dmabuf_bytes); + task_unlock(tsk); + } + rcu_read_unlock(); + + return 0; +} + +void dma_buf_process_info_init_procfs(void) +{ + proc_dmabuf_entry = proc_create_single("process_dmabuf_info", 0444, + NULL, + dma_buf_process_info_show); + if (!proc_dmabuf_entry) + pr_err("%s: create node /proc/process_dmabuf_info failed\n", + __func__); +} + +void dma_buf_process_info_uninit_procfs(void) +{ + if (!proc_dmabuf_entry) + return; + + proc_remove(proc_dmabuf_entry); +} + +DEFINE_SHOW_ATTRIBUTE(dma_buf_process_info); + +int dma_buf_process_info_init_debugfs(struct dentry *parent) +{ + struct dentry *debugfs_file = NULL; + int err = 0; + + if (IS_ERR_OR_NULL(parent)) + return -EINVAL; + + debugfs_file = debugfs_create_file("process_bufinfo", 0444, + parent, NULL, + &dma_buf_process_info_fops); + if (IS_ERR(debugfs_file)) { + pr_err("dma_buf: debugfs: create process_bufinfo failed\n"); + err = PTR_ERR(debugfs_file); + } + + return err; +} diff --git a/drivers/dma-buf/dma-buf-process-info.h b/drivers/dma-buf/dma-buf-process-info.h new file mode 100644 index 000000000000..1275c1c7e2aa --- /dev/null +++ b/drivers/dma-buf/dma-buf-process-info.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * DMA-BUF: dmabuf usage of all processes statistics. + * + * Copyright (c) 2022 Huawei Device Co., Ltd. + */ + +#ifndef __DMA_BUF_PROCESS_INFO_H +#define __DMA_BUF_PROCESS_INFO_H + +#ifdef CONFIG_DMABUF_PROCESS_INFO +/** + * init_dma_buf_task_info - init exp_pid and exp_task_comm of dma_buf + * @buf: [in] pointer to struct dma_buf. If @buf IS_ERR_OR_NULL, + * return with doing nothing. + */ +void init_dma_buf_task_info(struct dma_buf *buf); + +/** + * dma_buf_exp_pid - return exp_pid of @buf + * @buf: [in] pointer to struct dma_buf + * + * Return 0 if @buf IS_ERR_OR_NULL, else return buf->exp_pid + */ +pid_t dma_buf_exp_pid(const struct dma_buf *buf); + +/** + * dma_buf_exp_task_comm - return exp_task_comm of @buf + * @buf: [in] pointer to struct dma_buf + * + * Return NULL if @buf IS_ERR_OR_NULL, else return buf->exp_task_comm + */ +const char *dma_buf_exp_task_comm(const struct dma_buf *buf); + +/** + * dma_buf_process_info_init_procfs - module init: create node in procfs + */ +void dma_buf_process_info_init_procfs(void); + +/** + * dma_buf_process_info_uninit_procfs - module exit: remove node in procfs + */ +void dma_buf_process_info_uninit_procfs(void); + +/** + * dma_buf_process_info_init_debugfs - create debug node under @parent + * in debugfs. + * @parent: [in] pointer to struct dentry. If @parent IS_ERR_OR_NULL, + * return -EINVAL + * + * Return 0 if success, otherwise return errno. + * + * Note that there is no related uninit function, since the debug node will + * be removed in dma_buf_uninit_debugfs() when dma_buf_deinit() called. + */ +int dma_buf_process_info_init_debugfs(struct dentry *parent); + +#else /* CONFIG_DMABUF_PROCESS_INFO */ + +static inline void init_dma_buf_task_info(struct dma_buf *buf) {} + +static inline pid_t dma_buf_exp_pid(const struct dma_buf *buf) +{ + return 0; +} + +static inline const char *dma_buf_exp_task_comm(const struct dma_buf *buf) +{ + return NULL; +} + +static inline void dma_buf_process_info_init_procfs(void) {} + +static inline void dma_buf_process_info_uninit_procfs(void) {} + +static inline int +dma_buf_process_info_init_debugfs(struct dentry *parent) +{ + return 0; +} +#endif /* CONFIG_DMABUF_PROCESS_INFO */ +#endif /* __DMA_BUF_PROCESS_INFO_H */ + diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index f55396de2fcc..b6ae42d5971e 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -30,6 +30,7 @@ #include #include "dma-buf-sysfs-stats.h" +#include "dma-buf-process-info.h" static inline int is_dma_buf_file(struct file *); @@ -593,6 +594,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) list_add(&dmabuf->list_node, &db_list.head); mutex_unlock(&db_list.lock); + init_dma_buf_task_info(dmabuf); return dmabuf; err_sysfs: @@ -1302,8 +1304,10 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) return ret; seq_puts(s, "\nDma-buf Objects:\n"); - seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\t%-8s\n", - "size", "flags", "mode", "count", "ino"); + seq_printf(s, "%-8s\t%-8s\t%-8s\t%-8s\texp_name\t%-8s\t" + "%-16s\t%-16s\t%-16s\n", + "size", "flags", "mode", "count", "ino", + "buf_name", "exp_pid", "exp_task_comm"); list_for_each_entry(buf_obj, &db_list.head, list_node) { @@ -1311,13 +1315,16 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused) if (ret) goto error_unlock; - seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\t%08lu\t%s\n", + seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\t%08lu\t%s\t" + "%-16d\t%-16s\n", buf_obj->size, buf_obj->file->f_flags, buf_obj->file->f_mode, file_count(buf_obj->file), buf_obj->exp_name, file_inode(buf_obj->file)->i_ino, - buf_obj->name ?: ""); + buf_obj->name ?: "NULL", + dma_buf_exp_pid(buf_obj), + dma_buf_exp_task_comm(buf_obj) ?: "NULL"); robj = buf_obj->resv; while (true) { @@ -1398,6 +1405,7 @@ static int dma_buf_init_debugfs(void) err = PTR_ERR(d); } + dma_buf_process_info_init_debugfs(dma_buf_debugfs_dir); return err; } @@ -1415,6 +1423,19 @@ static inline void dma_buf_uninit_debugfs(void) } #endif +#ifdef CONFIG_DMABUF_PROCESS_INFO +struct dma_buf *get_dma_buf_from_file(struct file *f) +{ + if (IS_ERR_OR_NULL(f)) + return NULL; + + if (!is_dma_buf_file(f)) + return NULL; + + return f->private_data; +} +#endif /* CONFIG_DMABUF_PROCESS_INFO */ + static int __init dma_buf_init(void) { int ret; @@ -1430,6 +1451,7 @@ static int __init dma_buf_init(void) mutex_init(&db_list.lock); INIT_LIST_HEAD(&db_list.head); dma_buf_init_debugfs(); + dma_buf_process_info_init_procfs(); return 0; } subsys_initcall(dma_buf_init); @@ -1439,5 +1461,6 @@ static void __exit dma_buf_deinit(void) dma_buf_uninit_debugfs(); kern_unmount(dma_buf_mnt); dma_buf_uninit_sysfs_statistics(); + dma_buf_process_info_uninit_procfs(); } __exitcall(dma_buf_deinit); diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index e79fa6751fe0..0c5706abb7fe 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -289,6 +289,8 @@ struct dma_buf_ops { * @list_node: node for dma_buf accounting and debugging. * @priv: exporter specific private data for this buffer object. * @resv: reservation object linked to this dma-buf + * @exp_pid: pid of exporter task which created this obj + * @exp_task_comm: process name of exporter task which created this obj * @poll: for userspace poll support * @cb_excl: for userspace poll support * @cb_shared: for userspace poll support @@ -320,6 +322,10 @@ struct dma_buf { struct list_head list_node; void *priv; struct dma_resv *resv; +#ifdef CONFIG_DMABUF_PROCESS_INFO + pid_t exp_pid; + char exp_task_comm[TASK_COMM_LEN]; +#endif /* poll support */ wait_queue_head_t poll; @@ -514,4 +520,16 @@ int dma_buf_mmap(struct dma_buf *, struct vm_area_struct *, unsigned long); void *dma_buf_vmap(struct dma_buf *); void dma_buf_vunmap(struct dma_buf *, void *vaddr); + +#ifdef CONFIG_DMABUF_PROCESS_INFO +/** + * get_dma_buf_from_file - Get struct dma_buf* from struct file* + * @f: [in] pointer to struct file, which is associated with a + * dma_buf object. + * + * If @f IS_ERR_OR_NULL, return NULL. + * If @f is not a file associated with dma_buf, return NULL. + */ +struct dma_buf *get_dma_buf_from_file(struct file *f); +#endif /* CONFIG_DMABUF_PROCESS_INFO */ #endif /* __DMA_BUF_H__ */ -- Gitee