1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2025 Google LLC */
3 #include <linux/bpf.h>
4 #include <linux/btf_ids.h>
5 #include <linux/dma-buf.h>
6 #include <linux/kernel.h>
7 #include <linux/seq_file.h>
8
dmabuf_iter_seq_start(struct seq_file * seq,loff_t * pos)9 static void *dmabuf_iter_seq_start(struct seq_file *seq, loff_t *pos)
10 {
11 if (*pos)
12 return NULL;
13
14 return dma_buf_iter_begin();
15 }
16
dmabuf_iter_seq_next(struct seq_file * seq,void * v,loff_t * pos)17 static void *dmabuf_iter_seq_next(struct seq_file *seq, void *v, loff_t *pos)
18 {
19 struct dma_buf *dmabuf = v;
20
21 ++*pos;
22
23 return dma_buf_iter_next(dmabuf);
24 }
25
26 struct bpf_iter__dmabuf {
27 __bpf_md_ptr(struct bpf_iter_meta *, meta);
28 __bpf_md_ptr(struct dma_buf *, dmabuf);
29 };
30
__dmabuf_seq_show(struct seq_file * seq,void * v,bool in_stop)31 static int __dmabuf_seq_show(struct seq_file *seq, void *v, bool in_stop)
32 {
33 struct bpf_iter_meta meta = {
34 .seq = seq,
35 };
36 struct bpf_iter__dmabuf ctx = {
37 .meta = &meta,
38 .dmabuf = v,
39 };
40 struct bpf_prog *prog = bpf_iter_get_info(&meta, in_stop);
41
42 if (prog)
43 return bpf_iter_run_prog(prog, &ctx);
44
45 return 0;
46 }
47
dmabuf_iter_seq_show(struct seq_file * seq,void * v)48 static int dmabuf_iter_seq_show(struct seq_file *seq, void *v)
49 {
50 return __dmabuf_seq_show(seq, v, false);
51 }
52
dmabuf_iter_seq_stop(struct seq_file * seq,void * v)53 static void dmabuf_iter_seq_stop(struct seq_file *seq, void *v)
54 {
55 struct dma_buf *dmabuf = v;
56
57 if (dmabuf)
58 dma_buf_put(dmabuf);
59 }
60
61 static const struct seq_operations dmabuf_iter_seq_ops = {
62 .start = dmabuf_iter_seq_start,
63 .next = dmabuf_iter_seq_next,
64 .stop = dmabuf_iter_seq_stop,
65 .show = dmabuf_iter_seq_show,
66 };
67
bpf_iter_dmabuf_show_fdinfo(const struct bpf_iter_aux_info * aux,struct seq_file * seq)68 static void bpf_iter_dmabuf_show_fdinfo(const struct bpf_iter_aux_info *aux,
69 struct seq_file *seq)
70 {
71 seq_puts(seq, "dmabuf iter\n");
72 }
73
74 static const struct bpf_iter_seq_info dmabuf_iter_seq_info = {
75 .seq_ops = &dmabuf_iter_seq_ops,
76 .init_seq_private = NULL,
77 .fini_seq_private = NULL,
78 .seq_priv_size = 0,
79 };
80
81 static struct bpf_iter_reg bpf_dmabuf_reg_info = {
82 .target = "dmabuf",
83 .feature = BPF_ITER_RESCHED,
84 .show_fdinfo = bpf_iter_dmabuf_show_fdinfo,
85 .ctx_arg_info_size = 1,
86 .ctx_arg_info = {
87 { offsetof(struct bpf_iter__dmabuf, dmabuf),
88 PTR_TO_BTF_ID_OR_NULL },
89 },
90 .seq_info = &dmabuf_iter_seq_info,
91 };
92
DEFINE_BPF_ITER_FUNC(dmabuf,struct bpf_iter_meta * meta,struct dma_buf * dmabuf)93 DEFINE_BPF_ITER_FUNC(dmabuf, struct bpf_iter_meta *meta, struct dma_buf *dmabuf)
94 BTF_ID_LIST_SINGLE(bpf_dmabuf_btf_id, struct, dma_buf)
95
96 static int __init dmabuf_iter_init(void)
97 {
98 bpf_dmabuf_reg_info.ctx_arg_info[0].btf_id = bpf_dmabuf_btf_id[0];
99 return bpf_iter_reg_target(&bpf_dmabuf_reg_info);
100 }
101
102 late_initcall(dmabuf_iter_init);
103
104 struct bpf_iter_dmabuf {
105 /*
106 * opaque iterator state; having __u64 here allows to preserve correct
107 * alignment requirements in vmlinux.h, generated from BTF
108 */
109 __u64 __opaque[1];
110 } __aligned(8);
111
112 /* Non-opaque version of bpf_iter_dmabuf */
113 struct bpf_iter_dmabuf_kern {
114 struct dma_buf *dmabuf;
115 } __aligned(8);
116
117 __bpf_kfunc_start_defs();
118
bpf_iter_dmabuf_new(struct bpf_iter_dmabuf * it)119 __bpf_kfunc int bpf_iter_dmabuf_new(struct bpf_iter_dmabuf *it)
120 {
121 struct bpf_iter_dmabuf_kern *kit = (void *)it;
122
123 BUILD_BUG_ON(sizeof(*kit) > sizeof(*it));
124 BUILD_BUG_ON(__alignof__(*kit) != __alignof__(*it));
125
126 kit->dmabuf = NULL;
127 return 0;
128 }
129
bpf_iter_dmabuf_next(struct bpf_iter_dmabuf * it)130 __bpf_kfunc struct dma_buf *bpf_iter_dmabuf_next(struct bpf_iter_dmabuf *it)
131 {
132 struct bpf_iter_dmabuf_kern *kit = (void *)it;
133
134 if (kit->dmabuf)
135 kit->dmabuf = dma_buf_iter_next(kit->dmabuf);
136 else
137 kit->dmabuf = dma_buf_iter_begin();
138
139 return kit->dmabuf;
140 }
141
bpf_iter_dmabuf_destroy(struct bpf_iter_dmabuf * it)142 __bpf_kfunc void bpf_iter_dmabuf_destroy(struct bpf_iter_dmabuf *it)
143 {
144 struct bpf_iter_dmabuf_kern *kit = (void *)it;
145
146 if (kit->dmabuf)
147 dma_buf_put(kit->dmabuf);
148 }
149
150 __bpf_kfunc_end_defs();
151