1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * FUSE-BPF: Filesystem in Userspace with BPF
4 * Copyright (c) 2021 Google LLC
5 */
6
7 #include "fuse_i.h"
8
9 #include <linux/fdtable.h>
10 #include <linux/filelock.h>
11 #include <linux/filter.h>
12 #include <linux/fs_stack.h>
13 #include <linux/splice.h>
14 #include <linux/namei.h>
15
16 #include "../internal.h"
17
18 #define FUSE_BPF_IOCB_MASK (IOCB_APPEND | IOCB_DSYNC | IOCB_HIPRI | IOCB_NOWAIT | IOCB_SYNC)
19
20 struct fuse_bpf_aio_req {
21 struct kiocb iocb;
22 refcount_t ref;
23 struct kiocb *iocb_orig;
24 };
25
26 static struct kmem_cache *fuse_bpf_aio_request_cachep;
27
28 static void fuse_stat_to_attr(struct fuse_conn *fc, struct inode *inode,
29 struct kstat *stat, struct fuse_attr *attr);
30
fuse_copyattr(struct file * dst_file,struct file * src_file)31 static void fuse_copyattr(struct file *dst_file, struct file *src_file)
32 {
33 struct inode *dst = file_inode(dst_file);
34 struct inode *src = file_inode(src_file);
35
36 inode_set_mtime_to_ts(dst, inode_get_mtime(src));
37 inode_set_ctime_to_ts(dst, inode_get_ctime(src));
38 inode_set_atime_to_ts(dst, inode_get_atime(src));
39 i_size_write(dst, i_size_read(src));
40 }
41
fuse_file_accessed(struct file * dst_file,struct file * src_file)42 static void fuse_file_accessed(struct file *dst_file, struct file *src_file)
43 {
44 struct inode *dst_inode;
45 struct inode *src_inode;
46 struct timespec64 dst_ctime, src_ctime, dst_mtime, src_mtime;
47
48 if (dst_file->f_flags & O_NOATIME)
49 return;
50
51 dst_inode = file_inode(dst_file);
52 src_inode = file_inode(src_file);
53
54 dst_ctime = inode_get_ctime(dst_inode);
55 src_ctime = inode_get_ctime(src_inode);
56 dst_mtime = inode_get_mtime(dst_inode);
57 src_mtime = inode_get_mtime(src_inode);
58 if (!timespec64_equal(&dst_mtime, &src_mtime) ||
59 !timespec64_equal(&dst_ctime, &src_ctime)) {
60 // Why not just call these two unconditionally?
61 inode_set_mtime_to_ts(dst_inode, inode_get_mtime(src_inode));
62 inode_set_ctime_to_ts(dst_inode, inode_get_ctime(src_inode));
63 }
64
65 touch_atime(&dst_file->f_path);
66 }
67
fuse_open_initialize(struct fuse_bpf_args * fa,struct fuse_open_io * foio,struct inode * inode,struct file * file,bool isdir)68 int fuse_open_initialize(struct fuse_bpf_args *fa, struct fuse_open_io *foio,
69 struct inode *inode, struct file *file, bool isdir)
70 {
71 foio->foi = (struct fuse_open_in) {
72 .flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY),
73 };
74
75 foio->foo = (struct fuse_open_out) {0};
76
77 *fa = (struct fuse_bpf_args) {
78 .nodeid = get_fuse_inode(inode)->nodeid,
79 .opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN,
80 .in_numargs = 1,
81 .out_numargs = 1,
82 .in_args[0] = (struct fuse_bpf_in_arg) {
83 .size = sizeof(foio->foi),
84 .value = &foio->foi,
85 },
86 .out_args[0] = (struct fuse_bpf_arg) {
87 .size = sizeof(foio->foo),
88 .value = &foio->foo,
89 },
90 };
91
92 return 0;
93 }
94
fuse_open_backing(struct fuse_bpf_args * fa,struct inode * inode,struct file * file,bool isdir)95 int fuse_open_backing(struct fuse_bpf_args *fa,
96 struct inode *inode, struct file *file, bool isdir)
97 {
98 struct fuse_mount *fm = get_fuse_mount(inode);
99 const struct fuse_open_in *foi = fa->in_args[0].value;
100 struct fuse_file *ff;
101 int retval;
102 int mask;
103 struct fuse_dentry *fd = get_fuse_dentry(file->f_path.dentry);
104 struct file *backing_file;
105
106 ff = fuse_file_alloc(fm, true);
107 if (!ff)
108 return -ENOMEM;
109 file->private_data = ff;
110
111 switch (foi->flags & O_ACCMODE) {
112 case O_RDONLY:
113 mask = MAY_READ;
114 break;
115
116 case O_WRONLY:
117 mask = MAY_WRITE;
118 break;
119
120 case O_RDWR:
121 mask = MAY_READ | MAY_WRITE;
122 break;
123
124 default:
125 return -EINVAL;
126 }
127
128 retval = inode_permission(&nop_mnt_idmap,
129 get_fuse_inode(inode)->backing_inode, mask);
130 if (retval)
131 return retval;
132
133 backing_file = dentry_open(&fd->backing_path,
134 foi->flags,
135 current_cred());
136
137 if (IS_ERR(backing_file)) {
138 fuse_file_free(ff);
139 file->private_data = NULL;
140 return PTR_ERR(backing_file);
141 }
142 ff->backing_file = backing_file;
143
144 return 0;
145 }
146
fuse_open_finalize(struct fuse_bpf_args * fa,struct inode * inode,struct file * file,bool isdir)147 void *fuse_open_finalize(struct fuse_bpf_args *fa,
148 struct inode *inode, struct file *file, bool isdir)
149 {
150 struct fuse_file *ff = file->private_data;
151 struct fuse_open_out *foo = fa->out_args[0].value;
152
153 if (ff) {
154 ff->fh = foo->fh;
155 ff->nodeid = get_fuse_inode(inode)->nodeid;
156 }
157 return 0;
158 }
159
fuse_create_open_initialize(struct fuse_bpf_args * fa,struct fuse_create_open_io * fcoio,struct inode * dir,struct dentry * entry,struct file * file,unsigned int flags,umode_t mode)160 int fuse_create_open_initialize(
161 struct fuse_bpf_args *fa, struct fuse_create_open_io *fcoio,
162 struct inode *dir, struct dentry *entry,
163 struct file *file, unsigned int flags, umode_t mode)
164 {
165 fcoio->fci = (struct fuse_create_in) {
166 .flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY),
167 .mode = mode,
168 };
169
170 fcoio->feo = (struct fuse_entry_out) {0};
171 fcoio->foo = (struct fuse_open_out) {0};
172
173 *fa = (struct fuse_bpf_args) {
174 .nodeid = get_node_id(dir),
175 .opcode = FUSE_CREATE,
176 .in_numargs = 2,
177 .out_numargs = 2,
178 .in_args[0] = (struct fuse_bpf_in_arg) {
179 .size = sizeof(fcoio->fci),
180 .value = &fcoio->fci,
181 },
182 .in_args[1] = (struct fuse_bpf_in_arg) {
183 .size = entry->d_name.len + 1,
184 .value = entry->d_name.name,
185 },
186 .out_args[0] = (struct fuse_bpf_arg) {
187 .size = sizeof(fcoio->feo),
188 .value = &fcoio->feo,
189 },
190 .out_args[1] = (struct fuse_bpf_arg) {
191 .size = sizeof(fcoio->foo),
192 .value = &fcoio->foo,
193 },
194 };
195
196 return 0;
197 }
198
fuse_open_file_backing(struct inode * inode,struct file * file)199 static int fuse_open_file_backing(struct inode *inode, struct file *file)
200 {
201 struct fuse_mount *fm = get_fuse_mount(inode);
202 struct dentry *entry = file->f_path.dentry;
203 struct fuse_dentry *fuse_dentry = get_fuse_dentry(entry);
204 struct fuse_file *fuse_file;
205 struct file *backing_file;
206
207 fuse_file = fuse_file_alloc(fm, true);
208 if (!fuse_file)
209 return -ENOMEM;
210 file->private_data = fuse_file;
211
212 backing_file = dentry_open(&fuse_dentry->backing_path, file->f_flags,
213 current_cred());
214 if (IS_ERR(backing_file)) {
215 fuse_file_free(fuse_file);
216 file->private_data = NULL;
217 return PTR_ERR(backing_file);
218 }
219 fuse_file->backing_file = backing_file;
220
221 return 0;
222 }
223
fuse_create_open_backing(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,struct file * file,unsigned int flags,umode_t mode)224 int fuse_create_open_backing(
225 struct fuse_bpf_args *fa,
226 struct inode *dir, struct dentry *entry,
227 struct file *file, unsigned int flags, umode_t mode)
228 {
229 struct fuse_inode *dir_fuse_inode = get_fuse_inode(dir);
230 struct fuse_dentry *fuse_entry = get_fuse_dentry(entry);
231 struct fuse_dentry *dir_fuse_dentry = get_fuse_dentry(entry->d_parent);
232 struct dentry *backing_dentry = NULL;
233 struct inode *inode = NULL;
234 struct dentry *newent;
235 int err = 0;
236 const struct fuse_create_in *fci = fa->in_args[0].value;
237 struct inode *d_inode = entry->d_inode;
238 u64 target_nodeid = 0;
239
240 if (!dir_fuse_inode || !dir_fuse_dentry)
241 return -EIO;
242
243 inode_lock_nested(dir_fuse_inode->backing_inode, I_MUTEX_PARENT);
244 backing_dentry = lookup_one_len(fa->in_args[1].value,
245 dir_fuse_dentry->backing_path.dentry,
246 strlen(fa->in_args[1].value));
247 inode_unlock(dir_fuse_inode->backing_inode);
248
249 if (IS_ERR(backing_dentry))
250 return PTR_ERR(backing_dentry);
251
252 if (d_really_is_positive(backing_dentry)) {
253 err = -EIO;
254 goto out;
255 }
256
257 err = vfs_create(&nop_mnt_idmap, dir_fuse_inode->backing_inode,
258 backing_dentry, fci->mode, true);
259 if (err)
260 goto out;
261
262 if (fuse_entry->backing_path.dentry)
263 path_put(&fuse_entry->backing_path);
264 fuse_entry->backing_path = (struct path) {
265 .mnt = dir_fuse_dentry->backing_path.mnt,
266 .dentry = backing_dentry,
267 };
268 path_get(&fuse_entry->backing_path);
269
270 if (d_inode)
271 target_nodeid = get_fuse_inode(d_inode)->nodeid;
272
273 inode = fuse_iget_backing(dir->i_sb, target_nodeid,
274 fuse_entry->backing_path.dentry->d_inode);
275 if (!inode) {
276 err = -EIO;
277 goto out;
278 }
279
280 if (get_fuse_inode(inode)->bpf)
281 bpf_prog_put(get_fuse_inode(inode)->bpf);
282 get_fuse_inode(inode)->bpf = fuse_entry->bpf;
283 fuse_entry->bpf = NULL;
284
285 newent = d_splice_alias(inode, entry);
286 if (IS_ERR(newent)) {
287 err = PTR_ERR(newent);
288 goto out;
289 }
290
291 inode = NULL;
292 entry = newent ? newent : entry;
293 err = finish_open(file, entry, fuse_open_file_backing);
294
295 out:
296 iput(inode);
297 dput(backing_dentry);
298 return err;
299 }
300
fuse_create_open_finalize(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,struct file * file,unsigned int flags,umode_t mode)301 void *fuse_create_open_finalize(
302 struct fuse_bpf_args *fa,
303 struct inode *dir, struct dentry *entry,
304 struct file *file, unsigned int flags, umode_t mode)
305 {
306 struct fuse_file *ff = file->private_data;
307 struct fuse_inode *fi = get_fuse_inode(file->f_inode);
308 struct fuse_entry_out *feo = fa->out_args[0].value;
309 struct fuse_open_out *foo = fa->out_args[1].value;
310
311 if (fi)
312 fi->nodeid = feo->nodeid;
313 if (ff)
314 ff->fh = foo->fh;
315 return 0;
316 }
317
fuse_release_initialize(struct fuse_bpf_args * fa,struct fuse_release_in * fri,struct inode * inode,struct fuse_file * ff)318 int fuse_release_initialize(struct fuse_bpf_args *fa, struct fuse_release_in *fri,
319 struct inode *inode, struct fuse_file *ff)
320 {
321 /* Always put backing file whatever bpf/userspace says */
322 if (ff->backing_file) {
323 fput(ff->backing_file);
324 }
325
326 *fri = (struct fuse_release_in) {
327 .fh = ff->fh,
328 };
329
330 *fa = (struct fuse_bpf_args) {
331 .nodeid = get_fuse_inode(inode)->nodeid,
332 .opcode = S_ISDIR(inode->i_mode) ? FUSE_RELEASEDIR
333 : FUSE_RELEASE,
334 .in_numargs = 1,
335 .in_args[0].size = sizeof(*fri),
336 .in_args[0].value = fri,
337 };
338
339 return 0;
340 }
341
fuse_release_backing(struct fuse_bpf_args * fa,struct inode * inode,struct fuse_file * ff)342 int fuse_release_backing(struct fuse_bpf_args *fa,
343 struct inode *inode, struct fuse_file *ff)
344 {
345 return 0;
346 }
347
fuse_release_finalize(struct fuse_bpf_args * fa,struct inode * inode,struct fuse_file * ff)348 void *fuse_release_finalize(struct fuse_bpf_args *fa,
349 struct inode *inode, struct fuse_file *ff)
350 {
351 return NULL;
352 }
353
fuse_flush_initialize(struct fuse_bpf_args * fa,struct fuse_flush_in * ffi,struct file * file,fl_owner_t id)354 int fuse_flush_initialize(struct fuse_bpf_args *fa, struct fuse_flush_in *ffi,
355 struct file *file, fl_owner_t id)
356 {
357 struct fuse_file *fuse_file = file->private_data;
358
359 *ffi = (struct fuse_flush_in) {
360 .fh = fuse_file->fh,
361 };
362
363 *fa = (struct fuse_bpf_args) {
364 .nodeid = get_node_id(file->f_inode),
365 .opcode = FUSE_FLUSH,
366 .in_numargs = 1,
367 .in_args[0].size = sizeof(*ffi),
368 .in_args[0].value = ffi,
369 .flags = FUSE_BPF_FORCE,
370 };
371
372 return 0;
373 }
374
fuse_flush_backing(struct fuse_bpf_args * fa,struct file * file,fl_owner_t id)375 int fuse_flush_backing(struct fuse_bpf_args *fa, struct file *file, fl_owner_t id)
376 {
377 struct fuse_file *fuse_file = file->private_data;
378 struct file *backing_file = fuse_file->backing_file;
379
380 if (backing_file->f_op->flush)
381 return backing_file->f_op->flush(backing_file, id);
382 return 0;
383 }
384
fuse_flush_finalize(struct fuse_bpf_args * fa,struct file * file,fl_owner_t id)385 void *fuse_flush_finalize(struct fuse_bpf_args *fa, struct file *file, fl_owner_t id)
386 {
387 return NULL;
388 }
389
fuse_lseek_initialize(struct fuse_bpf_args * fa,struct fuse_lseek_io * flio,struct file * file,loff_t offset,int whence)390 int fuse_lseek_initialize(struct fuse_bpf_args *fa, struct fuse_lseek_io *flio,
391 struct file *file, loff_t offset, int whence)
392 {
393 struct fuse_file *fuse_file = file->private_data;
394
395 flio->fli = (struct fuse_lseek_in) {
396 .fh = fuse_file->fh,
397 .offset = offset,
398 .whence = whence,
399 };
400
401 *fa = (struct fuse_bpf_args) {
402 .nodeid = get_node_id(file->f_inode),
403 .opcode = FUSE_LSEEK,
404 .in_numargs = 1,
405 .in_args[0].size = sizeof(flio->fli),
406 .in_args[0].value = &flio->fli,
407 .out_numargs = 1,
408 .out_args[0].size = sizeof(flio->flo),
409 .out_args[0].value = &flio->flo,
410 };
411
412 return 0;
413 }
414
fuse_lseek_backing(struct fuse_bpf_args * fa,struct file * file,loff_t offset,int whence)415 int fuse_lseek_backing(struct fuse_bpf_args *fa, struct file *file, loff_t offset, int whence)
416 {
417 const struct fuse_lseek_in *fli = fa->in_args[0].value;
418 struct fuse_lseek_out *flo = fa->out_args[0].value;
419 struct fuse_file *fuse_file = file->private_data;
420 struct file *backing_file = fuse_file->backing_file;
421 loff_t ret;
422
423 if (offset == 0) {
424 if (whence == SEEK_CUR) {
425 flo->offset = file->f_pos;
426 return 0;
427 }
428
429 if (whence == SEEK_SET) {
430 flo->offset = vfs_setpos(file, 0, 0);
431 return 0;
432 }
433 }
434
435 inode_lock(file->f_inode);
436 backing_file->f_pos = file->f_pos;
437 ret = vfs_llseek(backing_file, fli->offset, fli->whence);
438
439 if (!IS_ERR(ERR_PTR(ret))) {
440 flo->offset = ret;
441 ret = 0;
442 }
443 inode_unlock(file->f_inode);
444 return ret;
445 }
446
fuse_lseek_finalize(struct fuse_bpf_args * fa,struct file * file,loff_t offset,int whence)447 void *fuse_lseek_finalize(struct fuse_bpf_args *fa, struct file *file, loff_t offset, int whence)
448 {
449 struct fuse_lseek_out *flo = fa->out_args[0].value;
450
451 if (!fa->error_in)
452 file->f_pos = flo->offset;
453 return ERR_PTR(flo->offset);
454 }
455
fuse_copy_file_range_initialize(struct fuse_bpf_args * fa,struct fuse_copy_file_range_io * fcf,struct file * file_in,loff_t pos_in,struct file * file_out,loff_t pos_out,size_t len,unsigned int flags)456 int fuse_copy_file_range_initialize(struct fuse_bpf_args *fa, struct fuse_copy_file_range_io *fcf,
457 struct file *file_in, loff_t pos_in, struct file *file_out,
458 loff_t pos_out, size_t len, unsigned int flags)
459 {
460 struct fuse_file *fuse_file_in = file_in->private_data;
461 struct fuse_file *fuse_file_out = file_out->private_data;
462
463
464 fcf->fci = (struct fuse_copy_file_range_in) {
465 .fh_in = fuse_file_in->fh,
466 .off_in = pos_in,
467 .nodeid_out = fuse_file_out->nodeid,
468 .fh_out = fuse_file_out->fh,
469 .off_out = pos_out,
470 .len = len,
471 .flags = flags,
472 };
473
474 *fa = (struct fuse_bpf_args) {
475 .nodeid = get_node_id(file_in->f_inode),
476 .opcode = FUSE_COPY_FILE_RANGE,
477 .in_numargs = 1,
478 .in_args[0].size = sizeof(fcf->fci),
479 .in_args[0].value = &fcf->fci,
480 .out_numargs = 1,
481 .out_args[0].size = sizeof(fcf->fwo),
482 .out_args[0].value = &fcf->fwo,
483 };
484
485 return 0;
486 }
487
fuse_copy_file_range_backing(struct fuse_bpf_args * fa,struct file * file_in,loff_t pos_in,struct file * file_out,loff_t pos_out,size_t len,unsigned int flags)488 int fuse_copy_file_range_backing(struct fuse_bpf_args *fa, struct file *file_in, loff_t pos_in,
489 struct file *file_out, loff_t pos_out, size_t len,
490 unsigned int flags)
491 {
492 const struct fuse_copy_file_range_in *fci = fa->in_args[0].value;
493 struct fuse_file *fuse_file_in = file_in->private_data;
494 struct file *backing_file_in = fuse_file_in->backing_file;
495 struct fuse_file *fuse_file_out = file_out->private_data;
496 struct file *backing_file_out = fuse_file_out->backing_file;
497
498 /* TODO: Handle changing of in/out files */
499 if (backing_file_out)
500 return vfs_copy_file_range(backing_file_in, fci->off_in, backing_file_out,
501 fci->off_out, fci->len, fci->flags);
502 return -EXDEV;
503 }
504
fuse_copy_file_range_finalize(struct fuse_bpf_args * fa,struct file * file_in,loff_t pos_in,struct file * file_out,loff_t pos_out,size_t len,unsigned int flags)505 void *fuse_copy_file_range_finalize(struct fuse_bpf_args *fa, struct file *file_in, loff_t pos_in,
506 struct file *file_out, loff_t pos_out, size_t len,
507 unsigned int flags)
508 {
509 return NULL;
510 }
511
fuse_fsync_initialize(struct fuse_bpf_args * fa,struct fuse_fsync_in * ffi,struct file * file,loff_t start,loff_t end,int datasync)512 int fuse_fsync_initialize(struct fuse_bpf_args *fa, struct fuse_fsync_in *ffi,
513 struct file *file, loff_t start, loff_t end, int datasync)
514 {
515 struct fuse_file *fuse_file = file->private_data;
516
517 *ffi = (struct fuse_fsync_in) {
518 .fh = fuse_file->fh,
519 .fsync_flags = datasync ? FUSE_FSYNC_FDATASYNC : 0,
520 };
521
522 *fa = (struct fuse_bpf_args) {
523 .nodeid = get_fuse_inode(file->f_inode)->nodeid,
524 .opcode = FUSE_FSYNC,
525 .in_numargs = 1,
526 .in_args[0].size = sizeof(*ffi),
527 .in_args[0].value = ffi,
528 .flags = FUSE_BPF_FORCE,
529 };
530
531 return 0;
532 }
533
fuse_fsync_backing(struct fuse_bpf_args * fa,struct file * file,loff_t start,loff_t end,int datasync)534 int fuse_fsync_backing(struct fuse_bpf_args *fa,
535 struct file *file, loff_t start, loff_t end, int datasync)
536 {
537 struct fuse_file *fuse_file = file->private_data;
538 struct file *backing_file = fuse_file->backing_file;
539 const struct fuse_fsync_in *ffi = fa->in_args[0].value;
540 int new_datasync = (ffi->fsync_flags & FUSE_FSYNC_FDATASYNC) ? 1 : 0;
541
542 return vfs_fsync(backing_file, new_datasync);
543 }
544
fuse_fsync_finalize(struct fuse_bpf_args * fa,struct file * file,loff_t start,loff_t end,int datasync)545 void *fuse_fsync_finalize(struct fuse_bpf_args *fa,
546 struct file *file, loff_t start, loff_t end, int datasync)
547 {
548 return NULL;
549 }
550
fuse_dir_fsync_initialize(struct fuse_bpf_args * fa,struct fuse_fsync_in * ffi,struct file * file,loff_t start,loff_t end,int datasync)551 int fuse_dir_fsync_initialize(struct fuse_bpf_args *fa, struct fuse_fsync_in *ffi,
552 struct file *file, loff_t start, loff_t end, int datasync)
553 {
554 struct fuse_file *fuse_file = file->private_data;
555
556 *ffi = (struct fuse_fsync_in) {
557 .fh = fuse_file->fh,
558 .fsync_flags = datasync ? FUSE_FSYNC_FDATASYNC : 0,
559 };
560
561 *fa = (struct fuse_bpf_args) {
562 .nodeid = get_fuse_inode(file->f_inode)->nodeid,
563 .opcode = FUSE_FSYNCDIR,
564 .in_numargs = 1,
565 .in_args[0].size = sizeof(*ffi),
566 .in_args[0].value = ffi,
567 .flags = FUSE_BPF_FORCE,
568 };
569
570 return 0;
571 }
572
fuse_getxattr_initialize(struct fuse_bpf_args * fa,struct fuse_getxattr_io * fgio,struct dentry * dentry,const char * name,void * value,size_t size)573 int fuse_getxattr_initialize(struct fuse_bpf_args *fa,
574 struct fuse_getxattr_io *fgio,
575 struct dentry *dentry, const char *name, void *value,
576 size_t size)
577 {
578 *fgio = (struct fuse_getxattr_io) {
579 .fgi.size = size,
580 };
581
582 *fa = (struct fuse_bpf_args) {
583 .nodeid = get_fuse_inode(dentry->d_inode)->nodeid,
584 .opcode = FUSE_GETXATTR,
585 .in_numargs = 2,
586 .out_numargs = 1,
587 .in_args[0] = (struct fuse_bpf_in_arg) {
588 .size = sizeof(fgio->fgi),
589 .value = &fgio->fgi,
590 },
591 .in_args[1] = (struct fuse_bpf_in_arg) {
592 .size = strlen(name) + 1,
593 .value = name,
594 },
595 .flags = size ? FUSE_BPF_OUT_ARGVAR : 0,
596 .out_args[0].size = size ? size : sizeof(fgio->fgo),
597 .out_args[0].value = size ? value : &fgio->fgo,
598 };
599 return 0;
600 }
601
fuse_getxattr_backing(struct fuse_bpf_args * fa,struct dentry * dentry,const char * name,void * value,size_t size)602 int fuse_getxattr_backing(struct fuse_bpf_args *fa,
603 struct dentry *dentry, const char *name, void *value,
604 size_t size)
605 {
606 ssize_t ret = vfs_getxattr(&nop_mnt_idmap,
607 get_fuse_dentry(dentry)->backing_path.dentry,
608 fa->in_args[1].value, value, size);
609
610 if (fa->flags & FUSE_BPF_OUT_ARGVAR)
611 fa->out_args[0].size = ret;
612 else
613 ((struct fuse_getxattr_out *)fa->out_args[0].value)->size = ret;
614
615 return 0;
616 }
617
fuse_getxattr_finalize(struct fuse_bpf_args * fa,struct dentry * dentry,const char * name,void * value,size_t size)618 void *fuse_getxattr_finalize(struct fuse_bpf_args *fa,
619 struct dentry *dentry, const char *name, void *value,
620 size_t size)
621 {
622 struct fuse_getxattr_out *fgo;
623
624 if (fa->flags & FUSE_BPF_OUT_ARGVAR)
625 return ERR_PTR(fa->out_args[0].size);
626
627 fgo = fa->out_args[0].value;
628
629 return ERR_PTR(fgo->size);
630
631 }
632
fuse_listxattr_initialize(struct fuse_bpf_args * fa,struct fuse_getxattr_io * fgio,struct dentry * dentry,char * list,size_t size)633 int fuse_listxattr_initialize(struct fuse_bpf_args *fa,
634 struct fuse_getxattr_io *fgio,
635 struct dentry *dentry, char *list, size_t size)
636 {
637 *fgio = (struct fuse_getxattr_io){
638 .fgi.size = size,
639 };
640
641 *fa = (struct fuse_bpf_args){
642 .nodeid = get_fuse_inode(dentry->d_inode)->nodeid,
643 .opcode = FUSE_LISTXATTR,
644 .in_numargs = 1,
645 .out_numargs = 1,
646 .in_args[0] =
647 (struct fuse_bpf_in_arg){
648 .size = sizeof(fgio->fgi),
649 .value = &fgio->fgi,
650 },
651 .flags = size ? FUSE_BPF_OUT_ARGVAR : 0,
652 .out_args[0].size = size ? size : sizeof(fgio->fgo),
653 .out_args[0].value = size ? (void *)list : &fgio->fgo,
654 };
655
656 return 0;
657 }
658
fuse_listxattr_backing(struct fuse_bpf_args * fa,struct dentry * dentry,char * list,size_t size)659 int fuse_listxattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry,
660 char *list, size_t size)
661 {
662 ssize_t ret =
663 vfs_listxattr(get_fuse_dentry(dentry)->backing_path.dentry,
664 list, size);
665
666 if (ret < 0)
667 return ret;
668
669 if (fa->flags & FUSE_BPF_OUT_ARGVAR)
670 fa->out_args[0].size = ret;
671 else
672 ((struct fuse_getxattr_out *)fa->out_args[0].value)->size = ret;
673
674 return ret;
675 }
676
fuse_listxattr_finalize(struct fuse_bpf_args * fa,struct dentry * dentry,char * list,size_t size)677 void *fuse_listxattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry,
678 char *list, size_t size)
679 {
680 struct fuse_getxattr_out *fgo;
681
682 if (fa->error_in)
683 return NULL;
684
685 if (fa->flags & FUSE_BPF_OUT_ARGVAR)
686 return ERR_PTR(fa->out_args[0].size);
687
688 fgo = fa->out_args[0].value;
689 return ERR_PTR(fgo->size);
690 }
691
fuse_setxattr_initialize(struct fuse_bpf_args * fa,struct fuse_setxattr_in * fsxi,struct dentry * dentry,const char * name,const void * value,size_t size,int flags)692 int fuse_setxattr_initialize(struct fuse_bpf_args *fa,
693 struct fuse_setxattr_in *fsxi,
694 struct dentry *dentry, const char *name,
695 const void *value, size_t size, int flags)
696 {
697 *fsxi = (struct fuse_setxattr_in) {
698 .size = size,
699 .flags = flags,
700 };
701
702 *fa = (struct fuse_bpf_args) {
703 .nodeid = get_fuse_inode(dentry->d_inode)->nodeid,
704 .opcode = FUSE_SETXATTR,
705 .in_numargs = 3,
706 .in_args[0] = (struct fuse_bpf_in_arg) {
707 .size = sizeof(*fsxi),
708 .value = fsxi,
709 },
710 .in_args[1] = (struct fuse_bpf_in_arg) {
711 .size = strlen(name) + 1,
712 .value = name,
713 },
714 .in_args[2] = (struct fuse_bpf_in_arg) {
715 .size = size,
716 .value = value,
717 },
718 };
719
720 return 0;
721 }
722
fuse_setxattr_backing(struct fuse_bpf_args * fa,struct dentry * dentry,const char * name,const void * value,size_t size,int flags)723 int fuse_setxattr_backing(struct fuse_bpf_args *fa, struct dentry *dentry,
724 const char *name, const void *value, size_t size,
725 int flags)
726 {
727 return vfs_setxattr(&nop_mnt_idmap,
728 get_fuse_dentry(dentry)->backing_path.dentry, name,
729 value, size, flags);
730 }
731
fuse_setxattr_finalize(struct fuse_bpf_args * fa,struct dentry * dentry,const char * name,const void * value,size_t size,int flags)732 void *fuse_setxattr_finalize(struct fuse_bpf_args *fa, struct dentry *dentry,
733 const char *name, const void *value, size_t size,
734 int flags)
735 {
736 return NULL;
737 }
738
fuse_removexattr_initialize(struct fuse_bpf_args * fa,struct fuse_dummy_io * unused,struct dentry * dentry,const char * name)739 int fuse_removexattr_initialize(struct fuse_bpf_args *fa,
740 struct fuse_dummy_io *unused,
741 struct dentry *dentry, const char *name)
742 {
743 *fa = (struct fuse_bpf_args) {
744 .nodeid = get_fuse_inode(dentry->d_inode)->nodeid,
745 .opcode = FUSE_REMOVEXATTR,
746 .in_numargs = 1,
747 .in_args[0] = (struct fuse_bpf_in_arg) {
748 .size = strlen(name) + 1,
749 .value = name,
750 },
751 };
752
753 return 0;
754 }
755
fuse_removexattr_backing(struct fuse_bpf_args * fa,struct dentry * dentry,const char * name)756 int fuse_removexattr_backing(struct fuse_bpf_args *fa,
757 struct dentry *dentry, const char *name)
758 {
759 struct path *backing_path =
760 &get_fuse_dentry(dentry)->backing_path;
761
762 /* TODO account for changes of the name by prefilter */
763 return vfs_removexattr(&nop_mnt_idmap, backing_path->dentry, name);
764 }
765
fuse_removexattr_finalize(struct fuse_bpf_args * fa,struct dentry * dentry,const char * name)766 void *fuse_removexattr_finalize(struct fuse_bpf_args *fa,
767 struct dentry *dentry, const char *name)
768 {
769 return NULL;
770 }
771
fuse_bpf_aio_put(struct fuse_bpf_aio_req * aio_req)772 static inline void fuse_bpf_aio_put(struct fuse_bpf_aio_req *aio_req)
773 {
774 if (refcount_dec_and_test(&aio_req->ref))
775 kmem_cache_free(fuse_bpf_aio_request_cachep, aio_req);
776 }
777
fuse_bpf_aio_cleanup_handler(struct fuse_bpf_aio_req * aio_req)778 static void fuse_bpf_aio_cleanup_handler(struct fuse_bpf_aio_req *aio_req)
779 {
780 struct kiocb *iocb = &aio_req->iocb;
781 struct kiocb *iocb_orig = aio_req->iocb_orig;
782
783 if (iocb->ki_flags & IOCB_WRITE) {
784 kiocb_end_write(iocb);
785 fuse_copyattr(iocb_orig->ki_filp, iocb->ki_filp);
786 }
787 iocb_orig->ki_pos = iocb->ki_pos;
788 fuse_bpf_aio_put(aio_req);
789 }
790
fuse_bpf_aio_rw_complete(struct kiocb * iocb,long res)791 static void fuse_bpf_aio_rw_complete(struct kiocb *iocb, long res)
792 {
793 struct fuse_bpf_aio_req *aio_req =
794 container_of(iocb, struct fuse_bpf_aio_req, iocb);
795 struct kiocb *iocb_orig = aio_req->iocb_orig;
796
797 fuse_bpf_aio_cleanup_handler(aio_req);
798 iocb_orig->ki_complete(iocb_orig, res);
799 }
800
801
fuse_file_read_iter_initialize(struct fuse_bpf_args * fa,struct fuse_file_read_iter_io * fri,struct kiocb * iocb,struct iov_iter * to)802 int fuse_file_read_iter_initialize(
803 struct fuse_bpf_args *fa, struct fuse_file_read_iter_io *fri,
804 struct kiocb *iocb, struct iov_iter *to)
805 {
806 struct file *file = iocb->ki_filp;
807 struct fuse_file *ff = file->private_data;
808
809 fri->fri = (struct fuse_read_in) {
810 .fh = ff->fh,
811 .offset = iocb->ki_pos,
812 .size = to->count,
813 };
814
815 fri->frio = (struct fuse_read_iter_out) {
816 .ret = fri->fri.size,
817 };
818
819 /* TODO we can't assume 'to' is a kvec */
820 /* TODO we also can't assume the vector has only one component */
821 *fa = (struct fuse_bpf_args) {
822 .opcode = FUSE_READ,
823 .nodeid = ff->nodeid,
824 .in_numargs = 1,
825 .in_args[0].size = sizeof(fri->fri),
826 .in_args[0].value = &fri->fri,
827 .out_numargs = 1,
828 .out_args[0].size = sizeof(fri->frio),
829 .out_args[0].value = &fri->frio,
830 /*
831 * TODO Design this properly.
832 * Possible approach: do not pass buf to bpf
833 * If going to userland, do a deep copy
834 * For extra credit, do that to/from the vector, rather than
835 * making an extra copy in the kernel
836 */
837 };
838
839 return 0;
840 }
841
fuse_file_read_iter_backing(struct fuse_bpf_args * fa,struct kiocb * iocb,struct iov_iter * to)842 int fuse_file_read_iter_backing(struct fuse_bpf_args *fa,
843 struct kiocb *iocb, struct iov_iter *to)
844 {
845 struct fuse_read_iter_out *frio = fa->out_args[0].value;
846 struct file *file = iocb->ki_filp;
847 struct fuse_file *ff = file->private_data;
848 ssize_t ret;
849
850 if (!iov_iter_count(to))
851 return 0;
852
853 if ((iocb->ki_flags & IOCB_DIRECT) &&
854 (!ff->backing_file->f_mapping->a_ops ||
855 !ff->backing_file->f_mapping->a_ops->direct_IO))
856 return -EINVAL;
857
858 /* TODO This just plain ignores any change to fuse_read_in */
859 if (is_sync_kiocb(iocb)) {
860 ret = vfs_iter_read(ff->backing_file, to, &iocb->ki_pos,
861 iocb->ki_flags & FUSE_BPF_IOCB_MASK);
862 } else {
863 struct fuse_bpf_aio_req *aio_req;
864
865 ret = -ENOMEM;
866 aio_req = kmem_cache_zalloc(fuse_bpf_aio_request_cachep, GFP_KERNEL);
867 if (!aio_req)
868 goto out;
869
870 aio_req->iocb_orig = iocb;
871 kiocb_clone(&aio_req->iocb, iocb, ff->backing_file);
872 aio_req->iocb.ki_complete = fuse_bpf_aio_rw_complete;
873 refcount_set(&aio_req->ref, 2);
874 ret = vfs_iocb_iter_read(ff->backing_file, &aio_req->iocb, to);
875 fuse_bpf_aio_put(aio_req);
876 if (ret != -EIOCBQUEUED)
877 fuse_bpf_aio_cleanup_handler(aio_req);
878 }
879
880 frio->ret = ret;
881
882 /* TODO Need to point value at the buffer for post-modification */
883
884 out:
885 fuse_file_accessed(file, ff->backing_file);
886
887 return ret;
888 }
889
fuse_file_read_iter_finalize(struct fuse_bpf_args * fa,struct kiocb * iocb,struct iov_iter * to)890 void *fuse_file_read_iter_finalize(struct fuse_bpf_args *fa,
891 struct kiocb *iocb, struct iov_iter *to)
892 {
893 struct fuse_read_iter_out *frio = fa->out_args[0].value;
894
895 return ERR_PTR(frio->ret);
896 }
897
fuse_file_write_iter_initialize(struct fuse_bpf_args * fa,struct fuse_file_write_iter_io * fwio,struct kiocb * iocb,struct iov_iter * from)898 int fuse_file_write_iter_initialize(
899 struct fuse_bpf_args *fa, struct fuse_file_write_iter_io *fwio,
900 struct kiocb *iocb, struct iov_iter *from)
901 {
902 struct file *file = iocb->ki_filp;
903 struct fuse_file *ff = file->private_data;
904
905 *fwio = (struct fuse_file_write_iter_io) {
906 .fwi.fh = ff->fh,
907 .fwi.offset = iocb->ki_pos,
908 .fwi.size = from->count,
909 };
910
911 /* TODO we can't assume 'from' is a kvec */
912 *fa = (struct fuse_bpf_args) {
913 .opcode = FUSE_WRITE,
914 .nodeid = ff->nodeid,
915 .in_numargs = 2,
916 .in_args[0].size = sizeof(fwio->fwi),
917 .in_args[0].value = &fwio->fwi,
918 .in_args[1].size = fwio->fwi.size,
919 .in_args[1].value = iov_iter_is_kvec(from)
920 ? from->kvec->iov_base : NULL,
921 .out_numargs = 1,
922 .out_args[0].size = sizeof(fwio->fwio),
923 .out_args[0].value = &fwio->fwio,
924 };
925
926 return 0;
927 }
928
fuse_file_write_iter_backing(struct fuse_bpf_args * fa,struct kiocb * iocb,struct iov_iter * from)929 int fuse_file_write_iter_backing(struct fuse_bpf_args *fa,
930 struct kiocb *iocb, struct iov_iter *from)
931 {
932 struct file *file = iocb->ki_filp;
933 struct fuse_file *ff = file->private_data;
934 struct fuse_write_iter_out *fwio = fa->out_args[0].value;
935 ssize_t ret;
936
937 if (!iov_iter_count(from))
938 return 0;
939
940 /* TODO This just plain ignores any change to fuse_write_in */
941 /* TODO uint32_t seems smaller than ssize_t.... right? */
942 inode_lock(file_inode(file));
943
944 fuse_copyattr(file, ff->backing_file);
945
946 if (is_sync_kiocb(iocb)) {
947 ret = vfs_iter_write(ff->backing_file, from, &iocb->ki_pos,
948 iocb->ki_flags & FUSE_BPF_IOCB_MASK);
949
950 /* Must reflect change in size of backing file to upper file */
951 if (ret > 0)
952 fuse_copyattr(file, ff->backing_file);
953 } else {
954 struct fuse_bpf_aio_req *aio_req;
955
956 ret = -ENOMEM;
957 aio_req = kmem_cache_zalloc(fuse_bpf_aio_request_cachep, GFP_KERNEL);
958 if (!aio_req)
959 goto out;
960
961 aio_req->iocb_orig = iocb;
962 kiocb_clone(&aio_req->iocb, iocb, ff->backing_file);
963 aio_req->iocb.ki_complete = fuse_bpf_aio_rw_complete;
964 refcount_set(&aio_req->ref, 2);
965 ret = vfs_iocb_iter_write(ff->backing_file, &aio_req->iocb, from);
966 fuse_bpf_aio_put(aio_req);
967 if (ret != -EIOCBQUEUED)
968 fuse_bpf_aio_cleanup_handler(aio_req);
969 }
970
971 out:
972 inode_unlock(file_inode(file));
973 fwio->ret = ret;
974 if (ret < 0)
975 return ret;
976 return 0;
977 }
978
fuse_file_write_iter_finalize(struct fuse_bpf_args * fa,struct kiocb * iocb,struct iov_iter * from)979 void *fuse_file_write_iter_finalize(struct fuse_bpf_args *fa,
980 struct kiocb *iocb, struct iov_iter *from)
981 {
982 struct fuse_write_iter_out *fwio = fa->out_args[0].value;
983
984 return ERR_PTR(fwio->ret);
985 }
986
fuse_splice_read_backing(struct file * in,loff_t * ppos,struct pipe_inode_info * pipe,size_t len,unsigned long flags)987 ssize_t fuse_splice_read_backing(struct file *in, loff_t *ppos,
988 struct pipe_inode_info *pipe, size_t len, unsigned long flags)
989 {
990 struct fuse_file *ff = in->private_data;
991 ssize_t ret;
992
993 ret = vfs_splice_read(ff->backing_file, ppos, pipe, len, flags);
994 fuse_file_accessed(in, ff->backing_file);
995
996 return ret;
997 }
998
fuse_splice_write_backing(struct pipe_inode_info * pipe,struct file * out,loff_t * ppos,size_t len,unsigned long flags)999 ssize_t fuse_splice_write_backing(struct pipe_inode_info *pipe,
1000 struct file *out, loff_t *ppos, size_t len, unsigned long flags)
1001 {
1002 ssize_t ret;
1003 struct fuse_file *ff = out->private_data;
1004
1005 inode_lock(file_inode(out));
1006 file_start_write(ff->backing_file);
1007 ret = iter_file_splice_write(pipe, ff->backing_file, ppos, len, flags);
1008 file_end_write(ff->backing_file);
1009 if (ret > 0)
1010 fuse_copyattr(out, ff->backing_file);
1011 inode_unlock(file_inode(out));
1012 return ret;
1013 }
1014
fuse_backing_ioctl(struct file * file,unsigned int command,unsigned long arg,int flags)1015 long fuse_backing_ioctl(struct file *file, unsigned int command, unsigned long arg, int flags)
1016 {
1017 struct fuse_file *ff = file->private_data;
1018 long ret;
1019
1020 if (flags & FUSE_IOCTL_COMPAT)
1021 ret = -ENOTTY;
1022 else
1023 ret = vfs_ioctl(ff->backing_file, command, arg);
1024
1025 return ret;
1026 }
1027
fuse_file_flock_backing(struct file * file,int cmd,struct file_lock * fl)1028 int fuse_file_flock_backing(struct file *file, int cmd, struct file_lock *fl)
1029 {
1030 struct fuse_file *ff = file->private_data;
1031 struct file *backing_file = ff->backing_file;
1032 int error;
1033
1034 fl->c.flc_file = backing_file;
1035 if (backing_file->f_op->flock)
1036 error = backing_file->f_op->flock(backing_file, cmd, fl);
1037 else
1038 error = locks_lock_file_wait(backing_file, fl);
1039 return error;
1040 }
1041
fuse_backing_mmap(struct file * file,struct vm_area_struct * vma)1042 ssize_t fuse_backing_mmap(struct file *file, struct vm_area_struct *vma)
1043 {
1044 int ret;
1045 struct fuse_file *ff = file->private_data;
1046 struct inode *fuse_inode = file_inode(file);
1047 struct file *backing_file = ff->backing_file;
1048 struct inode *backing_inode = file_inode(backing_file);
1049 struct timespec64 fuse_inode_ctime, backing_inode_ctime;
1050 struct timespec64 fuse_inode_mtime, backing_inode_mtime;
1051
1052 if (!backing_file->f_op->mmap)
1053 return -ENODEV;
1054
1055 if (WARN_ON(file != vma->vm_file))
1056 return -EIO;
1057
1058 vma->vm_file = get_file(backing_file);
1059
1060 ret = call_mmap(vma->vm_file, vma);
1061
1062 if (ret)
1063 fput(backing_file);
1064 else
1065 fput(file);
1066
1067 if (file->f_flags & O_NOATIME)
1068 return ret;
1069
1070 fuse_inode_ctime = inode_get_ctime(fuse_inode);
1071 backing_inode_ctime = inode_get_ctime(backing_inode);
1072 fuse_inode_mtime = inode_get_mtime(fuse_inode);
1073 backing_inode_mtime = inode_get_mtime(backing_inode);
1074 if ((!timespec64_equal(&fuse_inode_mtime, &backing_inode_mtime) ||
1075 !timespec64_equal(&fuse_inode_ctime, &backing_inode_ctime))) {
1076 inode_set_mtime_to_ts(fuse_inode, backing_inode_mtime);
1077 inode_set_ctime_to_ts(fuse_inode, backing_inode_ctime);
1078 }
1079 touch_atime(&file->f_path);
1080
1081 return ret;
1082 }
1083
fuse_file_fallocate_initialize(struct fuse_bpf_args * fa,struct fuse_fallocate_in * ffi,struct file * file,int mode,loff_t offset,loff_t length)1084 int fuse_file_fallocate_initialize(struct fuse_bpf_args *fa,
1085 struct fuse_fallocate_in *ffi,
1086 struct file *file, int mode, loff_t offset, loff_t length)
1087 {
1088 struct fuse_file *ff = file->private_data;
1089
1090 *ffi = (struct fuse_fallocate_in) {
1091 .fh = ff->fh,
1092 .offset = offset,
1093 .length = length,
1094 .mode = mode
1095 };
1096
1097 *fa = (struct fuse_bpf_args) {
1098 .opcode = FUSE_FALLOCATE,
1099 .nodeid = ff->nodeid,
1100 .in_numargs = 1,
1101 .in_args[0].size = sizeof(*ffi),
1102 .in_args[0].value = ffi,
1103 };
1104
1105 return 0;
1106 }
1107
fuse_file_fallocate_backing(struct fuse_bpf_args * fa,struct file * file,int mode,loff_t offset,loff_t length)1108 int fuse_file_fallocate_backing(struct fuse_bpf_args *fa,
1109 struct file *file, int mode, loff_t offset, loff_t length)
1110 {
1111 const struct fuse_fallocate_in *ffi = fa->in_args[0].value;
1112 struct fuse_file *ff = file->private_data;
1113
1114 return vfs_fallocate(ff->backing_file, ffi->mode, ffi->offset,
1115 ffi->length);
1116 }
1117
fuse_file_fallocate_finalize(struct fuse_bpf_args * fa,struct file * file,int mode,loff_t offset,loff_t length)1118 void *fuse_file_fallocate_finalize(struct fuse_bpf_args *fa,
1119 struct file *file, int mode, loff_t offset, loff_t length)
1120 {
1121 return NULL;
1122 }
1123
1124 /*******************************************************************************
1125 * Directory operations after here *
1126 ******************************************************************************/
1127
fuse_lookup_initialize(struct fuse_bpf_args * fa,struct fuse_lookup_io * fli,struct inode * dir,struct dentry * entry,unsigned int flags)1128 int fuse_lookup_initialize(struct fuse_bpf_args *fa, struct fuse_lookup_io *fli,
1129 struct inode *dir, struct dentry *entry, unsigned int flags)
1130 {
1131 *fa = (struct fuse_bpf_args) {
1132 .nodeid = get_fuse_inode(dir)->nodeid,
1133 .opcode = FUSE_LOOKUP,
1134 .in_numargs = 1,
1135 .out_numargs = 2,
1136 .flags = FUSE_BPF_OUT_ARGVAR,
1137 .in_args[0] = (struct fuse_bpf_in_arg) {
1138 .size = entry->d_name.len + 1,
1139 .value = entry->d_name.name,
1140 },
1141 .out_args[0] = (struct fuse_bpf_arg) {
1142 .size = sizeof(fli->feo),
1143 .value = &fli->feo,
1144 },
1145 .out_args[1] = (struct fuse_bpf_arg) {
1146 .size = sizeof(fli->feb.out),
1147 .value = &fli->feb.out,
1148 },
1149 };
1150
1151 return 0;
1152 }
1153
fuse_lookup_backing(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,unsigned int flags)1154 int fuse_lookup_backing(struct fuse_bpf_args *fa, struct inode *dir,
1155 struct dentry *entry, unsigned int flags)
1156 {
1157 struct fuse_dentry *fuse_entry = get_fuse_dentry(entry);
1158 struct fuse_dentry *dir_fuse_entry = get_fuse_dentry(entry->d_parent);
1159 struct dentry *dir_backing_entry = dir_fuse_entry->backing_path.dentry;
1160 struct inode *dir_backing_inode = dir_backing_entry->d_inode;
1161 struct dentry *backing_entry;
1162 struct fuse_entry_out *feo = (void *)fa->out_args[0].value;
1163 struct kstat stat;
1164 int err;
1165
1166 inode_lock_nested(dir_backing_inode, I_MUTEX_PARENT);
1167 backing_entry = lookup_one_len(entry->d_name.name, dir_backing_entry,
1168 strlen(entry->d_name.name));
1169 inode_unlock(dir_backing_inode);
1170
1171 if (IS_ERR(backing_entry))
1172 return PTR_ERR(backing_entry);
1173
1174 fuse_entry->backing_path = (struct path) {
1175 .dentry = backing_entry,
1176 .mnt = mntget(dir_fuse_entry->backing_path.mnt),
1177 };
1178
1179 if (d_is_negative(backing_entry)) {
1180 fa->error_in = -ENOENT;
1181 return 0;
1182 }
1183
1184 err = follow_down(&fuse_entry->backing_path, 0);
1185 if (err)
1186 goto err_out;
1187
1188 err = vfs_getattr(&fuse_entry->backing_path, &stat,
1189 STATX_BASIC_STATS, 0);
1190 if (err)
1191 goto err_out;
1192
1193 fuse_stat_to_attr(get_fuse_conn(dir),
1194 backing_entry->d_inode, &stat, &feo->attr);
1195 return 0;
1196
1197 err_out:
1198 path_put(&fuse_entry->backing_path);
1199 fuse_entry->backing_path = (struct path) { };
1200 return err;
1201 }
1202
fuse_handle_backing(struct fuse_entry_bpf * feb,struct inode ** backing_inode,struct path * backing_path)1203 int fuse_handle_backing(struct fuse_entry_bpf *feb, struct inode **backing_inode,
1204 struct path *backing_path)
1205 {
1206 switch (feb->out.backing_action) {
1207 case FUSE_ACTION_KEEP:
1208 /* backing inode/path are added in fuse_lookup_backing */
1209 break;
1210
1211 case FUSE_ACTION_REMOVE:
1212 iput(*backing_inode);
1213 *backing_inode = NULL;
1214 path_put(backing_path);
1215 *backing_path = (struct path) { };
1216 break;
1217
1218 case FUSE_ACTION_REPLACE: {
1219 struct file *backing_file = feb->backing_file;
1220
1221 if (!backing_file)
1222 return -EINVAL;
1223 if (IS_ERR(backing_file))
1224 return PTR_ERR(backing_file);
1225
1226 if (backing_inode)
1227 iput(*backing_inode);
1228 *backing_inode = backing_file->f_inode;
1229 ihold(*backing_inode);
1230
1231 path_put(backing_path);
1232 *backing_path = backing_file->f_path;
1233 path_get(backing_path);
1234 break;
1235 }
1236
1237 default:
1238 return -EINVAL;
1239 }
1240
1241 return 0;
1242 }
1243
fuse_handle_bpf_prog(struct fuse_entry_bpf * feb,struct inode * parent,struct bpf_prog ** bpf)1244 int fuse_handle_bpf_prog(struct fuse_entry_bpf *feb, struct inode *parent,
1245 struct bpf_prog **bpf)
1246 {
1247 struct bpf_prog *new_bpf = NULL;
1248
1249 switch (feb->out.bpf_action) {
1250 case FUSE_ACTION_KEEP: {
1251 /* Parent isn't presented, but we want to keep
1252 * Don't touch bpf program at all in this case
1253 */
1254 if (!parent)
1255 return 0;
1256
1257 new_bpf = get_fuse_inode(parent)->bpf;
1258 if (new_bpf)
1259 bpf_prog_inc(new_bpf);
1260 break;
1261 }
1262
1263 case FUSE_ACTION_REMOVE:
1264 break;
1265
1266 case FUSE_ACTION_REPLACE: {
1267 struct file *bpf_file = feb->bpf_file;
1268
1269 if (!bpf_file)
1270 return -EINVAL;
1271 if (IS_ERR(bpf_file))
1272 return PTR_ERR(bpf_file);
1273
1274 new_bpf = fuse_get_bpf_prog(bpf_file);
1275 if (IS_ERR(new_bpf))
1276 return PTR_ERR(new_bpf);
1277 break;
1278 }
1279
1280 default:
1281 return -EINVAL;
1282 }
1283
1284 /* Cannot change existing program */
1285 if (*bpf) {
1286 if (new_bpf)
1287 bpf_prog_put(new_bpf);
1288 return new_bpf == *bpf ? 0 : -EINVAL;
1289 }
1290
1291 *bpf = new_bpf;
1292 return 0;
1293 }
1294
fuse_lookup_finalize(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,unsigned int flags)1295 struct dentry *fuse_lookup_finalize(struct fuse_bpf_args *fa, struct inode *dir,
1296 struct dentry *entry, unsigned int flags)
1297 {
1298 struct fuse_dentry *fuse_entry;
1299 struct dentry *backing_entry;
1300 struct inode *inode = NULL, *backing_inode;
1301 struct inode *entry_inode = entry->d_inode;
1302 struct fuse_entry_out *feo = fa->out_args[0].value;
1303 struct fuse_entry_bpf_out *febo = fa->out_args[1].value;
1304 struct fuse_entry_bpf *feb = container_of(febo, struct fuse_entry_bpf,
1305 out);
1306 int error = -1;
1307 u64 target_nodeid = 0;
1308 struct dentry *ret = NULL;
1309
1310 fuse_entry = get_fuse_dentry(entry);
1311 if (!fuse_entry) {
1312 ret = ERR_PTR(-EIO);
1313 goto out;
1314 }
1315
1316 backing_entry = fuse_entry->backing_path.dentry;
1317 if (!backing_entry) {
1318 ret = ERR_PTR(-ENOENT);
1319 goto out;
1320 }
1321
1322 if (entry_inode)
1323 target_nodeid = get_fuse_inode(entry_inode)->nodeid;
1324
1325 backing_inode = backing_entry->d_inode;
1326 if (backing_inode)
1327 inode = fuse_iget_backing(dir->i_sb, target_nodeid,
1328 backing_inode);
1329
1330 error = inode ?
1331 fuse_handle_bpf_prog(feb, dir, &get_fuse_inode(inode)->bpf) :
1332 fuse_handle_bpf_prog(feb, dir, &fuse_entry->bpf);
1333 if (error) {
1334 ret = ERR_PTR(error);
1335 goto out;
1336 }
1337
1338 if (inode) {
1339 error = fuse_handle_backing(feb,
1340 &get_fuse_inode(inode)->backing_inode,
1341 &fuse_entry->backing_path);
1342 if (error) {
1343 ret = ERR_PTR(error);
1344 goto out;
1345 }
1346
1347 get_fuse_inode(inode)->nodeid = feo->nodeid;
1348 ret = d_splice_alias(inode, entry);
1349 if (!IS_ERR(ret))
1350 inode = NULL;
1351 }
1352 out:
1353 iput(inode);
1354 if (feb->backing_file)
1355 fput(feb->backing_file);
1356 return ret;
1357 }
1358
fuse_revalidate_backing(struct dentry * entry,unsigned int flags)1359 int fuse_revalidate_backing(struct dentry *entry, unsigned int flags)
1360 {
1361 struct fuse_dentry *fuse_dentry = get_fuse_dentry(entry);
1362 struct dentry *backing_entry = fuse_dentry->backing_path.dentry;
1363
1364 spin_lock(&backing_entry->d_lock);
1365 if (d_unhashed(backing_entry)) {
1366 spin_unlock(&backing_entry->d_lock);
1367 return 0;
1368 }
1369 spin_unlock(&backing_entry->d_lock);
1370
1371 if (unlikely(backing_entry->d_flags & DCACHE_OP_REVALIDATE))
1372 return backing_entry->d_op->d_revalidate(backing_entry, flags);
1373 return 1;
1374 }
1375
fuse_canonical_path_initialize(struct fuse_bpf_args * fa,struct fuse_dummy_io * fdi,const struct path * path,struct path * canonical_path)1376 int fuse_canonical_path_initialize(struct fuse_bpf_args *fa,
1377 struct fuse_dummy_io *fdi,
1378 const struct path *path,
1379 struct path *canonical_path)
1380 {
1381 fa->opcode = FUSE_CANONICAL_PATH;
1382 return 0;
1383 }
1384
fuse_canonical_path_backing(struct fuse_bpf_args * fa,const struct path * path,struct path * canonical_path)1385 int fuse_canonical_path_backing(struct fuse_bpf_args *fa, const struct path *path,
1386 struct path *canonical_path)
1387 {
1388 get_fuse_backing_path(path->dentry, canonical_path);
1389 return 0;
1390 }
1391
fuse_canonical_path_finalize(struct fuse_bpf_args * fa,const struct path * path,struct path * canonical_path)1392 void *fuse_canonical_path_finalize(struct fuse_bpf_args *fa,
1393 const struct path *path,
1394 struct path *canonical_path)
1395 {
1396 return NULL;
1397 }
1398
fuse_mknod_initialize(struct fuse_bpf_args * fa,struct fuse_mknod_in * fmi,struct inode * dir,struct dentry * entry,umode_t mode,dev_t rdev)1399 int fuse_mknod_initialize(
1400 struct fuse_bpf_args *fa, struct fuse_mknod_in *fmi,
1401 struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev)
1402 {
1403 *fmi = (struct fuse_mknod_in) {
1404 .mode = mode,
1405 .rdev = new_encode_dev(rdev),
1406 .umask = current_umask(),
1407 };
1408 *fa = (struct fuse_bpf_args) {
1409 .nodeid = get_node_id(dir),
1410 .opcode = FUSE_MKNOD,
1411 .in_numargs = 2,
1412 .in_args[0] = (struct fuse_bpf_in_arg) {
1413 .size = sizeof(*fmi),
1414 .value = fmi,
1415 },
1416 .in_args[1] = (struct fuse_bpf_in_arg) {
1417 .size = entry->d_name.len + 1,
1418 .value = entry->d_name.name,
1419 },
1420 };
1421
1422 return 0;
1423 }
1424
fuse_mknod_backing(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,umode_t mode,dev_t rdev)1425 int fuse_mknod_backing(
1426 struct fuse_bpf_args *fa,
1427 struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev)
1428 {
1429 int err = 0;
1430 const struct fuse_mknod_in *fmi = fa->in_args[0].value;
1431 struct fuse_inode *fuse_inode = get_fuse_inode(dir);
1432 struct inode *backing_inode = fuse_inode->backing_inode;
1433 struct path backing_path = {};
1434 struct inode *inode = NULL;
1435
1436 //TODO Actually deal with changing the backing entry in mknod
1437 get_fuse_backing_path(entry, &backing_path);
1438 if (!backing_path.dentry)
1439 return -EBADF;
1440
1441 inode_lock_nested(backing_inode, I_MUTEX_PARENT);
1442 mode = fmi->mode;
1443 if (!IS_POSIXACL(backing_inode))
1444 mode &= ~fmi->umask;
1445 err = vfs_mknod(&nop_mnt_idmap, backing_inode, backing_path.dentry, mode,
1446 new_decode_dev(fmi->rdev));
1447 inode_unlock(backing_inode);
1448 if (err)
1449 goto out;
1450 if (d_really_is_negative(backing_path.dentry) ||
1451 unlikely(d_unhashed(backing_path.dentry))) {
1452 err = -EINVAL;
1453 /**
1454 * TODO: overlayfs responds to this situation with a
1455 * lookupOneLen. Should we do that too?
1456 */
1457 goto out;
1458 }
1459 inode = fuse_iget_backing(dir->i_sb, fuse_inode->nodeid, backing_inode);
1460 if (IS_ERR(inode)) {
1461 err = PTR_ERR(inode);
1462 goto out;
1463 }
1464 d_instantiate(entry, inode);
1465 out:
1466 path_put(&backing_path);
1467 return err;
1468 }
1469
fuse_mknod_finalize(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,umode_t mode,dev_t rdev)1470 void *fuse_mknod_finalize(
1471 struct fuse_bpf_args *fa,
1472 struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev)
1473 {
1474 return NULL;
1475 }
1476
fuse_mkdir_initialize(struct fuse_bpf_args * fa,struct fuse_mkdir_in * fmi,struct inode * dir,struct dentry * entry,umode_t mode)1477 int fuse_mkdir_initialize(
1478 struct fuse_bpf_args *fa, struct fuse_mkdir_in *fmi,
1479 struct inode *dir, struct dentry *entry, umode_t mode)
1480 {
1481 *fmi = (struct fuse_mkdir_in) {
1482 .mode = mode,
1483 .umask = current_umask(),
1484 };
1485 *fa = (struct fuse_bpf_args) {
1486 .nodeid = get_node_id(dir),
1487 .opcode = FUSE_MKDIR,
1488 .in_numargs = 2,
1489 .in_args[0] = (struct fuse_bpf_in_arg) {
1490 .size = sizeof(*fmi),
1491 .value = fmi,
1492 },
1493 .in_args[1] = (struct fuse_bpf_in_arg) {
1494 .size = entry->d_name.len + 1,
1495 .value = entry->d_name.name,
1496 },
1497 };
1498
1499 return 0;
1500 }
1501
fuse_mkdir_backing(struct fuse_bpf_args * fa,struct inode * dir_inode,struct dentry * entry,umode_t mode)1502 int fuse_mkdir_backing(
1503 struct fuse_bpf_args *fa,
1504 struct inode *dir_inode, struct dentry *entry, umode_t mode)
1505 {
1506 int err = 0;
1507 const struct fuse_mkdir_in *fmi = fa->in_args[0].value;
1508 struct fuse_inode *dir_fuse_inode = get_fuse_inode(dir_inode);
1509 struct inode *dir_backing_inode = dir_fuse_inode->backing_inode;
1510 struct path backing_path = {};
1511 struct inode *inode = NULL;
1512
1513 //TODO Actually deal with changing the backing entry in mkdir
1514 get_fuse_backing_path(entry, &backing_path);
1515 if (!backing_path.dentry)
1516 return -EBADF;
1517
1518 inode_lock_nested(dir_backing_inode, I_MUTEX_PARENT);
1519 mode = fmi->mode;
1520 if (!IS_POSIXACL(dir_backing_inode))
1521 mode &= ~fmi->umask;
1522 err = vfs_mkdir(&nop_mnt_idmap, dir_backing_inode, backing_path.dentry, mode);
1523 if (err)
1524 goto out;
1525 if (d_really_is_negative(backing_path.dentry) ||
1526 unlikely(d_unhashed(backing_path.dentry))) {
1527 struct dentry *d = lookup_one_len(entry->d_name.name,
1528 backing_path.dentry->d_parent,
1529 entry->d_name.len);
1530
1531 if (IS_ERR(d)) {
1532 err = PTR_ERR(d);
1533 goto out;
1534 }
1535 dput(backing_path.dentry);
1536 backing_path.dentry = d;
1537 }
1538 inode = fuse_iget_backing(dir_inode->i_sb, 0,
1539 backing_path.dentry->d_inode);
1540 if (IS_ERR(inode)) {
1541 err = PTR_ERR(inode);
1542 goto out;
1543 }
1544 d_instantiate(entry, inode);
1545 if (get_fuse_inode(inode)->bpf)
1546 bpf_prog_put(get_fuse_inode(inode)->bpf);
1547 get_fuse_inode(inode)->bpf = get_fuse_dentry(entry)->bpf;
1548 get_fuse_dentry(entry)->bpf = NULL;
1549 out:
1550 inode_unlock(dir_backing_inode);
1551 path_put(&backing_path);
1552 return err;
1553 }
1554
fuse_mkdir_finalize(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,umode_t mode)1555 void *fuse_mkdir_finalize(
1556 struct fuse_bpf_args *fa,
1557 struct inode *dir, struct dentry *entry, umode_t mode)
1558 {
1559 return NULL;
1560 }
1561
fuse_rmdir_initialize(struct fuse_bpf_args * fa,struct fuse_dummy_io * dummy,struct inode * dir,struct dentry * entry)1562 int fuse_rmdir_initialize(
1563 struct fuse_bpf_args *fa, struct fuse_dummy_io *dummy,
1564 struct inode *dir, struct dentry *entry)
1565 {
1566 *fa = (struct fuse_bpf_args) {
1567 .nodeid = get_node_id(dir),
1568 .opcode = FUSE_RMDIR,
1569 .in_numargs = 1,
1570 .in_args[0] = (struct fuse_bpf_in_arg) {
1571 .size = entry->d_name.len + 1,
1572 .value = entry->d_name.name,
1573 },
1574 };
1575
1576 return 0;
1577 }
1578
fuse_rmdir_backing(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry)1579 int fuse_rmdir_backing(
1580 struct fuse_bpf_args *fa,
1581 struct inode *dir, struct dentry *entry)
1582 {
1583 int err = 0;
1584 struct path backing_path = {};
1585 struct dentry *backing_parent_dentry;
1586 struct inode *backing_inode;
1587
1588 /* TODO Actually deal with changing the backing entry in rmdir */
1589 get_fuse_backing_path(entry, &backing_path);
1590 if (!backing_path.dentry)
1591 return -EBADF;
1592
1593 /* TODO Not sure if we should reverify like overlayfs, or get inode from d_parent */
1594 backing_parent_dentry = dget_parent(backing_path.dentry);
1595 backing_inode = d_inode(backing_parent_dentry);
1596
1597 inode_lock_nested(backing_inode, I_MUTEX_PARENT);
1598 err = vfs_rmdir(&nop_mnt_idmap, backing_inode, backing_path.dentry);
1599 inode_unlock(backing_inode);
1600
1601 dput(backing_parent_dentry);
1602 if (!err)
1603 d_drop(entry);
1604 path_put(&backing_path);
1605 return err;
1606 }
1607
fuse_rmdir_finalize(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry)1608 void *fuse_rmdir_finalize(
1609 struct fuse_bpf_args *fa,
1610 struct inode *dir, struct dentry *entry)
1611 {
1612 return NULL;
1613 }
1614
fuse_rename_backing_common(struct inode * olddir,struct dentry * oldent,struct inode * newdir,struct dentry * newent,unsigned int flags)1615 static int fuse_rename_backing_common(
1616 struct inode *olddir, struct dentry *oldent,
1617 struct inode *newdir, struct dentry *newent,
1618 unsigned int flags)
1619 {
1620 int err = 0;
1621 struct path old_backing_path;
1622 struct path new_backing_path;
1623 struct dentry *old_backing_dir_dentry;
1624 struct dentry *old_backing_dentry;
1625 struct dentry *new_backing_dir_dentry;
1626 struct dentry *new_backing_dentry;
1627 struct dentry *trap = NULL;
1628 struct inode *target_inode;
1629 struct renamedata rd;
1630
1631 //TODO Actually deal with changing anything that isn't a flag
1632 get_fuse_backing_path(oldent, &old_backing_path);
1633 if (!old_backing_path.dentry)
1634 return -EBADF;
1635 get_fuse_backing_path(newent, &new_backing_path);
1636 if (!new_backing_path.dentry) {
1637 /*
1638 * TODO A file being moved from a backing path to another
1639 * backing path which is not yet instrumented with FUSE-BPF.
1640 * This may be slow and should be substituted with something
1641 * more clever.
1642 */
1643 err = -EXDEV;
1644 goto put_old_path;
1645 }
1646 if (new_backing_path.mnt != old_backing_path.mnt) {
1647 err = -EXDEV;
1648 goto put_new_path;
1649 }
1650 old_backing_dentry = old_backing_path.dentry;
1651 new_backing_dentry = new_backing_path.dentry;
1652 old_backing_dir_dentry = dget_parent(old_backing_dentry);
1653 new_backing_dir_dentry = dget_parent(new_backing_dentry);
1654 target_inode = d_inode(newent);
1655
1656 trap = lock_rename(old_backing_dir_dentry, new_backing_dir_dentry);
1657 if (trap == old_backing_dentry) {
1658 err = -EINVAL;
1659 goto put_parents;
1660 }
1661 if (trap == new_backing_dentry) {
1662 err = -ENOTEMPTY;
1663 goto put_parents;
1664 }
1665 rd = (struct renamedata) {
1666 .old_mnt_idmap = &nop_mnt_idmap,
1667 .old_dir = d_inode(old_backing_dir_dentry),
1668 .old_dentry = old_backing_dentry,
1669 .new_mnt_idmap = &nop_mnt_idmap,
1670 .new_dir = d_inode(new_backing_dir_dentry),
1671 .new_dentry = new_backing_dentry,
1672 .flags = flags,
1673 };
1674 err = vfs_rename(&rd);
1675 if (err)
1676 goto unlock;
1677 if (target_inode)
1678 fsstack_copy_attr_all(target_inode,
1679 get_fuse_inode(target_inode)->backing_inode);
1680 fsstack_copy_attr_all(d_inode(oldent), d_inode(old_backing_dentry));
1681 unlock:
1682 unlock_rename(old_backing_dir_dentry, new_backing_dir_dentry);
1683 put_parents:
1684 dput(new_backing_dir_dentry);
1685 dput(old_backing_dir_dentry);
1686 put_new_path:
1687 path_put(&new_backing_path);
1688 put_old_path:
1689 path_put(&old_backing_path);
1690 return err;
1691 }
1692
fuse_rename2_initialize(struct fuse_bpf_args * fa,struct fuse_rename2_in * fri,struct inode * olddir,struct dentry * oldent,struct inode * newdir,struct dentry * newent,unsigned int flags)1693 int fuse_rename2_initialize(struct fuse_bpf_args *fa, struct fuse_rename2_in *fri,
1694 struct inode *olddir, struct dentry *oldent,
1695 struct inode *newdir, struct dentry *newent,
1696 unsigned int flags)
1697 {
1698 *fri = (struct fuse_rename2_in) {
1699 .newdir = get_node_id(newdir),
1700 .flags = flags,
1701 };
1702 *fa = (struct fuse_bpf_args) {
1703 .nodeid = get_node_id(olddir),
1704 .opcode = FUSE_RENAME2,
1705 .in_numargs = 3,
1706 .in_args[0] = (struct fuse_bpf_in_arg) {
1707 .size = sizeof(*fri),
1708 .value = fri,
1709 },
1710 .in_args[1] = (struct fuse_bpf_in_arg) {
1711 .size = oldent->d_name.len + 1,
1712 .value = oldent->d_name.name,
1713 },
1714 .in_args[2] = (struct fuse_bpf_in_arg) {
1715 .size = newent->d_name.len + 1,
1716 .value = newent->d_name.name,
1717 },
1718 };
1719
1720 return 0;
1721 }
1722
fuse_rename2_backing(struct fuse_bpf_args * fa,struct inode * olddir,struct dentry * oldent,struct inode * newdir,struct dentry * newent,unsigned int flags)1723 int fuse_rename2_backing(struct fuse_bpf_args *fa,
1724 struct inode *olddir, struct dentry *oldent,
1725 struct inode *newdir, struct dentry *newent,
1726 unsigned int flags)
1727 {
1728 const struct fuse_rename2_in *fri = fa->in_args[0].value;
1729
1730 /* TODO: deal with changing dirs/ents */
1731 return fuse_rename_backing_common(olddir, oldent, newdir, newent, fri->flags);
1732 }
1733
fuse_rename2_finalize(struct fuse_bpf_args * fa,struct inode * olddir,struct dentry * oldent,struct inode * newdir,struct dentry * newent,unsigned int flags)1734 void *fuse_rename2_finalize(struct fuse_bpf_args *fa,
1735 struct inode *olddir, struct dentry *oldent,
1736 struct inode *newdir, struct dentry *newent,
1737 unsigned int flags)
1738 {
1739 return NULL;
1740 }
1741
fuse_rename_initialize(struct fuse_bpf_args * fa,struct fuse_rename_in * fri,struct inode * olddir,struct dentry * oldent,struct inode * newdir,struct dentry * newent)1742 int fuse_rename_initialize(struct fuse_bpf_args *fa, struct fuse_rename_in *fri,
1743 struct inode *olddir, struct dentry *oldent,
1744 struct inode *newdir, struct dentry *newent)
1745 {
1746 *fri = (struct fuse_rename_in) {
1747 .newdir = get_node_id(newdir),
1748 };
1749 *fa = (struct fuse_bpf_args) {
1750 .nodeid = get_node_id(olddir),
1751 .opcode = FUSE_RENAME,
1752 .in_numargs = 3,
1753 .in_args[0] = (struct fuse_bpf_in_arg) {
1754 .size = sizeof(*fri),
1755 .value = fri,
1756 },
1757 .in_args[1] = (struct fuse_bpf_in_arg) {
1758 .size = oldent->d_name.len + 1,
1759 .value = oldent->d_name.name,
1760 },
1761 .in_args[2] = (struct fuse_bpf_in_arg) {
1762 .size = newent->d_name.len + 1,
1763 .value = newent->d_name.name,
1764 },
1765 };
1766
1767 return 0;
1768 }
1769
fuse_rename_backing(struct fuse_bpf_args * fa,struct inode * olddir,struct dentry * oldent,struct inode * newdir,struct dentry * newent)1770 int fuse_rename_backing(struct fuse_bpf_args *fa,
1771 struct inode *olddir, struct dentry *oldent,
1772 struct inode *newdir, struct dentry *newent)
1773 {
1774 /* TODO: deal with changing dirs/ents */
1775 return fuse_rename_backing_common(olddir, oldent, newdir, newent, 0);
1776 }
1777
fuse_rename_finalize(struct fuse_bpf_args * fa,struct inode * olddir,struct dentry * oldent,struct inode * newdir,struct dentry * newent)1778 void *fuse_rename_finalize(struct fuse_bpf_args *fa,
1779 struct inode *olddir, struct dentry *oldent,
1780 struct inode *newdir, struct dentry *newent)
1781 {
1782 return NULL;
1783 }
1784
fuse_unlink_initialize(struct fuse_bpf_args * fa,struct fuse_dummy_io * dummy,struct inode * dir,struct dentry * entry)1785 int fuse_unlink_initialize(
1786 struct fuse_bpf_args *fa, struct fuse_dummy_io *dummy,
1787 struct inode *dir, struct dentry *entry)
1788 {
1789 *fa = (struct fuse_bpf_args) {
1790 .nodeid = get_node_id(dir),
1791 .opcode = FUSE_UNLINK,
1792 .in_numargs = 1,
1793 .in_args[0] = (struct fuse_bpf_in_arg) {
1794 .size = entry->d_name.len + 1,
1795 .value = entry->d_name.name,
1796 },
1797 };
1798
1799 return 0;
1800 }
1801
fuse_unlink_backing(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry)1802 int fuse_unlink_backing(
1803 struct fuse_bpf_args *fa,
1804 struct inode *dir, struct dentry *entry)
1805 {
1806 int err = 0;
1807 struct path backing_path = {};
1808 struct dentry *backing_parent_dentry;
1809 struct inode *backing_inode;
1810
1811 /* TODO Actually deal with changing the backing entry in unlink */
1812 get_fuse_backing_path(entry, &backing_path);
1813 if (!backing_path.dentry)
1814 return -EBADF;
1815
1816 /* TODO Not sure if we should reverify like overlayfs, or get inode from d_parent */
1817 backing_parent_dentry = dget_parent(backing_path.dentry);
1818 backing_inode = d_inode(backing_parent_dentry);
1819
1820 inode_lock_nested(backing_inode, I_MUTEX_PARENT);
1821 err = vfs_unlink(&nop_mnt_idmap, backing_inode, backing_path.dentry, NULL);
1822 inode_unlock(backing_inode);
1823
1824 dput(backing_parent_dentry);
1825 if (!err)
1826 d_drop(entry);
1827 path_put(&backing_path);
1828 return err;
1829 }
1830
fuse_unlink_finalize(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry)1831 void *fuse_unlink_finalize(
1832 struct fuse_bpf_args *fa,
1833 struct inode *dir, struct dentry *entry)
1834 {
1835 return NULL;
1836 }
1837
fuse_link_initialize(struct fuse_bpf_args * fa,struct fuse_link_in * fli,struct dentry * entry,struct inode * dir,struct dentry * newent)1838 int fuse_link_initialize(struct fuse_bpf_args *fa, struct fuse_link_in *fli,
1839 struct dentry *entry, struct inode *dir,
1840 struct dentry *newent)
1841 {
1842 struct inode *src_inode = entry->d_inode;
1843
1844 *fli = (struct fuse_link_in){
1845 .oldnodeid = get_node_id(src_inode),
1846 };
1847
1848 fa->opcode = FUSE_LINK;
1849 fa->in_numargs = 2;
1850 fa->in_args[0].size = sizeof(*fli);
1851 fa->in_args[0].value = fli;
1852 fa->in_args[1].size = newent->d_name.len + 1;
1853 fa->in_args[1].value = newent->d_name.name;
1854
1855 return 0;
1856 }
1857
fuse_link_backing(struct fuse_bpf_args * fa,struct dentry * entry,struct inode * dir,struct dentry * newent)1858 int fuse_link_backing(struct fuse_bpf_args *fa, struct dentry *entry,
1859 struct inode *dir, struct dentry *newent)
1860 {
1861 int err = 0;
1862 struct path backing_old_path = {};
1863 struct path backing_new_path = {};
1864 struct dentry *backing_dir_dentry;
1865 struct inode *fuse_new_inode = NULL;
1866 struct fuse_inode *fuse_dir_inode = get_fuse_inode(dir);
1867 struct inode *backing_dir_inode = fuse_dir_inode->backing_inode;
1868
1869 get_fuse_backing_path(entry, &backing_old_path);
1870 if (!backing_old_path.dentry)
1871 return -EBADF;
1872
1873 get_fuse_backing_path(newent, &backing_new_path);
1874 if (!backing_new_path.dentry) {
1875 err = -EBADF;
1876 goto err_dst_path;
1877 }
1878
1879 backing_dir_dentry = dget_parent(backing_new_path.dentry);
1880 backing_dir_inode = d_inode(backing_dir_dentry);
1881
1882 inode_lock_nested(backing_dir_inode, I_MUTEX_PARENT);
1883 err = vfs_link(backing_old_path.dentry, &nop_mnt_idmap,
1884 backing_dir_inode, backing_new_path.dentry, NULL);
1885 inode_unlock(backing_dir_inode);
1886 if (err)
1887 goto out;
1888
1889 if (d_really_is_negative(backing_new_path.dentry) ||
1890 unlikely(d_unhashed(backing_new_path.dentry))) {
1891 err = -EINVAL;
1892 /**
1893 * TODO: overlayfs responds to this situation with a
1894 * lookupOneLen. Should we do that too?
1895 */
1896 goto out;
1897 }
1898
1899 fuse_new_inode = fuse_iget_backing(dir->i_sb, fuse_dir_inode->nodeid, backing_dir_inode);
1900 if (IS_ERR(fuse_new_inode)) {
1901 err = PTR_ERR(fuse_new_inode);
1902 goto out;
1903 }
1904 d_instantiate(newent, fuse_new_inode);
1905
1906 out:
1907 dput(backing_dir_dentry);
1908 path_put(&backing_new_path);
1909 err_dst_path:
1910 path_put(&backing_old_path);
1911 return err;
1912 }
1913
fuse_link_finalize(struct fuse_bpf_args * fa,struct dentry * entry,struct inode * dir,struct dentry * newent)1914 void *fuse_link_finalize(struct fuse_bpf_args *fa, struct dentry *entry,
1915 struct inode *dir, struct dentry *newent)
1916 {
1917 return NULL;
1918 }
1919
fuse_getattr_initialize(struct fuse_bpf_args * fa,struct fuse_getattr_io * fgio,const struct dentry * entry,struct kstat * stat,u32 request_mask,unsigned int flags)1920 int fuse_getattr_initialize(struct fuse_bpf_args *fa, struct fuse_getattr_io *fgio,
1921 const struct dentry *entry, struct kstat *stat,
1922 u32 request_mask, unsigned int flags)
1923 {
1924 fgio->fgi = (struct fuse_getattr_in) {
1925 .getattr_flags = flags,
1926 .fh = -1, /* TODO is this OK? */
1927 };
1928
1929 fgio->fao = (struct fuse_attr_out) {0};
1930
1931 *fa = (struct fuse_bpf_args) {
1932 .nodeid = get_node_id(entry->d_inode),
1933 .opcode = FUSE_GETATTR,
1934 .in_numargs = 1,
1935 .out_numargs = 1,
1936 .in_args[0] = (struct fuse_bpf_in_arg) {
1937 .size = sizeof(fgio->fgi),
1938 .value = &fgio->fgi,
1939 },
1940 .out_args[0] = (struct fuse_bpf_arg) {
1941 .size = sizeof(fgio->fao),
1942 .value = &fgio->fao,
1943 },
1944 };
1945
1946 return 0;
1947 }
1948
fuse_stat_to_attr(struct fuse_conn * fc,struct inode * inode,struct kstat * stat,struct fuse_attr * attr)1949 static void fuse_stat_to_attr(struct fuse_conn *fc, struct inode *inode,
1950 struct kstat *stat, struct fuse_attr *attr)
1951 {
1952 unsigned int blkbits;
1953
1954 /* see the comment in fuse_change_attributes() */
1955 if (fc->writeback_cache && S_ISREG(inode->i_mode)) {
1956 stat->size = i_size_read(inode);
1957 stat->mtime.tv_sec = inode_get_mtime_sec(inode);;
1958 stat->mtime.tv_nsec = inode_get_mtime_nsec(inode);
1959 stat->ctime.tv_sec = inode_get_ctime_sec(inode);
1960 stat->ctime.tv_nsec = inode_get_ctime_nsec(inode);
1961 }
1962
1963 attr->ino = stat->ino;
1964 attr->mode = (inode->i_mode & S_IFMT) | (stat->mode & 07777);
1965 attr->nlink = stat->nlink;
1966 attr->uid = from_kuid(fc->user_ns, stat->uid);
1967 attr->gid = from_kgid(fc->user_ns, stat->gid);
1968 attr->atime = stat->atime.tv_sec;
1969 attr->atimensec = stat->atime.tv_nsec;
1970 attr->mtime = stat->mtime.tv_sec;
1971 attr->mtimensec = stat->mtime.tv_nsec;
1972 attr->ctime = stat->ctime.tv_sec;
1973 attr->ctimensec = stat->ctime.tv_nsec;
1974 attr->size = stat->size;
1975 attr->blocks = stat->blocks;
1976
1977 if (stat->blksize != 0)
1978 blkbits = ilog2(stat->blksize);
1979 else
1980 blkbits = inode->i_sb->s_blocksize_bits;
1981
1982 attr->blksize = 1 << blkbits;
1983 }
1984
fuse_getattr_backing(struct fuse_bpf_args * fa,const struct dentry * entry,struct kstat * stat,u32 request_mask,unsigned int flags)1985 int fuse_getattr_backing(struct fuse_bpf_args *fa,
1986 const struct dentry *entry, struct kstat *stat,
1987 u32 request_mask, unsigned int flags)
1988 {
1989 struct path *backing_path =
1990 &get_fuse_dentry(entry)->backing_path;
1991 struct inode *backing_inode = backing_path->dentry->d_inode;
1992 struct fuse_attr_out *fao = fa->out_args[0].value;
1993 struct kstat tmp;
1994 int err;
1995
1996 if (!stat)
1997 stat = &tmp;
1998
1999 if (flags & AT_GETATTR_NOSEC)
2000 err = vfs_getattr_nosec(backing_path, stat, request_mask, flags);
2001 else
2002 err = vfs_getattr(backing_path, stat, request_mask, flags);
2003
2004 if (!err)
2005 fuse_stat_to_attr(get_fuse_conn(entry->d_inode),
2006 backing_inode, stat, &fao->attr);
2007
2008 return err;
2009 }
2010
fuse_getattr_finalize(struct fuse_bpf_args * fa,const struct dentry * entry,struct kstat * stat,u32 request_mask,unsigned int flags)2011 void *fuse_getattr_finalize(struct fuse_bpf_args *fa,
2012 const struct dentry *entry, struct kstat *stat,
2013 u32 request_mask, unsigned int flags)
2014 {
2015 struct fuse_attr_out *outarg = fa->out_args[0].value;
2016 struct inode *inode = entry->d_inode;
2017 u64 attr_version = fuse_get_attr_version(get_fuse_mount(inode)->fc);
2018 int err = 0;
2019
2020 /* TODO: Ensure this doesn't happen if we had an error getting attrs in
2021 * backing.
2022 */
2023 err = finalize_attr(inode, outarg, attr_version, stat);
2024 return ERR_PTR(err);
2025 }
2026
fattr_to_iattr(struct fuse_conn * fc,const struct fuse_setattr_in * arg,struct iattr * iattr)2027 static void fattr_to_iattr(struct fuse_conn *fc,
2028 const struct fuse_setattr_in *arg,
2029 struct iattr *iattr)
2030 {
2031 unsigned int fvalid = arg->valid;
2032
2033 if (fvalid & FATTR_MODE)
2034 iattr->ia_valid |= ATTR_MODE, iattr->ia_mode = arg->mode;
2035 if (fvalid & FATTR_UID) {
2036 iattr->ia_valid |= ATTR_UID;
2037 iattr->ia_uid = make_kuid(fc->user_ns, arg->uid);
2038 }
2039 if (fvalid & FATTR_GID) {
2040 iattr->ia_valid |= ATTR_GID;
2041 iattr->ia_gid = make_kgid(fc->user_ns, arg->gid);
2042 }
2043 if (fvalid & FATTR_SIZE)
2044 iattr->ia_valid |= ATTR_SIZE, iattr->ia_size = arg->size;
2045 if (fvalid & FATTR_ATIME) {
2046 iattr->ia_valid |= ATTR_ATIME;
2047 iattr->ia_atime.tv_sec = arg->atime;
2048 iattr->ia_atime.tv_nsec = arg->atimensec;
2049 if (!(fvalid & FATTR_ATIME_NOW))
2050 iattr->ia_valid |= ATTR_ATIME_SET;
2051 }
2052 if (fvalid & FATTR_MTIME) {
2053 iattr->ia_valid |= ATTR_MTIME;
2054 iattr->ia_mtime.tv_sec = arg->mtime;
2055 iattr->ia_mtime.tv_nsec = arg->mtimensec;
2056 if (!(fvalid & FATTR_MTIME_NOW))
2057 iattr->ia_valid |= ATTR_MTIME_SET;
2058 }
2059 if (fvalid & FATTR_CTIME) {
2060 iattr->ia_valid |= ATTR_CTIME;
2061 iattr->ia_ctime.tv_sec = arg->ctime;
2062 iattr->ia_ctime.tv_nsec = arg->ctimensec;
2063 }
2064 }
2065
fuse_setattr_initialize(struct fuse_bpf_args * fa,struct fuse_setattr_io * fsio,struct dentry * dentry,struct iattr * attr,struct file * file)2066 int fuse_setattr_initialize(struct fuse_bpf_args *fa, struct fuse_setattr_io *fsio,
2067 struct dentry *dentry, struct iattr *attr, struct file *file)
2068 {
2069 struct fuse_conn *fc = get_fuse_conn(dentry->d_inode);
2070
2071 *fsio = (struct fuse_setattr_io) {0};
2072 iattr_to_fattr(&nop_mnt_idmap, fc, attr, &fsio->fsi, true);
2073
2074 *fa = (struct fuse_bpf_args) {
2075 .opcode = FUSE_SETATTR,
2076 .nodeid = get_node_id(dentry->d_inode),
2077 .in_numargs = 1,
2078 .in_args[0].size = sizeof(fsio->fsi),
2079 .in_args[0].value = &fsio->fsi,
2080 .out_numargs = 1,
2081 .out_args[0].size = sizeof(fsio->fao),
2082 .out_args[0].value = &fsio->fao,
2083 };
2084
2085 return 0;
2086 }
2087
fuse_setattr_backing(struct fuse_bpf_args * fa,struct dentry * dentry,struct iattr * attr,struct file * file)2088 int fuse_setattr_backing(struct fuse_bpf_args *fa,
2089 struct dentry *dentry, struct iattr *attr, struct file *file)
2090 {
2091 struct fuse_conn *fc = get_fuse_conn(dentry->d_inode);
2092 const struct fuse_setattr_in *fsi = fa->in_args[0].value;
2093 struct iattr new_attr = {0};
2094 struct path *backing_path = &get_fuse_dentry(dentry)->backing_path;
2095 int res;
2096
2097 fattr_to_iattr(fc, fsi, &new_attr);
2098 /* TODO: Some info doesn't get saved by the attr->fattr->attr transition
2099 * When we actually allow the bpf to change these, we may have to consider
2100 * the extra flags more, or pass more info into the bpf. Until then we can
2101 * keep everything except for ATTR_FILE, since we'd need a file on the
2102 * lower fs. For what it's worth, neither f2fs nor ext4 make use of that
2103 * even if it is present.
2104 */
2105 new_attr.ia_valid = attr->ia_valid & ~ATTR_FILE;
2106 inode_lock(d_inode(backing_path->dentry));
2107 res = notify_change(&nop_mnt_idmap, backing_path->dentry, &new_attr, NULL);
2108 inode_unlock(d_inode(backing_path->dentry));
2109
2110 if (res == 0 && (new_attr.ia_valid & ATTR_SIZE))
2111 i_size_write(dentry->d_inode, new_attr.ia_size);
2112 return res;
2113 }
2114
fuse_setattr_finalize(struct fuse_bpf_args * fa,struct dentry * dentry,struct iattr * attr,struct file * file)2115 void *fuse_setattr_finalize(struct fuse_bpf_args *fa,
2116 struct dentry *dentry, struct iattr *attr, struct file *file)
2117 {
2118 return NULL;
2119 }
2120
fuse_statfs_initialize(struct fuse_bpf_args * fa,struct fuse_statfs_out * fso,struct dentry * dentry,struct kstatfs * buf)2121 int fuse_statfs_initialize(
2122 struct fuse_bpf_args *fa, struct fuse_statfs_out *fso,
2123 struct dentry *dentry, struct kstatfs *buf)
2124 {
2125 *fso = (struct fuse_statfs_out) {0};
2126 *fa = (struct fuse_bpf_args) {
2127 .nodeid = get_node_id(d_inode(dentry)),
2128 .opcode = FUSE_STATFS,
2129 .out_numargs = 1,
2130 .out_numargs = 1,
2131 .out_args[0].size = sizeof(fso),
2132 .out_args[0].value = fso,
2133 };
2134
2135 return 0;
2136 }
2137
fuse_statfs_backing(struct fuse_bpf_args * fa,struct dentry * dentry,struct kstatfs * buf)2138 int fuse_statfs_backing(
2139 struct fuse_bpf_args *fa,
2140 struct dentry *dentry, struct kstatfs *buf)
2141 {
2142 int err = 0;
2143 struct path backing_path;
2144 struct fuse_statfs_out *fso = fa->out_args[0].value;
2145
2146 get_fuse_backing_path(dentry, &backing_path);
2147 if (!backing_path.dentry)
2148 return -EBADF;
2149 err = vfs_statfs(&backing_path, buf);
2150 path_put(&backing_path);
2151 buf->f_type = FUSE_SUPER_MAGIC;
2152
2153 //TODO Provide postfilter opportunity to modify
2154 if (!err)
2155 convert_statfs_to_fuse(&fso->st, buf);
2156
2157 return err;
2158 }
2159
fuse_statfs_finalize(struct fuse_bpf_args * fa,struct dentry * dentry,struct kstatfs * buf)2160 void *fuse_statfs_finalize(
2161 struct fuse_bpf_args *fa,
2162 struct dentry *dentry, struct kstatfs *buf)
2163 {
2164 struct fuse_statfs_out *fso = fa->out_args[0].value;
2165
2166 if (!fa->error_in)
2167 convert_fuse_statfs(buf, &fso->st);
2168 return NULL;
2169 }
2170
fuse_get_link_initialize(struct fuse_bpf_args * fa,struct fuse_dummy_io * unused,struct inode * inode,struct dentry * dentry,struct delayed_call * callback,const char ** out)2171 int fuse_get_link_initialize(struct fuse_bpf_args *fa, struct fuse_dummy_io *unused,
2172 struct inode *inode, struct dentry *dentry,
2173 struct delayed_call *callback, const char **out)
2174 {
2175 /*
2176 * TODO
2177 * If we want to handle changing these things, we'll need to copy
2178 * the lower fs's data into our own buffer, and provide our own callback
2179 * to free that buffer.
2180 *
2181 * Pre could change the name we're looking at
2182 * postfilter can change the name we return
2183 *
2184 * We ought to only make that buffer if it's been requested, so leaving
2185 * this unimplemented for the moment
2186 */
2187 *fa = (struct fuse_bpf_args) {
2188 .opcode = FUSE_READLINK,
2189 .nodeid = get_node_id(inode),
2190 .in_numargs = 1,
2191 .in_args[0] = (struct fuse_bpf_in_arg) {
2192 .size = dentry->d_name.len + 1,
2193 .value = dentry->d_name.name,
2194 },
2195 /*
2196 * .out_argvar = 1,
2197 * .out_numargs = 1,
2198 * .out_args[0].size = ,
2199 * .out_args[0].value = ,
2200 */
2201 };
2202
2203 return 0;
2204 }
2205
fuse_get_link_backing(struct fuse_bpf_args * fa,struct inode * inode,struct dentry * dentry,struct delayed_call * callback,const char ** out)2206 int fuse_get_link_backing(struct fuse_bpf_args *fa,
2207 struct inode *inode, struct dentry *dentry,
2208 struct delayed_call *callback, const char **out)
2209 {
2210 struct path backing_path;
2211
2212 if (!dentry) {
2213 *out = ERR_PTR(-ECHILD);
2214 return PTR_ERR(*out);
2215 }
2216
2217 get_fuse_backing_path(dentry, &backing_path);
2218 if (!backing_path.dentry) {
2219 *out = ERR_PTR(-ECHILD);
2220 return PTR_ERR(*out);
2221 }
2222
2223 /*
2224 * TODO: If we want to do our own thing, copy the data and then call the
2225 * callback
2226 */
2227 *out = vfs_get_link(backing_path.dentry, callback);
2228
2229 path_put(&backing_path);
2230 return 0;
2231 }
2232
fuse_get_link_finalize(struct fuse_bpf_args * fa,struct inode * inode,struct dentry * dentry,struct delayed_call * callback,const char ** out)2233 void *fuse_get_link_finalize(struct fuse_bpf_args *fa,
2234 struct inode *inode, struct dentry *dentry,
2235 struct delayed_call *callback, const char **out)
2236 {
2237 return NULL;
2238 }
2239
fuse_symlink_initialize(struct fuse_bpf_args * fa,struct fuse_dummy_io * unused,struct inode * dir,struct dentry * entry,const char * link,int len)2240 int fuse_symlink_initialize(
2241 struct fuse_bpf_args *fa, struct fuse_dummy_io *unused,
2242 struct inode *dir, struct dentry *entry, const char *link, int len)
2243 {
2244 *fa = (struct fuse_bpf_args) {
2245 .nodeid = get_node_id(dir),
2246 .opcode = FUSE_SYMLINK,
2247 .in_numargs = 2,
2248 .in_args[0] = (struct fuse_bpf_in_arg) {
2249 .size = entry->d_name.len + 1,
2250 .value = entry->d_name.name,
2251 },
2252 .in_args[1] = (struct fuse_bpf_in_arg) {
2253 .size = len,
2254 .value = link,
2255 },
2256 };
2257
2258 return 0;
2259 }
2260
fuse_symlink_backing(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,const char * link,int len)2261 int fuse_symlink_backing(
2262 struct fuse_bpf_args *fa,
2263 struct inode *dir, struct dentry *entry, const char *link, int len)
2264 {
2265 int err = 0;
2266 struct fuse_inode *fuse_inode = get_fuse_inode(dir);
2267 struct inode *backing_inode = fuse_inode->backing_inode;
2268 struct path backing_path = {};
2269 struct inode *inode = NULL;
2270
2271 //TODO Actually deal with changing the backing entry in symlink
2272 get_fuse_backing_path(entry, &backing_path);
2273 if (!backing_path.dentry)
2274 return -EBADF;
2275
2276 inode_lock_nested(backing_inode, I_MUTEX_PARENT);
2277 err = vfs_symlink(&nop_mnt_idmap, backing_inode, backing_path.dentry, link);
2278 inode_unlock(backing_inode);
2279 if (err)
2280 goto out;
2281 if (d_really_is_negative(backing_path.dentry) ||
2282 unlikely(d_unhashed(backing_path.dentry))) {
2283 err = -EINVAL;
2284 /**
2285 * TODO: overlayfs responds to this situation with a
2286 * lookupOneLen. Should we do that too?
2287 */
2288 goto out;
2289 }
2290 inode = fuse_iget_backing(dir->i_sb, fuse_inode->nodeid, backing_inode);
2291 if (IS_ERR(inode)) {
2292 err = PTR_ERR(inode);
2293 goto out;
2294 }
2295 d_instantiate(entry, inode);
2296 out:
2297 path_put(&backing_path);
2298 return err;
2299 }
2300
fuse_symlink_finalize(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,const char * link,int len)2301 void *fuse_symlink_finalize(
2302 struct fuse_bpf_args *fa,
2303 struct inode *dir, struct dentry *entry, const char *link, int len)
2304 {
2305 return NULL;
2306 }
2307
fuse_readdir_initialize(struct fuse_bpf_args * fa,struct fuse_read_io * frio,struct file * file,struct dir_context * ctx,bool * force_again,bool * allow_force,bool is_continued)2308 int fuse_readdir_initialize(struct fuse_bpf_args *fa, struct fuse_read_io *frio,
2309 struct file *file, struct dir_context *ctx,
2310 bool *force_again, bool *allow_force, bool is_continued)
2311 {
2312 struct fuse_file *ff = file->private_data;
2313 u8 *page = (u8 *)__get_free_page(GFP_KERNEL);
2314
2315 if (!page)
2316 return -ENOMEM;
2317
2318 *fa = (struct fuse_bpf_args) {
2319 .nodeid = ff->nodeid,
2320 .opcode = FUSE_READDIR,
2321 .in_numargs = 1,
2322 .flags = FUSE_BPF_OUT_ARGVAR,
2323 .out_numargs = 2,
2324 .in_args[0] = (struct fuse_bpf_in_arg) {
2325 .size = sizeof(frio->fri),
2326 .value = &frio->fri,
2327 },
2328 .out_args[0] = (struct fuse_bpf_arg) {
2329 .size = sizeof(frio->fro),
2330 .value = &frio->fro,
2331 },
2332 .out_args[1] = (struct fuse_bpf_arg) {
2333 .size = PAGE_SIZE,
2334 .value = page,
2335 },
2336 };
2337
2338 frio->fri = (struct fuse_read_in) {
2339 .fh = ff->fh,
2340 .offset = ctx->pos,
2341 .size = PAGE_SIZE,
2342 };
2343 frio->fro = (struct fuse_read_out) {
2344 .again = 0,
2345 .offset = 0,
2346 };
2347 *force_again = false;
2348 *allow_force = true;
2349 return 0;
2350 }
2351
2352 struct extfuse_ctx {
2353 struct dir_context ctx;
2354 u8 *addr;
2355 size_t offset;
2356 };
2357
filldir(struct dir_context * ctx,const char * name,int namelen,loff_t offset,u64 ino,unsigned int d_type)2358 static bool filldir(struct dir_context *ctx, const char *name, int namelen,
2359 loff_t offset, u64 ino, unsigned int d_type)
2360 {
2361 struct extfuse_ctx *ec = container_of(ctx, struct extfuse_ctx, ctx);
2362 struct fuse_dirent *fd = (struct fuse_dirent *) (ec->addr + ec->offset);
2363
2364 if (ec->offset + sizeof(struct fuse_dirent) + namelen > PAGE_SIZE)
2365 return false;
2366
2367 *fd = (struct fuse_dirent) {
2368 .ino = ino,
2369 .off = offset,
2370 .namelen = namelen,
2371 .type = d_type,
2372 };
2373
2374 memcpy(fd->name, name, namelen);
2375 ec->offset += FUSE_DIRENT_SIZE(fd);
2376
2377 return true;
2378 }
2379
parse_dirfile(char * buf,size_t nbytes,struct dir_context * ctx,loff_t next_offset)2380 static int parse_dirfile(char *buf, size_t nbytes, struct dir_context *ctx,
2381 loff_t next_offset)
2382 {
2383 char *buffstart = buf;
2384
2385 while (nbytes >= FUSE_NAME_OFFSET) {
2386 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
2387 size_t reclen = FUSE_DIRENT_SIZE(dirent);
2388
2389 if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
2390 return -EIO;
2391 if (reclen > nbytes)
2392 break;
2393 if (memchr(dirent->name, '/', dirent->namelen) != NULL)
2394 return -EIO;
2395
2396 ctx->pos = dirent->off;
2397 if (!dir_emit(ctx, dirent->name, dirent->namelen, dirent->ino,
2398 dirent->type)) {
2399 // If we can't make any progress, user buffer is too small
2400 if (buf == buffstart)
2401 return -EINVAL;
2402 else
2403 return 0;
2404 }
2405
2406 buf += reclen;
2407 nbytes -= reclen;
2408 }
2409 ctx->pos = next_offset;
2410
2411 return 0;
2412 }
2413
2414
fuse_readdir_backing(struct fuse_bpf_args * fa,struct file * file,struct dir_context * ctx,bool * force_again,bool * allow_force,bool is_continued)2415 int fuse_readdir_backing(struct fuse_bpf_args *fa,
2416 struct file *file, struct dir_context *ctx,
2417 bool *force_again, bool *allow_force, bool is_continued)
2418 {
2419 struct fuse_file *ff = file->private_data;
2420 struct file *backing_dir = ff->backing_file;
2421 struct fuse_read_out *fro = fa->out_args[0].value;
2422 struct extfuse_ctx ec;
2423 int err;
2424
2425 ec = (struct extfuse_ctx) {
2426 .ctx.actor = filldir,
2427 .ctx.pos = ctx->pos,
2428 .addr = fa->out_args[1].value,
2429 };
2430
2431 if (!ec.addr)
2432 return -ENOMEM;
2433
2434 if (!is_continued)
2435 backing_dir->f_pos = file->f_pos;
2436
2437 err = iterate_dir(backing_dir, &ec.ctx);
2438 if (ec.offset == 0)
2439 *allow_force = false;
2440 fa->out_args[1].size = ec.offset;
2441
2442 fro->offset = ec.ctx.pos;
2443 fro->again = false;
2444 return err;
2445 }
2446
fuse_readdir_finalize(struct fuse_bpf_args * fa,struct file * file,struct dir_context * ctx,bool * force_again,bool * allow_force,bool is_continued)2447 void *fuse_readdir_finalize(struct fuse_bpf_args *fa,
2448 struct file *file, struct dir_context *ctx,
2449 bool *force_again, bool *allow_force, bool is_continued)
2450 {
2451 struct fuse_read_out *fro = fa->out_args[0].value;
2452 struct fuse_file *ff = file->private_data;
2453 struct file *backing_dir = ff->backing_file;
2454 int err = 0;
2455
2456 err = parse_dirfile(fa->out_args[1].value, fa->out_args[1].size, ctx, fro->offset);
2457 *force_again = !!fro->again;
2458 if (*force_again && !*allow_force)
2459 err = -EINVAL;
2460
2461 backing_dir->f_pos = ctx->pos;
2462
2463 free_page((unsigned long) fa->out_args[1].value);
2464 return ERR_PTR(err);
2465 }
2466
fuse_access_initialize(struct fuse_bpf_args * fa,struct fuse_access_in * fai,struct inode * inode,int mask)2467 int fuse_access_initialize(struct fuse_bpf_args *fa, struct fuse_access_in *fai,
2468 struct inode *inode, int mask)
2469 {
2470 *fai = (struct fuse_access_in) {
2471 .mask = mask,
2472 };
2473
2474 *fa = (struct fuse_bpf_args) {
2475 .opcode = FUSE_ACCESS,
2476 .nodeid = get_node_id(inode),
2477 .in_numargs = 1,
2478 .in_args[0].size = sizeof(*fai),
2479 .in_args[0].value = fai,
2480 };
2481
2482 return 0;
2483 }
2484
fuse_access_backing(struct fuse_bpf_args * fa,struct inode * inode,int mask)2485 int fuse_access_backing(struct fuse_bpf_args *fa, struct inode *inode, int mask)
2486 {
2487 struct fuse_inode *fi = get_fuse_inode(inode);
2488 const struct fuse_access_in *fai = fa->in_args[0].value;
2489
2490 return inode_permission(&nop_mnt_idmap, fi->backing_inode, fai->mask);
2491 }
2492
fuse_access_finalize(struct fuse_bpf_args * fa,struct inode * inode,int mask)2493 void *fuse_access_finalize(struct fuse_bpf_args *fa, struct inode *inode, int mask)
2494 {
2495 return NULL;
2496 }
2497
fuse_bpf_init(void)2498 int __init fuse_bpf_init(void)
2499 {
2500 fuse_bpf_aio_request_cachep = kmem_cache_create("fuse_bpf_aio_req",
2501 sizeof(struct fuse_bpf_aio_req),
2502 0, SLAB_HWCACHE_ALIGN, NULL);
2503 if (!fuse_bpf_aio_request_cachep)
2504 return -ENOMEM;
2505
2506 return 0;
2507 }
2508
fuse_bpf_cleanup(void)2509 void __exit fuse_bpf_cleanup(void)
2510 {
2511 kmem_cache_destroy(fuse_bpf_aio_request_cachep);
2512 }
2513
fuse_bpf_simple_request(struct fuse_mount * fm,struct fuse_bpf_args * bpf_args)2514 ssize_t fuse_bpf_simple_request(struct fuse_mount *fm, struct fuse_bpf_args *bpf_args)
2515 {
2516 int i;
2517 ssize_t res;
2518 struct fuse_args args = {
2519 .nodeid = bpf_args->nodeid,
2520 .opcode = bpf_args->opcode,
2521 .error_in = bpf_args->error_in,
2522 .in_numargs = bpf_args->in_numargs,
2523 .out_numargs = bpf_args->out_numargs,
2524 .force = !!(bpf_args->flags & FUSE_BPF_FORCE),
2525 .out_argvar = !!(bpf_args->flags & FUSE_BPF_OUT_ARGVAR),
2526 };
2527
2528 for (i = 0; i < args.in_numargs; ++i)
2529 args.in_args[i] = (struct fuse_in_arg) {
2530 .size = bpf_args->in_args[i].size,
2531 .value = bpf_args->in_args[i].value,
2532 };
2533 for (i = 0; i < args.out_numargs; ++i)
2534 args.out_args[i] = (struct fuse_arg) {
2535 .size = bpf_args->out_args[i].size,
2536 .value = bpf_args->out_args[i].value,
2537 };
2538
2539 res = fuse_simple_request(fm, &args);
2540
2541 *bpf_args = (struct fuse_bpf_args) {
2542 .nodeid = args.nodeid,
2543 .opcode = args.opcode,
2544 .error_in = args.error_in,
2545 .in_numargs = args.in_numargs,
2546 .out_numargs = args.out_numargs,
2547 };
2548 if (args.force)
2549 bpf_args->flags |= FUSE_BPF_FORCE;
2550 if (args.out_argvar)
2551 bpf_args->flags |= FUSE_BPF_OUT_ARGVAR;
2552 for (i = 0; i < args.in_numargs; ++i)
2553 bpf_args->in_args[i] = (struct fuse_bpf_in_arg) {
2554 .size = args.in_args[i].size,
2555 .value = args.in_args[i].value,
2556 };
2557 for (i = 0; i < args.out_numargs; ++i)
2558 bpf_args->out_args[i] = (struct fuse_bpf_arg) {
2559 .size = args.out_args[i].size,
2560 .value = args.out_args[i].value,
2561 };
2562 return res;
2563 }
2564