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