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