diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 7c9ac163d115..cb91dadeb465 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -115,6 +115,9 @@ static void dma_buf_release(struct dentry *dentry) if (dmabuf->resv == (struct dma_resv *)&dmabuf[1]) dma_resv_fini(dmabuf->resv); + if (atomic64_read(&dmabuf->num_unique_refs)) + pr_err("destroying dmabuf with non-zero task refs\n"); + WARN_ON(!list_empty(&dmabuf->attachments)); module_put(dmabuf->owner); kfree(dmabuf->name); @@ -199,6 +202,8 @@ static int new_task_dmabuf_record(struct task_struct *task, struct dma_buf *dmab rec->refcnt = 1; list_add(&rec->node, &task->dmabuf_info->dmabufs); + atomic64_inc(&dmabuf->num_unique_refs); + return 0; } @@ -276,6 +281,7 @@ void dma_buf_unaccount_task(struct dma_buf *dmabuf, struct task_struct *task) list_del(&rec->node); kfree(rec); task->dmabuf_info->rss -= dmabuf->size; + atomic64_dec(&dmabuf->num_unique_refs); } err: spin_unlock(&task->dmabuf_info->lock); @@ -851,6 +857,8 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) dmabuf->resv = resv; } + atomic64_set(&dmabuf->num_unique_refs, 0); + file->private_data = dmabuf; file->f_path.dentry->d_fsdata = dmabuf; dmabuf->file = file; diff --git a/fs/proc/base.c b/fs/proc/base.c index 6b91ddcab7e2..2eee67e06ffe 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3397,6 +3397,39 @@ static const struct file_operations proc_dmabuf_rss_hwm_operations = { .llseek = seq_lseek, .release = single_release, }; + +static int proc_dmabuf_pss_show(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *task) +{ + struct task_dma_buf_record *rec; + u64 pss = 0; + + if (!task->dmabuf_info) { + pr_err("%s dmabuf accounting record was not allocated\n", __func__); + return -ENOMEM; + } + + if (!(task->flags & PF_KTHREAD)) { + spin_lock(&task->dmabuf_info->lock); + list_for_each_entry(rec, &task->dmabuf_info->dmabufs, node) { + s64 refs = atomic64_read(&rec->dmabuf->num_unique_refs); + + if (refs <= 0) { + pr_err("dmabuf has <= refs %lld\n", refs); + continue; + } + + pss += rec->dmabuf->size / (size_t)refs; + } + spin_unlock(&task->dmabuf_info->lock); + + seq_printf(m, "%llu\n", pss); + } else { + seq_puts(m, "0\n"); + } + + return 0; +} #endif /* @@ -3525,6 +3558,7 @@ static const struct pid_entry tgid_base_stuff[] = { #ifdef CONFIG_DMA_SHARED_BUFFER ONE("dmabuf_rss", S_IRUGO, proc_dmabuf_rss_show), REG("dmabuf_rss_hwm", S_IRUGO|S_IWUSR, proc_dmabuf_rss_hwm_operations), + ONE("dmabuf_pss", S_IRUGO, proc_dmabuf_pss_show), #endif }; diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index a362c8ba7a21..267bf322272f 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -25,6 +25,7 @@ #include #include #ifndef __GENKSYMS__ +#include #include #endif @@ -534,6 +535,13 @@ struct dma_buf { } *sysfs_entry; #endif + /** + * @num_unique_refs: + * + * The number of tasks that reference this buffer. For calculating PSS. + */ + atomic64_t num_unique_refs; + ANDROID_KABI_RESERVE(1); ANDROID_KABI_RESERVE(2); };