mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Use the same test buffers as the traditional iterator and a new BPF map to verify the test buffers can be found with the open coded dmabuf iterator. Signed-off-by: T.J. Mercier <tjmercier@google.com> Acked-by: Christian König <christian.koenig@amd.com> Acked-by: Song Liu <song@kernel.org> Link: https://lore.kernel.org/r/20250522230429.941193-6-tjmercier@google.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
101 lines
2.3 KiB
C
101 lines
2.3 KiB
C
// 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;
|
|
}
|