1 // SPDX-License-Identifier: GPL-2.0-only
3 * DMA-BUF sysfs statistics.
5 * Copyright (C) 2021 Google LLC.
8 #include <linux/dma-buf.h>
9 #include <linux/dma-resv.h>
10 #include <linux/kobject.h>
11 #include <linux/printk.h>
12 #include <linux/slab.h>
13 #include <linux/sysfs.h>
15 #include "dma-buf-sysfs-stats.h"
17 #define to_dma_buf_entry_from_kobj(x) container_of(x, struct dma_buf_sysfs_entry, kobj)
22 * ``/sys/kernel/debug/dma_buf/bufinfo`` provides an overview of every DMA-BUF
23 * in the system. However, since debugfs is not safe to be mounted in
24 * production, procfs and sysfs can be used to gather DMA-BUF statistics on
27 * The ``/proc/<pid>/fdinfo/<fd>`` files in procfs can be used to gather
28 * information about DMA-BUF fds. Detailed documentation about the interface
29 * is present in Documentation/filesystems/proc.rst.
31 * Unfortunately, the existing procfs interfaces can only provide information
32 * about the DMA-BUFs for which processes hold fds or have the buffers mmapped
33 * into their address space. This necessitated the creation of the DMA-BUF sysfs
34 * statistics interface to provide per-buffer information on production systems.
36 * The interface at ``/sys/kernel/dma-buf/buffers`` exposes information about
37 * every DMA-BUF when ``CONFIG_DMABUF_SYSFS_STATS`` is enabled.
39 * The following stats are exposed by the interface:
41 * * ``/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name``
42 * * ``/sys/kernel/dmabuf/buffers/<inode_number>/size``
43 * * ``/sys/kernel/dmabuf/buffers/<inode_number>/attachments/<attach_uid>/device``
44 * * ``/sys/kernel/dmabuf/buffers/<inode_number>/attachments/<attach_uid>/map_counter``
46 * The information in the interface can also be used to derive per-exporter and
47 * per-device usage statistics. The data from the interface can be gathered
48 * on error conditions or other important events to provide a snapshot of
49 * DMA-BUF usage. It can also be collected periodically by telemetry to monitor
52 * Detailed documentation about the interface is present in
53 * Documentation/ABI/testing/sysfs-kernel-dmabuf-buffers.
56 struct dma_buf_stats_attribute {
57 struct attribute attr;
58 ssize_t (*show)(struct dma_buf *dmabuf,
59 struct dma_buf_stats_attribute *attr, char *buf);
61 #define to_dma_buf_stats_attr(x) container_of(x, struct dma_buf_stats_attribute, attr)
63 static ssize_t dma_buf_stats_attribute_show(struct kobject *kobj,
64 struct attribute *attr,
67 struct dma_buf_stats_attribute *attribute;
68 struct dma_buf_sysfs_entry *sysfs_entry;
69 struct dma_buf *dmabuf;
71 attribute = to_dma_buf_stats_attr(attr);
72 sysfs_entry = to_dma_buf_entry_from_kobj(kobj);
73 dmabuf = sysfs_entry->dmabuf;
75 if (!dmabuf || !attribute->show)
78 return attribute->show(dmabuf, attribute, buf);
81 static const struct sysfs_ops dma_buf_stats_sysfs_ops = {
82 .show = dma_buf_stats_attribute_show,
85 static ssize_t exporter_name_show(struct dma_buf *dmabuf,
86 struct dma_buf_stats_attribute *attr,
89 return sysfs_emit(buf, "%s\n", dmabuf->exp_name);
92 static ssize_t size_show(struct dma_buf *dmabuf,
93 struct dma_buf_stats_attribute *attr,
96 return sysfs_emit(buf, "%zu\n", dmabuf->size);
99 static struct dma_buf_stats_attribute exporter_name_attribute =
100 __ATTR_RO(exporter_name);
101 static struct dma_buf_stats_attribute size_attribute = __ATTR_RO(size);
103 static struct attribute *dma_buf_stats_default_attrs[] = {
104 &exporter_name_attribute.attr,
105 &size_attribute.attr,
108 ATTRIBUTE_GROUPS(dma_buf_stats_default);
110 static void dma_buf_sysfs_release(struct kobject *kobj)
112 struct dma_buf_sysfs_entry *sysfs_entry;
114 sysfs_entry = to_dma_buf_entry_from_kobj(kobj);
118 static struct kobj_type dma_buf_ktype = {
119 .sysfs_ops = &dma_buf_stats_sysfs_ops,
120 .release = dma_buf_sysfs_release,
121 .default_groups = dma_buf_stats_default_groups,
124 #define to_dma_buf_attach_entry_from_kobj(x) container_of(x, struct dma_buf_attach_sysfs_entry, kobj)
126 struct dma_buf_attach_stats_attribute {
127 struct attribute attr;
128 ssize_t (*show)(struct dma_buf_attach_sysfs_entry *sysfs_entry,
129 struct dma_buf_attach_stats_attribute *attr, char *buf);
131 #define to_dma_buf_attach_stats_attr(x) container_of(x, struct dma_buf_attach_stats_attribute, attr)
133 static ssize_t dma_buf_attach_stats_attribute_show(struct kobject *kobj,
134 struct attribute *attr,
137 struct dma_buf_attach_stats_attribute *attribute;
138 struct dma_buf_attach_sysfs_entry *sysfs_entry;
140 attribute = to_dma_buf_attach_stats_attr(attr);
141 sysfs_entry = to_dma_buf_attach_entry_from_kobj(kobj);
143 if (!attribute->show)
146 return attribute->show(sysfs_entry, attribute, buf);
149 static const struct sysfs_ops dma_buf_attach_stats_sysfs_ops = {
150 .show = dma_buf_attach_stats_attribute_show,
153 static ssize_t map_counter_show(struct dma_buf_attach_sysfs_entry *sysfs_entry,
154 struct dma_buf_attach_stats_attribute *attr,
157 return sysfs_emit(buf, "%u\n", sysfs_entry->map_counter);
160 static struct dma_buf_attach_stats_attribute map_counter_attribute =
161 __ATTR_RO(map_counter);
163 static struct attribute *dma_buf_attach_stats_default_attrs[] = {
164 &map_counter_attribute.attr,
167 ATTRIBUTE_GROUPS(dma_buf_attach_stats_default);
169 static void dma_buf_attach_sysfs_release(struct kobject *kobj)
171 struct dma_buf_attach_sysfs_entry *sysfs_entry;
173 sysfs_entry = to_dma_buf_attach_entry_from_kobj(kobj);
177 static struct kobj_type dma_buf_attach_ktype = {
178 .sysfs_ops = &dma_buf_attach_stats_sysfs_ops,
179 .release = dma_buf_attach_sysfs_release,
180 .default_groups = dma_buf_attach_stats_default_groups,
183 void dma_buf_attach_stats_teardown(struct dma_buf_attachment *attach)
185 struct dma_buf_attach_sysfs_entry *sysfs_entry;
187 sysfs_entry = attach->sysfs_entry;
191 sysfs_delete_link(&sysfs_entry->kobj, &attach->dev->kobj, "device");
193 kobject_del(&sysfs_entry->kobj);
194 kobject_put(&sysfs_entry->kobj);
197 int dma_buf_attach_stats_setup(struct dma_buf_attachment *attach,
200 struct dma_buf_attach_sysfs_entry *sysfs_entry;
202 struct dma_buf *dmabuf;
207 dmabuf = attach->dmabuf;
209 sysfs_entry = kzalloc(sizeof(struct dma_buf_attach_sysfs_entry),
214 sysfs_entry->kobj.kset = dmabuf->sysfs_entry->attach_stats_kset;
216 attach->sysfs_entry = sysfs_entry;
218 ret = kobject_init_and_add(&sysfs_entry->kobj, &dma_buf_attach_ktype,
223 ret = sysfs_create_link(&sysfs_entry->kobj, &attach->dev->kobj,
231 kobject_del(&sysfs_entry->kobj);
233 kobject_put(&sysfs_entry->kobj);
234 attach->sysfs_entry = NULL;
238 void dma_buf_stats_teardown(struct dma_buf *dmabuf)
240 struct dma_buf_sysfs_entry *sysfs_entry;
242 sysfs_entry = dmabuf->sysfs_entry;
246 kset_unregister(sysfs_entry->attach_stats_kset);
247 kobject_del(&sysfs_entry->kobj);
248 kobject_put(&sysfs_entry->kobj);
252 /* Statistics files do not need to send uevents. */
253 static int dmabuf_sysfs_uevent_filter(struct kset *kset, struct kobject *kobj)
258 static const struct kset_uevent_ops dmabuf_sysfs_no_uevent_ops = {
259 .filter = dmabuf_sysfs_uevent_filter,
262 static struct kset *dma_buf_stats_kset;
263 static struct kset *dma_buf_per_buffer_stats_kset;
264 int dma_buf_init_sysfs_statistics(void)
266 dma_buf_stats_kset = kset_create_and_add("dmabuf",
267 &dmabuf_sysfs_no_uevent_ops,
269 if (!dma_buf_stats_kset)
272 dma_buf_per_buffer_stats_kset = kset_create_and_add("buffers",
273 &dmabuf_sysfs_no_uevent_ops,
274 &dma_buf_stats_kset->kobj);
275 if (!dma_buf_per_buffer_stats_kset) {
276 kset_unregister(dma_buf_stats_kset);
283 void dma_buf_uninit_sysfs_statistics(void)
285 kset_unregister(dma_buf_per_buffer_stats_kset);
286 kset_unregister(dma_buf_stats_kset);
289 int dma_buf_stats_setup(struct dma_buf *dmabuf)
291 struct dma_buf_sysfs_entry *sysfs_entry;
293 struct kset *attach_stats_kset;
295 if (!dmabuf || !dmabuf->file)
298 if (!dmabuf->exp_name) {
299 pr_err("exporter name must not be empty if stats needed\n");
303 sysfs_entry = kzalloc(sizeof(struct dma_buf_sysfs_entry), GFP_KERNEL);
307 sysfs_entry->kobj.kset = dma_buf_per_buffer_stats_kset;
308 sysfs_entry->dmabuf = dmabuf;
310 dmabuf->sysfs_entry = sysfs_entry;
312 /* create the directory for buffer stats */
313 ret = kobject_init_and_add(&sysfs_entry->kobj, &dma_buf_ktype, NULL,
314 "%lu", file_inode(dmabuf->file)->i_ino);
316 goto err_sysfs_dmabuf;
318 /* create the directory for attachment stats */
319 attach_stats_kset = kset_create_and_add("attachments",
320 &dmabuf_sysfs_no_uevent_ops,
322 if (!attach_stats_kset) {
324 goto err_sysfs_attach;
327 sysfs_entry->attach_stats_kset = attach_stats_kset;
332 kobject_del(&sysfs_entry->kobj);
334 kobject_put(&sysfs_entry->kobj);
335 dmabuf->sysfs_entry = NULL;