From 9132fbe545925a36b45c0738d1f9aa5cecb86050 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Fri, 8 Jan 2021 12:10:08 -0800 Subject: [PATCH] ANDROID: dmabuf: Add mmap_count to struct dmabuf mmap_count can be used to efficiently calculate the PSS for any DMA buffer that the process has mapped. Bug: 167141117 Change-Id: I8296981f0135a5532969aca3a8baa5da61dfe39f Signed-off-by: Kalesh Singh --- .../ABI/testing/sysfs-kernel-dmabuf-buffers | 7 +++ drivers/dma-buf/dma-buf-sysfs-stats.c | 10 ++++ drivers/dma-buf/dma-buf.c | 50 ++++++++++++++++++- include/linux/dma-buf.h | 6 +++ 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-kernel-dmabuf-buffers b/Documentation/ABI/testing/sysfs-kernel-dmabuf-buffers index 6f7c65209f07..721d486a186b 100644 --- a/Documentation/ABI/testing/sysfs-kernel-dmabuf-buffers +++ b/Documentation/ABI/testing/sysfs-kernel-dmabuf-buffers @@ -50,3 +50,10 @@ KernelVersion: v5.12 Contact: Hridya Valsaraju Description: This file is read-only and contains a map_counter indicating the number of distinct device mappings of the attachment. + +What: /sys/kernel/dmabuf/buffers//mmap_count +Date: January 2021 +KernelVersion: v5.10 +Contact: Kalesh Singh +Description: This file is read-only and contains a counter indicating the + number of times the buffer has been mmap(). diff --git a/drivers/dma-buf/dma-buf-sysfs-stats.c b/drivers/dma-buf/dma-buf-sysfs-stats.c index 5dc2e17f3054..d1845a344cfc 100644 --- a/drivers/dma-buf/dma-buf-sysfs-stats.c +++ b/drivers/dma-buf/dma-buf-sysfs-stats.c @@ -52,6 +52,13 @@ static ssize_t exporter_name_show(struct dma_buf *dmabuf, return sysfs_emit(buf, "%s\n", dmabuf->exp_name); } +static ssize_t mmap_count_show(struct dma_buf *dmabuf, + struct dma_buf_stats_attribute *attr, + char *buf) +{ + return sysfs_emit(buf, "%d\n", dmabuf->mmap_count); +} + static ssize_t size_show(struct dma_buf *dmabuf, struct dma_buf_stats_attribute *attr, char *buf) @@ -62,10 +69,13 @@ static ssize_t size_show(struct dma_buf *dmabuf, static struct dma_buf_stats_attribute exporter_name_attribute = __ATTR_RO(exporter_name); static struct dma_buf_stats_attribute size_attribute = __ATTR_RO(size); +static struct dma_buf_stats_attribute mmap_count_attribute = + __ATTR_RO(mmap_count); static struct attribute *dma_buf_stats_default_attrs[] = { &exporter_name_attribute.attr, &size_attribute.attr, + &mmap_count_attribute.attr, NULL, }; ATTRIBUTE_GROUPS(dma_buf_stats_default); diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index e07851f8081b..3e8a616edc0b 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -127,6 +127,54 @@ static struct file_system_type dma_buf_fs_type = { .kill_sb = kill_anon_super, }; +#ifdef CONFIG_DMABUF_SYSFS_STATS +static void dma_buf_vma_open(struct vm_area_struct *vma) +{ + struct dma_buf *dmabuf = vma->vm_file->private_data; + + dmabuf->mmap_count++; + /* call the heap provided vma open() op */ + if (dmabuf->exp_vm_ops->open) + dmabuf->exp_vm_ops->open(vma); +} + +static void dma_buf_vma_close(struct vm_area_struct *vma) +{ + struct dma_buf *dmabuf = vma->vm_file->private_data; + + if (dmabuf->mmap_count) + dmabuf->mmap_count--; + /* call the heap provided vma close() op */ + if (dmabuf->exp_vm_ops->close) + dmabuf->exp_vm_ops->close(vma); +} + +static int dma_buf_do_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) +{ + /* call this first because the exporter might override vma->vm_ops */ + int ret = dmabuf->ops->mmap(dmabuf, vma); + + if (ret) + return ret; + + /* save the exporter provided vm_ops */ + dmabuf->exp_vm_ops = vma->vm_ops; + dmabuf->vm_ops = *(dmabuf->exp_vm_ops); + /* override open() and close() to provide buffer mmap count */ + dmabuf->vm_ops.open = dma_buf_vma_open; + dmabuf->vm_ops.close = dma_buf_vma_close; + vma->vm_ops = &dmabuf->vm_ops; + dmabuf->mmap_count++; + + return ret; +} +#else /* CONFIG_DMABUF_SYSFS_STATS */ +static int dma_buf_do_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) +{ + return dmabuf->ops->mmap(dmabuf, vma); +} +#endif /* CONFIG_DMABUF_SYSFS_STATS */ + static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma) { struct dma_buf *dmabuf; @@ -145,7 +193,7 @@ static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma) dmabuf->size >> PAGE_SHIFT) return -EINVAL; - return dmabuf->ops->mmap(dmabuf, vma); + return dma_buf_do_mmap(dmabuf, vma); } static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence) diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index d05f233f574e..c91d6a24c40a 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -381,6 +381,9 @@ struct dma_buf_ops { * @sysfs_entry: for exposing information about this buffer in sysfs. * The attachment_uid member of @sysfs_entry is protected by dma_resv lock * and is incremented on each attach. + * @mmap_count: number of times buffer has been mmapped. + * @exp_vm_ops: the vm ops provided by the buffer exporter. + * @vm_ops: the overridden vm_ops used to track mmap_count of the buffer. * * This represents a shared buffer, created by calling dma_buf_export(). The * userspace representation is a normal file descriptor, which can be created by @@ -424,6 +427,9 @@ struct dma_buf { unsigned int attachment_uid; struct kset *attach_stats_kset; } *sysfs_entry; + int mmap_count; + const struct vm_operations_struct *exp_vm_ops; + struct vm_operations_struct vm_ops; #endif };