Path: blob/master/drivers/dma-buf/dma-buf-sysfs-stats.c
26278 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* DMA-BUF sysfs statistics.3*4* Copyright (C) 2021 Google LLC.5*/67#include <linux/dma-buf.h>8#include <linux/dma-resv.h>9#include <linux/kobject.h>10#include <linux/printk.h>11#include <linux/slab.h>12#include <linux/sysfs.h>1314#include "dma-buf-sysfs-stats.h"1516#define to_dma_buf_entry_from_kobj(x) container_of(x, struct dma_buf_sysfs_entry, kobj)1718/**19* DOC: overview20*21* ``/sys/kernel/debug/dma_buf/bufinfo`` provides an overview of every DMA-BUF22* in the system. However, since debugfs is not safe to be mounted in23* production, procfs and sysfs can be used to gather DMA-BUF statistics on24* production systems.25*26* The ``/proc/<pid>/fdinfo/<fd>`` files in procfs can be used to gather27* information about DMA-BUF fds. Detailed documentation about the interface28* is present in Documentation/filesystems/proc.rst.29*30* Unfortunately, the existing procfs interfaces can only provide information31* about the DMA-BUFs for which processes hold fds or have the buffers mmapped32* into their address space. This necessitated the creation of the DMA-BUF sysfs33* statistics interface to provide per-buffer information on production systems.34*35* The interface at ``/sys/kernel/dmabuf/buffers`` exposes information about36* every DMA-BUF when ``CONFIG_DMABUF_SYSFS_STATS`` is enabled.37*38* The following stats are exposed by the interface:39*40* * ``/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name``41* * ``/sys/kernel/dmabuf/buffers/<inode_number>/size``42*43* The information in the interface can also be used to derive per-exporter44* statistics. The data from the interface can be gathered on error conditions45* or other important events to provide a snapshot of DMA-BUF usage.46* It can also be collected periodically by telemetry to monitor various metrics.47*48* Detailed documentation about the interface is present in49* Documentation/ABI/testing/sysfs-kernel-dmabuf-buffers.50*/5152struct dma_buf_stats_attribute {53struct attribute attr;54ssize_t (*show)(struct dma_buf *dmabuf,55struct dma_buf_stats_attribute *attr, char *buf);56};57#define to_dma_buf_stats_attr(x) container_of(x, struct dma_buf_stats_attribute, attr)5859static ssize_t dma_buf_stats_attribute_show(struct kobject *kobj,60struct attribute *attr,61char *buf)62{63struct dma_buf_stats_attribute *attribute;64struct dma_buf_sysfs_entry *sysfs_entry;65struct dma_buf *dmabuf;6667attribute = to_dma_buf_stats_attr(attr);68sysfs_entry = to_dma_buf_entry_from_kobj(kobj);69dmabuf = sysfs_entry->dmabuf;7071if (!dmabuf || !attribute->show)72return -EIO;7374return attribute->show(dmabuf, attribute, buf);75}7677static const struct sysfs_ops dma_buf_stats_sysfs_ops = {78.show = dma_buf_stats_attribute_show,79};8081static ssize_t exporter_name_show(struct dma_buf *dmabuf,82struct dma_buf_stats_attribute *attr,83char *buf)84{85return sysfs_emit(buf, "%s\n", dmabuf->exp_name);86}8788static ssize_t size_show(struct dma_buf *dmabuf,89struct dma_buf_stats_attribute *attr,90char *buf)91{92return sysfs_emit(buf, "%zu\n", dmabuf->size);93}9495static struct dma_buf_stats_attribute exporter_name_attribute =96__ATTR_RO(exporter_name);97static struct dma_buf_stats_attribute size_attribute = __ATTR_RO(size);9899static struct attribute *dma_buf_stats_default_attrs[] = {100&exporter_name_attribute.attr,101&size_attribute.attr,102NULL,103};104ATTRIBUTE_GROUPS(dma_buf_stats_default);105106static void dma_buf_sysfs_release(struct kobject *kobj)107{108struct dma_buf_sysfs_entry *sysfs_entry;109110sysfs_entry = to_dma_buf_entry_from_kobj(kobj);111kfree(sysfs_entry);112}113114static const struct kobj_type dma_buf_ktype = {115.sysfs_ops = &dma_buf_stats_sysfs_ops,116.release = dma_buf_sysfs_release,117.default_groups = dma_buf_stats_default_groups,118};119120void dma_buf_stats_teardown(struct dma_buf *dmabuf)121{122struct dma_buf_sysfs_entry *sysfs_entry;123124sysfs_entry = dmabuf->sysfs_entry;125if (!sysfs_entry)126return;127128kobject_del(&sysfs_entry->kobj);129kobject_put(&sysfs_entry->kobj);130}131132133/* Statistics files do not need to send uevents. */134static int dmabuf_sysfs_uevent_filter(const struct kobject *kobj)135{136return 0;137}138139static const struct kset_uevent_ops dmabuf_sysfs_no_uevent_ops = {140.filter = dmabuf_sysfs_uevent_filter,141};142143static struct kset *dma_buf_stats_kset;144static struct kset *dma_buf_per_buffer_stats_kset;145int dma_buf_init_sysfs_statistics(void)146{147dma_buf_stats_kset = kset_create_and_add("dmabuf",148&dmabuf_sysfs_no_uevent_ops,149kernel_kobj);150if (!dma_buf_stats_kset)151return -ENOMEM;152153dma_buf_per_buffer_stats_kset = kset_create_and_add("buffers",154&dmabuf_sysfs_no_uevent_ops,155&dma_buf_stats_kset->kobj);156if (!dma_buf_per_buffer_stats_kset) {157kset_unregister(dma_buf_stats_kset);158return -ENOMEM;159}160161return 0;162}163164void dma_buf_uninit_sysfs_statistics(void)165{166kset_unregister(dma_buf_per_buffer_stats_kset);167kset_unregister(dma_buf_stats_kset);168}169170int dma_buf_stats_setup(struct dma_buf *dmabuf, struct file *file)171{172struct dma_buf_sysfs_entry *sysfs_entry;173int ret;174175if (!dmabuf->exp_name) {176pr_err("exporter name must not be empty if stats needed\n");177return -EINVAL;178}179180sysfs_entry = kzalloc(sizeof(struct dma_buf_sysfs_entry), GFP_KERNEL);181if (!sysfs_entry)182return -ENOMEM;183184sysfs_entry->kobj.kset = dma_buf_per_buffer_stats_kset;185sysfs_entry->dmabuf = dmabuf;186187dmabuf->sysfs_entry = sysfs_entry;188189/* create the directory for buffer stats */190ret = kobject_init_and_add(&sysfs_entry->kobj, &dma_buf_ktype, NULL,191"%lu", file_inode(file)->i_ino);192if (ret)193goto err_sysfs_dmabuf;194195return 0;196197err_sysfs_dmabuf:198kobject_put(&sysfs_entry->kobj);199dmabuf->sysfs_entry = NULL;200return ret;201}202203204