1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 // Copyright (c) 2022 Google LLC
3
4 #include "test_fuse_bpf.h"
5
6 SEC("test_readdir_redact")
7 /* return FUSE_BPF_BACKING to use backing fs, 0 to pass to usermode */
readdir_test(struct fuse_bpf_args * fa)8 int readdir_test(struct fuse_bpf_args *fa)
9 {
10 switch (fa->opcode) {
11 case FUSE_READDIR | FUSE_PREFILTER: {
12 const struct fuse_read_in *fri = fa->in_args[0].value;
13
14 bpf_printk("readdir %d", fri->fh);
15 return FUSE_BPF_BACKING | FUSE_BPF_POST_FILTER;
16 }
17
18 case FUSE_READDIR | FUSE_POSTFILTER: {
19 const struct fuse_read_in *fri = fa->in_args[0].value;
20
21 bpf_printk("readdir postfilter %x", fri->fh);
22 return FUSE_BPF_USER_FILTER;
23 }
24
25 default:
26 bpf_printk("opcode %d", fa->opcode);
27 return FUSE_BPF_BACKING;
28 }
29 }
30
31 SEC("test_partial")
32 /* return FUSE_BPF_BACKING to use backing fs, 0 to pass to usermode */
partial_test(struct fuse_bpf_args * fa)33 int partial_test(struct fuse_bpf_args *fa)
34 {
35 switch (fa->opcode) {
36 case FUSE_LOOKUP | FUSE_PREFILTER: {
37 /* real and partial use backing file */
38 const char *name = fa->in_args[0].value;
39 bool backing = false;
40
41 if (strcmp(name, "real") == 0 || strcmp(name, "partial") == 0)
42 backing = true;
43
44 if (strcmp(name, "dir") == 0)
45 backing = true;
46 if (strcmp(name, "dir2") == 0)
47 backing = true;
48
49 if (strcmp(name, "file1") == 0)
50 backing = true;
51 if (strcmp(name, "file2") == 0)
52 backing = true;
53
54 bpf_printk("lookup %s %d", name, backing);
55 return backing ? FUSE_BPF_BACKING | FUSE_BPF_POST_FILTER : 0;
56 }
57
58 case FUSE_LOOKUP | FUSE_POSTFILTER: {
59 const char *name = fa->in_args[0].value;
60 struct fuse_entry_out *feo = fa->out_args[0].value;
61
62 if (strcmp(name, "real") == 0)
63 feo->nodeid = 5;
64 else if (strcmp(name, "partial") == 0)
65 feo->nodeid = 6;
66
67 bpf_printk("post-lookup %s %d", name, feo->nodeid);
68 return 0;
69 }
70
71 case FUSE_ACCESS | FUSE_PREFILTER: {
72 bpf_printk("Access: %d", fa->nodeid);
73 return FUSE_BPF_BACKING;
74 }
75
76 case FUSE_CREATE | FUSE_PREFILTER:
77 bpf_printk("Create: %d", fa->nodeid);
78 return FUSE_BPF_BACKING;
79
80 case FUSE_MKNOD | FUSE_PREFILTER: {
81 const struct fuse_mknod_in *fmi = fa->in_args[0].value;
82 const char *name = fa->in_args[1].value;
83
84 bpf_printk("mknod %s %x %x", name, fmi->rdev | fmi->mode, fmi->umask);
85 return FUSE_BPF_BACKING;
86 }
87
88 case FUSE_MKDIR | FUSE_PREFILTER: {
89 const struct fuse_mkdir_in *fmi = fa->in_args[0].value;
90 const char *name = fa->in_args[1].value;
91
92 bpf_printk("mkdir %s %x %x", name, fmi->mode, fmi->umask);
93 return FUSE_BPF_BACKING;
94 }
95
96 case FUSE_RMDIR | FUSE_PREFILTER: {
97 const char *name = fa->in_args[0].value;
98
99 bpf_printk("rmdir %s", name);
100 return FUSE_BPF_BACKING;
101 }
102
103 case FUSE_RENAME | FUSE_PREFILTER: {
104 const char *oldname = fa->in_args[1].value;
105 const char *newname = fa->in_args[2].value;
106
107 bpf_printk("rename from %s", oldname);
108 bpf_printk("rename to %s", newname);
109 return FUSE_BPF_BACKING;
110 }
111
112 case FUSE_RENAME2 | FUSE_PREFILTER: {
113 const struct fuse_rename2_in *fri = fa->in_args[0].value;
114 uint32_t flags = fri->flags;
115 const char *oldname = fa->in_args[1].value;
116 const char *newname = fa->in_args[2].value;
117
118 bpf_printk("rename(%x) from %s", flags, oldname);
119 bpf_printk("rename to %s", newname);
120 return FUSE_BPF_BACKING;
121 }
122
123 case FUSE_UNLINK | FUSE_PREFILTER: {
124 const char *name = fa->in_args[0].value;
125
126 bpf_printk("unlink %s", name);
127 return FUSE_BPF_BACKING;
128 }
129
130 case FUSE_LINK | FUSE_PREFILTER: {
131 const struct fuse_link_in *fli = fa->in_args[0].value;
132 const char *link_name = fa->in_args[1].value;
133
134 bpf_printk("link %d %s", fli->oldnodeid, link_name);
135 return FUSE_BPF_BACKING;
136 }
137
138 case FUSE_SYMLINK | FUSE_PREFILTER: {
139 const char *link_name = fa->in_args[0].value;
140 const char *link_dest = fa->in_args[1].value;
141
142 bpf_printk("symlink from %s", link_name);
143 bpf_printk("symlink to %s", link_dest);
144 return FUSE_BPF_BACKING;
145 }
146
147 case FUSE_READLINK | FUSE_PREFILTER: {
148 const char *link_name = fa->in_args[0].value;
149
150 bpf_printk("readlink from", link_name);
151 return FUSE_BPF_BACKING;
152 }
153
154 case FUSE_OPEN | FUSE_PREFILTER: {
155 int backing = 0;
156
157 switch (fa->nodeid) {
158 case 5:
159 backing = FUSE_BPF_BACKING;
160 break;
161
162 case 6:
163 backing = FUSE_BPF_BACKING | FUSE_BPF_POST_FILTER;
164 break;
165
166 default:
167 break;
168 }
169
170 bpf_printk("open %d %d", fa->nodeid, backing);
171 return backing;
172 }
173
174 case FUSE_OPEN | FUSE_POSTFILTER:
175 bpf_printk("open postfilter");
176 return FUSE_BPF_USER_FILTER;
177
178 case FUSE_READ | FUSE_PREFILTER: {
179 const struct fuse_read_in *fri = fa->in_args[0].value;
180
181 bpf_printk("read %llu %llu", fri->fh, fri->offset);
182 if (fri->fh == 1 && fri->offset == 0)
183 return 0;
184 return FUSE_BPF_BACKING;
185 }
186
187 case FUSE_GETATTR | FUSE_PREFILTER: {
188 /* real and partial use backing file */
189 int backing = 0;
190
191 switch (fa->nodeid) {
192 case 1:
193 case 5:
194 case 6:
195 /*
196 * TODO: Find better solution
197 * Add 100 to stop clang compiling to jump table which bpf hates
198 */
199 case 100:
200 backing = FUSE_BPF_BACKING;
201 break;
202 }
203
204 bpf_printk("getattr %d %d", fa->nodeid, backing);
205 return backing;
206 }
207
208 case FUSE_SETATTR | FUSE_PREFILTER: {
209 /* real and partial use backing file */
210 int backing = 0;
211
212 switch (fa->nodeid) {
213 case 1:
214 case 5:
215 case 6:
216 /* TODO See above */
217 case 100:
218 backing = FUSE_BPF_BACKING;
219 break;
220 }
221
222 bpf_printk("setattr %d %d", fa->nodeid, backing);
223 return backing;
224 }
225
226 case FUSE_OPENDIR | FUSE_PREFILTER: {
227 int backing = 0;
228
229 switch (fa->nodeid) {
230 case 1:
231 backing = FUSE_BPF_BACKING | FUSE_BPF_POST_FILTER;
232 break;
233 }
234
235 bpf_printk("opendir %d %d", fa->nodeid, backing);
236 return backing;
237 }
238
239 case FUSE_OPENDIR | FUSE_POSTFILTER: {
240 struct fuse_open_out *foo = fa->out_args[0].value;
241
242 foo->fh = 2;
243 bpf_printk("opendir postfilter");
244 return 0;
245 }
246
247 case FUSE_READDIR | FUSE_PREFILTER: {
248 const struct fuse_read_in *fri = fa->in_args[0].value;
249 int backing = 0;
250
251 if (fri->fh == 2)
252 backing = FUSE_BPF_BACKING | FUSE_BPF_POST_FILTER;
253
254 bpf_printk("readdir %d %d", fri->fh, backing);
255 return backing;
256 }
257
258 case FUSE_READDIR | FUSE_POSTFILTER: {
259 const struct fuse_read_in *fri = fa->in_args[0].value;
260 int backing = 0;
261
262 if (fri->fh == 2)
263 backing = FUSE_BPF_USER_FILTER | FUSE_BPF_BACKING |
264 FUSE_BPF_POST_FILTER;
265
266 bpf_printk("readdir postfilter %d %d", fri->fh, backing);
267 return backing;
268 }
269
270 case FUSE_FLUSH | FUSE_PREFILTER: {
271 const struct fuse_flush_in *ffi = fa->in_args[0].value;
272
273 bpf_printk("Flush %d", ffi->fh);
274 return FUSE_BPF_BACKING;
275 }
276
277 case FUSE_GETXATTR | FUSE_PREFILTER: {
278 const struct fuse_flush_in *ffi = fa->in_args[0].value;
279 const char *name = fa->in_args[1].value;
280
281 bpf_printk("getxattr %d %s", ffi->fh, name);
282 return FUSE_BPF_BACKING;
283 }
284
285 case FUSE_LISTXATTR | FUSE_PREFILTER: {
286 const struct fuse_flush_in *ffi = fa->in_args[0].value;
287 const char *name = fa->in_args[1].value;
288
289 bpf_printk("listxattr %d %s", ffi->fh, name);
290 return FUSE_BPF_BACKING;
291 }
292
293 case FUSE_SETXATTR | FUSE_PREFILTER: {
294 const struct fuse_flush_in *ffi = fa->in_args[0].value;
295 const char *name = fa->in_args[1].value;
296 unsigned int size = fa->in_args[2].size;
297
298 bpf_printk("setxattr %d %s %u", ffi->fh, name, size);
299 return FUSE_BPF_BACKING;
300 }
301
302 case FUSE_REMOVEXATTR | FUSE_PREFILTER: {
303 const char *name = fa->in_args[0].value;
304
305 bpf_printk("removexattr %s", name);
306 return FUSE_BPF_BACKING;
307 }
308
309 case FUSE_CANONICAL_PATH | FUSE_PREFILTER: {
310 bpf_printk("canonical_path");
311 return FUSE_BPF_BACKING;
312 }
313
314 case FUSE_STATFS | FUSE_PREFILTER: {
315 bpf_printk("statfs");
316 return FUSE_BPF_BACKING;
317 }
318
319 case FUSE_LSEEK | FUSE_PREFILTER: {
320 const struct fuse_lseek_in *fli = fa->in_args[0].value;
321
322 bpf_printk("lseek type:%d, offset:%lld", fli->whence, fli->offset);
323 return FUSE_BPF_BACKING;
324 }
325
326 default:
327 bpf_printk("Unknown opcode %d", fa->opcode);
328 return 0;
329 }
330 }
331
332 SEC("test_trace")
333 /* return FUSE_BPF_BACKING to use backing fs, 0 to pass to usermode */
trace_test(struct fuse_bpf_args * fa)334 int trace_test(struct fuse_bpf_args *fa)
335 {
336 switch (fa->opcode) {
337 case FUSE_LOOKUP | FUSE_PREFILTER: {
338 /* real and partial use backing file */
339 const char *name = fa->in_args[0].value;
340
341 bpf_printk("lookup %s", name);
342 return FUSE_BPF_BACKING;
343 }
344
345 case FUSE_ACCESS | FUSE_PREFILTER: {
346 bpf_printk("Access: %d", fa->nodeid);
347 return FUSE_BPF_BACKING;
348 }
349
350 case FUSE_CREATE | FUSE_PREFILTER:
351 bpf_printk("Create: %d", fa->nodeid);
352 return FUSE_BPF_BACKING;
353
354 case FUSE_MKNOD | FUSE_PREFILTER: {
355 const struct fuse_mknod_in *fmi = fa->in_args[0].value;
356 const char *name = fa->in_args[1].value;
357
358 bpf_printk("mknod %s %x %x", name, fmi->rdev | fmi->mode, fmi->umask);
359 return FUSE_BPF_BACKING;
360 }
361
362 case FUSE_MKDIR | FUSE_PREFILTER: {
363 const struct fuse_mkdir_in *fmi = fa->in_args[0].value;
364 const char *name = fa->in_args[1].value;
365
366 bpf_printk("mkdir %s %x %x", name, fmi->mode, fmi->umask);
367 return FUSE_BPF_BACKING;
368 }
369
370 case FUSE_RMDIR | FUSE_PREFILTER: {
371 const char *name = fa->in_args[0].value;
372
373 bpf_printk("rmdir %s", name);
374 return FUSE_BPF_BACKING;
375 }
376
377 case FUSE_RENAME | FUSE_PREFILTER: {
378 const char *oldname = fa->in_args[1].value;
379 const char *newname = fa->in_args[2].value;
380
381 bpf_printk("rename from %s", oldname);
382 bpf_printk("rename to %s", newname);
383 return FUSE_BPF_BACKING;
384 }
385
386 case FUSE_RENAME2 | FUSE_PREFILTER: {
387 const struct fuse_rename2_in *fri = fa->in_args[0].value;
388 uint32_t flags = fri->flags;
389 const char *oldname = fa->in_args[1].value;
390 const char *newname = fa->in_args[2].value;
391
392 bpf_printk("rename(%x) from %s", flags, oldname);
393 bpf_printk("rename to %s", newname);
394 return FUSE_BPF_BACKING;
395 }
396
397 case FUSE_UNLINK | FUSE_PREFILTER: {
398 const char *name = fa->in_args[0].value;
399
400 bpf_printk("unlink %s", name);
401 return FUSE_BPF_BACKING;
402 }
403
404 case FUSE_LINK | FUSE_PREFILTER: {
405 const struct fuse_link_in *fli = fa->in_args[0].value;
406 const char *link_name = fa->in_args[1].value;
407
408 bpf_printk("link %d %s", fli->oldnodeid, link_name);
409 return FUSE_BPF_BACKING;
410 }
411
412 case FUSE_SYMLINK | FUSE_PREFILTER: {
413 const char *link_name = fa->in_args[0].value;
414 const char *link_dest = fa->in_args[1].value;
415
416 bpf_printk("symlink from %s", link_name);
417 bpf_printk("symlink to %s", link_dest);
418 return FUSE_BPF_BACKING;
419 }
420
421 case FUSE_READLINK | FUSE_PREFILTER: {
422 const char *link_name = fa->in_args[0].value;
423
424 bpf_printk("readlink from", link_name);
425 return FUSE_BPF_BACKING;
426 }
427
428 case FUSE_OPEN | FUSE_PREFILTER: {
429 bpf_printk("open");
430 return FUSE_BPF_BACKING;
431 }
432
433 case FUSE_OPEN | FUSE_POSTFILTER:
434 bpf_printk("open postfilter");
435 return FUSE_BPF_USER_FILTER;
436
437 case FUSE_READ | FUSE_PREFILTER: {
438 const struct fuse_read_in *fri = fa->in_args[0].value;
439
440 bpf_printk("read %llu", fri->offset);
441 return FUSE_BPF_BACKING;
442 }
443
444 case FUSE_GETATTR | FUSE_PREFILTER: {
445 bpf_printk("getattr");
446 return FUSE_BPF_BACKING;
447 }
448
449 case FUSE_SETATTR | FUSE_PREFILTER: {
450 bpf_printk("setattr");
451 return FUSE_BPF_BACKING;
452 }
453
454 case FUSE_OPENDIR | FUSE_PREFILTER: {
455 bpf_printk("opendir");
456 return FUSE_BPF_BACKING;
457 }
458
459 case FUSE_READDIR | FUSE_PREFILTER: {
460 bpf_printk("readdir");
461 return FUSE_BPF_BACKING;
462 }
463
464 case FUSE_FLUSH | FUSE_PREFILTER: {
465 bpf_printk("Flush");
466 return FUSE_BPF_BACKING;
467 }
468
469 case FUSE_GETXATTR | FUSE_PREFILTER: {
470 const char *name = fa->in_args[1].value;
471
472 bpf_printk("getxattr %s", name);
473 return FUSE_BPF_BACKING;
474 }
475
476 case FUSE_LISTXATTR | FUSE_PREFILTER: {
477 const char *name = fa->in_args[1].value;
478
479 bpf_printk("listxattr %s", name);
480 return FUSE_BPF_BACKING;
481 }
482
483 case FUSE_SETXATTR | FUSE_PREFILTER: {
484 const char *name = fa->in_args[1].value;
485 unsigned int size = fa->in_args[2].size;
486
487 bpf_printk("setxattr %s %u", name, size);
488 return FUSE_BPF_BACKING;
489 }
490
491 case FUSE_REMOVEXATTR | FUSE_PREFILTER: {
492 const char *name = fa->in_args[0].value;
493
494 bpf_printk("removexattr %s", name);
495 return FUSE_BPF_BACKING;
496 }
497
498 case FUSE_CANONICAL_PATH | FUSE_PREFILTER: {
499 bpf_printk("canonical_path");
500 return FUSE_BPF_BACKING;
501 }
502
503 case FUSE_STATFS | FUSE_PREFILTER: {
504 bpf_printk("statfs");
505 return FUSE_BPF_BACKING;
506 }
507
508 case FUSE_LSEEK | FUSE_PREFILTER: {
509 const struct fuse_lseek_in *fli = fa->in_args[0].value;
510
511 bpf_printk("lseek type:%d, offset:%lld", fli->whence, fli->offset);
512 return FUSE_BPF_BACKING;
513 }
514
515 default:
516 bpf_printk("Unknown opcode %d", fa->opcode);
517 return FUSE_BPF_BACKING;
518 }
519 }
520
521 SEC("test_hidden")
trace_hidden(struct fuse_bpf_args * fa)522 int trace_hidden(struct fuse_bpf_args *fa)
523 {
524 switch (fa->opcode) {
525 case FUSE_LOOKUP | FUSE_PREFILTER: {
526 const char *name = fa->in_args[0].value;
527
528 bpf_printk("Lookup: %s", name);
529 if (!strcmp(name, "show"))
530 return FUSE_BPF_BACKING;
531 if (!strcmp(name, "hide"))
532 return -ENOENT;
533
534 return FUSE_BPF_BACKING;
535 }
536
537 case FUSE_ACCESS | FUSE_PREFILTER: {
538 bpf_printk("Access: %d", fa->nodeid);
539 return FUSE_BPF_BACKING;
540 }
541
542 case FUSE_CREATE | FUSE_PREFILTER:
543 bpf_printk("Create: %d", fa->nodeid);
544 return FUSE_BPF_BACKING;
545
546 case FUSE_WRITE | FUSE_PREFILTER:
547 // TODO: Clang combines similar printk calls, causing BPF to complain
548 // bpf_printk("Write: %d", fa->nodeid);
549 return FUSE_BPF_BACKING;
550
551 case FUSE_FLUSH | FUSE_PREFILTER: {
552 // const struct fuse_flush_in *ffi = fa->in_args[0].value;
553
554 // bpf_printk("Flush %d", ffi->fh);
555 return FUSE_BPF_BACKING;
556 }
557
558 case FUSE_RELEASE | FUSE_PREFILTER: {
559 // const struct fuse_release_in *fri = fa->in_args[0].value;
560
561 // bpf_printk("Release %d", fri->fh);
562 return FUSE_BPF_BACKING;
563 }
564
565 case FUSE_FALLOCATE | FUSE_PREFILTER:
566 // bpf_printk("fallocate %d", fa->nodeid);
567 return FUSE_BPF_BACKING;
568
569 case FUSE_CANONICAL_PATH | FUSE_PREFILTER: {
570 return FUSE_BPF_BACKING;
571 }
572 default:
573 bpf_printk("Unknown opcode: %d", fa->opcode);
574 return 0;
575 }
576 }
577
578 SEC("test_simple")
trace_simple(struct fuse_bpf_args * fa)579 int trace_simple(struct fuse_bpf_args *fa)
580 {
581 if (fa->opcode & FUSE_PREFILTER)
582 bpf_printk("prefilter opcode: %d",
583 fa->opcode & FUSE_OPCODE_FILTER);
584 else if (fa->opcode & FUSE_POSTFILTER)
585 bpf_printk("postfilter opcode: %d",
586 fa->opcode & FUSE_OPCODE_FILTER);
587 else
588 bpf_printk("*** UNKNOWN *** opcode: %d", fa->opcode);
589 return FUSE_BPF_BACKING;
590 }
591
592 SEC("test_passthrough")
trace_daemon(struct fuse_bpf_args * fa)593 int trace_daemon(struct fuse_bpf_args *fa)
594 {
595 switch (fa->opcode) {
596 case FUSE_LOOKUP | FUSE_PREFILTER: {
597 const char *name = fa->in_args[0].value;
598
599 bpf_printk("Lookup prefilter: %lx %s", fa->nodeid, name);
600 return FUSE_BPF_BACKING | FUSE_BPF_POST_FILTER;
601 }
602
603 case FUSE_LOOKUP | FUSE_POSTFILTER: {
604 const char *name = fa->in_args[0].value;
605 struct fuse_entry_bpf_out *febo = fa->out_args[1].value;
606
607 bpf_printk("Lookup postfilter: %lx %s %lu", fa->nodeid, name);
608 febo->bpf_action = FUSE_ACTION_REMOVE;
609
610 return FUSE_BPF_USER_FILTER;
611 }
612
613 default:
614 if (fa->opcode & FUSE_PREFILTER)
615 bpf_printk("prefilter opcode: %d",
616 fa->opcode & FUSE_OPCODE_FILTER);
617 else if (fa->opcode & FUSE_POSTFILTER)
618 bpf_printk("postfilter opcode: %d",
619 fa->opcode & FUSE_OPCODE_FILTER);
620 else
621 bpf_printk("*** UNKNOWN *** opcode: %d", fa->opcode);
622 return FUSE_BPF_BACKING;
623 }
624 }
625
626 SEC("test_error")
627 /* return FUSE_BPF_BACKING to use backing fs, 0 to pass to usermode */
error_test(struct fuse_bpf_args * fa)628 int error_test(struct fuse_bpf_args *fa)
629 {
630 switch (fa->opcode) {
631 case FUSE_MKDIR | FUSE_PREFILTER: {
632 bpf_printk("mkdir");
633 return FUSE_BPF_BACKING | FUSE_BPF_POST_FILTER;
634 }
635 case FUSE_MKDIR | FUSE_POSTFILTER: {
636 bpf_printk("mkdir postfilter");
637 if (fa->error_in == -EEXIST)
638 return -EPERM;
639
640 return 0;
641 }
642
643 case FUSE_LOOKUP | FUSE_PREFILTER: {
644 const char *name = fa->in_args[0].value;
645
646 bpf_printk("lookup prefilter %s", name);
647 return FUSE_BPF_BACKING | FUSE_BPF_POST_FILTER;
648 }
649 case FUSE_LOOKUP | FUSE_POSTFILTER: {
650 const char *name = fa->in_args[0].value;
651
652 bpf_printk("lookup postfilter %s %d", name, fa->error_in);
653 if (strcmp(name, "doesnotexist") == 0/* && fa->error_in == -EEXIST*/) {
654 bpf_printk("lookup postfilter doesnotexist");
655 return FUSE_BPF_USER_FILTER;
656 }
657 bpf_printk("meh");
658 return 0;
659 }
660
661 default:
662 if (fa->opcode & FUSE_PREFILTER)
663 bpf_printk("prefilter opcode: %d",
664 fa->opcode & FUSE_OPCODE_FILTER);
665 else if (fa->opcode & FUSE_POSTFILTER)
666 bpf_printk("postfilter opcode: %d",
667 fa->opcode & FUSE_OPCODE_FILTER);
668 else
669 bpf_printk("*** UNKNOWN *** opcode: %d", fa->opcode);
670 return FUSE_BPF_BACKING;
671 }
672 }
673
674 SEC("test_readdirplus")
readdirplus_test(struct fuse_bpf_args * fa)675 int readdirplus_test(struct fuse_bpf_args *fa)
676 {
677 switch (fa->opcode) {
678 case FUSE_READDIR | FUSE_PREFILTER: {
679 return 0;
680 }
681 }
682 return FUSE_BPF_BACKING;
683 }
684
685 SEC("test_lookup_postfilter")
lookuppostfilter_test(struct fuse_bpf_args * fa)686 int lookuppostfilter_test(struct fuse_bpf_args *fa)
687 {
688 switch (fa->opcode) {
689 case FUSE_LOOKUP | FUSE_PREFILTER:
690 return FUSE_BPF_BACKING | FUSE_BPF_POST_FILTER;
691 case FUSE_LOOKUP | FUSE_POSTFILTER:
692 return FUSE_BPF_USER_FILTER;
693 default:
694 return FUSE_BPF_BACKING;
695 }
696 }
697
698 SEC("test_create_remove")
createremovebpf_test(struct fuse_bpf_args * fa)699 int createremovebpf_test(struct fuse_bpf_args *fa)
700 {
701 switch (fa->opcode) {
702 case FUSE_LOOKUP | FUSE_PREFILTER: {
703 return FUSE_BPF_BACKING | FUSE_BPF_POST_FILTER;
704 }
705
706 case FUSE_LOOKUP | FUSE_POSTFILTER: {
707 struct fuse_entry_bpf_out *febo = fa->out_args[1].value;
708
709 febo->bpf_action = FUSE_ACTION_REMOVE;
710 return 0;
711 }
712
713 case FUSE_OPEN | FUSE_PREFILTER: {
714 return -EIO;
715 }
716
717 default:
718 return FUSE_BPF_BACKING;
719 }
720 }
721
722 SEC("test_mkdir_remove")
mkdirremovebpf_test(struct fuse_bpf_args * fa)723 int mkdirremovebpf_test(struct fuse_bpf_args *fa)
724 {
725 switch (fa->opcode) {
726 case FUSE_LOOKUP | FUSE_PREFILTER: {
727 return FUSE_BPF_BACKING | FUSE_BPF_POST_FILTER;
728 }
729
730 case FUSE_LOOKUP | FUSE_POSTFILTER: {
731 struct fuse_entry_bpf_out *febo = fa->out_args[1].value;
732
733 febo->bpf_action = FUSE_ACTION_REMOVE;
734 return 0;
735 }
736
737 case FUSE_OPENDIR | FUSE_PREFILTER: {
738 return -EIO;
739 }
740
741 default:
742 return FUSE_BPF_BACKING;
743 }
744 }
745