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