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 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 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 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 48 static int dmabuf_iter_seq_show(struct seq_file *seq, void *v) 49 { 50 return __dmabuf_seq_show(seq, v, false); 51 } 52 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 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 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 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 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 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