1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2025 Google LLC */
#include <vmlinux.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_helpers.h>
/* From uapi/linux/dma-buf.h */
#define DMA_BUF_NAME_LEN 32
char _license[] SEC("license") = "GPL";
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(key_size, DMA_BUF_NAME_LEN);
__type(value, bool);
__uint(max_entries, 5);
} testbuf_hash SEC(".maps");
/*
* Fields output by this iterator are delimited by newlines. Convert any
* newlines in user-provided printed strings to spaces.
*/
static void sanitize_string(char *src, size_t size)
{
for (char *c = src; (size_t)(c - src) < size && *c; ++c)
if (*c == '\n')
*c = ' ';
}
SEC("iter/dmabuf")
int dmabuf_collector(struct bpf_iter__dmabuf *ctx)
{
const struct dma_buf *dmabuf = ctx->dmabuf;
struct seq_file *seq = ctx->meta->seq;
unsigned long inode = 0;
size_t size;
const char *pname, *exporter;
char name[DMA_BUF_NAME_LEN] = {'\0'};
if (!dmabuf)
return 0;
if (BPF_CORE_READ_INTO(&inode, dmabuf, file, f_inode, i_ino) ||
bpf_core_read(&size, sizeof(size), &dmabuf->size) ||
bpf_core_read(&pname, sizeof(pname), &dmabuf->name) ||
bpf_core_read(&exporter, sizeof(exporter), &dmabuf->exp_name))
return 1;
/* Buffers are not required to be named */
if (pname) {
if (bpf_probe_read_kernel(name, sizeof(name), pname))
return 1;
/* Name strings can be provided by userspace */
sanitize_string(name, sizeof(name));
}
BPF_SEQ_PRINTF(seq, "%lu\n%llu\n%s\n%s\n", inode, size, name, exporter);
return 0;
}
SEC("syscall")
int iter_dmabuf_for_each(const void *ctx)
{
struct dma_buf *d;
bpf_for_each(dmabuf, d) {
char name[DMA_BUF_NAME_LEN];
const char *pname;
bool *found;
long len;
int i;
if (bpf_core_read(&pname, sizeof(pname), &d->name))
return 1;
/* Buffers are not required to be named */
if (!pname)
continue;
len = bpf_probe_read_kernel_str(name, sizeof(name), pname);
if (len < 0)
return 1;
/*
* The entire name buffer is used as a map key.
* Zeroize any uninitialized trailing bytes after the NUL.
*/
bpf_for(i, len, DMA_BUF_NAME_LEN)
name[i] = 0;
found = bpf_map_lookup_elem(&testbuf_hash, name);
if (found) {
bool t = true;
bpf_map_update_elem(&testbuf_hash, name, &t, BPF_EXIST);
}
}
return 0;
}
|