Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/dma-buf/dma-buf-sysfs-stats.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* DMA-BUF sysfs statistics.
4
*
5
* Copyright (C) 2021 Google LLC.
6
*/
7
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>
14
15
#include "dma-buf-sysfs-stats.h"
16
17
#define to_dma_buf_entry_from_kobj(x) container_of(x, struct dma_buf_sysfs_entry, kobj)
18
19
/**
20
* DOC: overview
21
*
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
25
* production systems.
26
*
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.
30
*
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.
35
*
36
* The interface at ``/sys/kernel/dmabuf/buffers`` exposes information about
37
* every DMA-BUF when ``CONFIG_DMABUF_SYSFS_STATS`` is enabled.
38
*
39
* The following stats are exposed by the interface:
40
*
41
* * ``/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name``
42
* * ``/sys/kernel/dmabuf/buffers/<inode_number>/size``
43
*
44
* The information in the interface can also be used to derive per-exporter
45
* statistics. The data from the interface can be gathered on error conditions
46
* or other important events to provide a snapshot of DMA-BUF usage.
47
* It can also be collected periodically by telemetry to monitor various metrics.
48
*
49
* Detailed documentation about the interface is present in
50
* Documentation/ABI/testing/sysfs-kernel-dmabuf-buffers.
51
*/
52
53
struct dma_buf_stats_attribute {
54
struct attribute attr;
55
ssize_t (*show)(struct dma_buf *dmabuf,
56
struct dma_buf_stats_attribute *attr, char *buf);
57
};
58
#define to_dma_buf_stats_attr(x) container_of(x, struct dma_buf_stats_attribute, attr)
59
60
static ssize_t dma_buf_stats_attribute_show(struct kobject *kobj,
61
struct attribute *attr,
62
char *buf)
63
{
64
struct dma_buf_stats_attribute *attribute;
65
struct dma_buf_sysfs_entry *sysfs_entry;
66
struct dma_buf *dmabuf;
67
68
attribute = to_dma_buf_stats_attr(attr);
69
sysfs_entry = to_dma_buf_entry_from_kobj(kobj);
70
dmabuf = sysfs_entry->dmabuf;
71
72
if (!dmabuf || !attribute->show)
73
return -EIO;
74
75
return attribute->show(dmabuf, attribute, buf);
76
}
77
78
static const struct sysfs_ops dma_buf_stats_sysfs_ops = {
79
.show = dma_buf_stats_attribute_show,
80
};
81
82
static ssize_t exporter_name_show(struct dma_buf *dmabuf,
83
struct dma_buf_stats_attribute *attr,
84
char *buf)
85
{
86
return sysfs_emit(buf, "%s\n", dmabuf->exp_name);
87
}
88
89
static ssize_t size_show(struct dma_buf *dmabuf,
90
struct dma_buf_stats_attribute *attr,
91
char *buf)
92
{
93
return sysfs_emit(buf, "%zu\n", dmabuf->size);
94
}
95
96
static struct dma_buf_stats_attribute exporter_name_attribute =
97
__ATTR_RO(exporter_name);
98
static struct dma_buf_stats_attribute size_attribute = __ATTR_RO(size);
99
100
static struct attribute *dma_buf_stats_default_attrs[] = {
101
&exporter_name_attribute.attr,
102
&size_attribute.attr,
103
NULL,
104
};
105
ATTRIBUTE_GROUPS(dma_buf_stats_default);
106
107
static void dma_buf_sysfs_release(struct kobject *kobj)
108
{
109
struct dma_buf_sysfs_entry *sysfs_entry;
110
111
sysfs_entry = to_dma_buf_entry_from_kobj(kobj);
112
kfree(sysfs_entry);
113
}
114
115
static const struct kobj_type dma_buf_ktype = {
116
.sysfs_ops = &dma_buf_stats_sysfs_ops,
117
.release = dma_buf_sysfs_release,
118
.default_groups = dma_buf_stats_default_groups,
119
};
120
121
void dma_buf_stats_teardown(struct dma_buf *dmabuf)
122
{
123
struct dma_buf_sysfs_entry *sysfs_entry;
124
125
sysfs_entry = dmabuf->sysfs_entry;
126
if (!sysfs_entry)
127
return;
128
129
kobject_del(&sysfs_entry->kobj);
130
kobject_put(&sysfs_entry->kobj);
131
}
132
133
134
/* Statistics files do not need to send uevents. */
135
static int dmabuf_sysfs_uevent_filter(const struct kobject *kobj)
136
{
137
return 0;
138
}
139
140
static const struct kset_uevent_ops dmabuf_sysfs_no_uevent_ops = {
141
.filter = dmabuf_sysfs_uevent_filter,
142
};
143
144
static struct kset *dma_buf_stats_kset;
145
static struct kset *dma_buf_per_buffer_stats_kset;
146
int dma_buf_init_sysfs_statistics(void)
147
{
148
dma_buf_stats_kset = kset_create_and_add("dmabuf",
149
&dmabuf_sysfs_no_uevent_ops,
150
kernel_kobj);
151
if (!dma_buf_stats_kset)
152
return -ENOMEM;
153
154
dma_buf_per_buffer_stats_kset = kset_create_and_add("buffers",
155
&dmabuf_sysfs_no_uevent_ops,
156
&dma_buf_stats_kset->kobj);
157
if (!dma_buf_per_buffer_stats_kset) {
158
kset_unregister(dma_buf_stats_kset);
159
return -ENOMEM;
160
}
161
162
return 0;
163
}
164
165
void dma_buf_uninit_sysfs_statistics(void)
166
{
167
kset_unregister(dma_buf_per_buffer_stats_kset);
168
kset_unregister(dma_buf_stats_kset);
169
}
170
171
int dma_buf_stats_setup(struct dma_buf *dmabuf, struct file *file)
172
{
173
struct dma_buf_sysfs_entry *sysfs_entry;
174
int ret;
175
176
if (!dmabuf->exp_name) {
177
pr_err("exporter name must not be empty if stats needed\n");
178
return -EINVAL;
179
}
180
181
sysfs_entry = kzalloc(sizeof(struct dma_buf_sysfs_entry), GFP_KERNEL);
182
if (!sysfs_entry)
183
return -ENOMEM;
184
185
sysfs_entry->kobj.kset = dma_buf_per_buffer_stats_kset;
186
sysfs_entry->dmabuf = dmabuf;
187
188
dmabuf->sysfs_entry = sysfs_entry;
189
190
/* create the directory for buffer stats */
191
ret = kobject_init_and_add(&sysfs_entry->kobj, &dma_buf_ktype, NULL,
192
"%lu", file_inode(file)->i_ino);
193
if (ret)
194
goto err_sysfs_dmabuf;
195
196
return 0;
197
198
err_sysfs_dmabuf:
199
kobject_put(&sysfs_entry->kobj);
200
dmabuf->sysfs_entry = NULL;
201
return ret;
202
}
203
204