• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)776 static void fuse_bpf_aio_rw_complete(struct kiocb *iocb, long res)
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);
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 = iov_iter_is_kvec(from)
905 			? from->kvec->iov_base : NULL,
906 		.out_numargs = 1,
907 		.out_args[0].size = sizeof(fwio->fwio),
908 		.out_args[0].value = &fwio->fwio,
909 	};
910 
911 	return 0;
912 }
913 
fuse_file_write_iter_backing(struct fuse_bpf_args * fa,struct kiocb * iocb,struct iov_iter * from)914 int fuse_file_write_iter_backing(struct fuse_bpf_args *fa,
915 		struct kiocb *iocb, struct iov_iter *from)
916 {
917 	struct file *file = iocb->ki_filp;
918 	struct fuse_file *ff = file->private_data;
919 	struct fuse_write_iter_out *fwio = fa->out_args[0].value;
920 	ssize_t ret;
921 
922 	if (!iov_iter_count(from))
923 		return 0;
924 
925 	/* TODO This just plain ignores any change to fuse_write_in */
926 	/* TODO uint32_t seems smaller than ssize_t.... right? */
927 	inode_lock(file_inode(file));
928 
929 	fuse_copyattr(file, ff->backing_file);
930 
931 	if (is_sync_kiocb(iocb)) {
932 		file_start_write(ff->backing_file);
933 		ret = vfs_iter_write(ff->backing_file, from, &iocb->ki_pos,
934 					   iocb_to_rw_flags(iocb->ki_flags, FUSE_BPF_IOCB_MASK));
935 		file_end_write(ff->backing_file);
936 
937 		/* Must reflect change in size of backing file to upper file */
938 		if (ret > 0)
939 			fuse_copyattr(file, ff->backing_file);
940 	} else {
941 		struct fuse_bpf_aio_req *aio_req;
942 
943 		ret = -ENOMEM;
944 		aio_req = kmem_cache_zalloc(fuse_bpf_aio_request_cachep, GFP_KERNEL);
945 		if (!aio_req)
946 			goto out;
947 
948 		file_start_write(ff->backing_file);
949 		__sb_writers_release(file_inode(ff->backing_file)->i_sb, SB_FREEZE_WRITE);
950 		aio_req->iocb_orig = iocb;
951 		kiocb_clone(&aio_req->iocb, iocb, ff->backing_file);
952 		aio_req->iocb.ki_complete = fuse_bpf_aio_rw_complete;
953 		refcount_set(&aio_req->ref, 2);
954 		ret = vfs_iocb_iter_write(ff->backing_file, &aio_req->iocb, from);
955 		fuse_bpf_aio_put(aio_req);
956 		if (ret != -EIOCBQUEUED)
957 			fuse_bpf_aio_cleanup_handler(aio_req);
958 	}
959 
960 out:
961 	inode_unlock(file_inode(file));
962 	fwio->ret = ret;
963 	if (ret < 0)
964 		return ret;
965 	return 0;
966 }
967 
fuse_file_write_iter_finalize(struct fuse_bpf_args * fa,struct kiocb * iocb,struct iov_iter * from)968 void *fuse_file_write_iter_finalize(struct fuse_bpf_args *fa,
969 		struct kiocb *iocb, struct iov_iter *from)
970 {
971 	struct fuse_write_iter_out *fwio = fa->out_args[0].value;
972 
973 	return ERR_PTR(fwio->ret);
974 }
975 
fuse_backing_ioctl(struct file * file,unsigned int command,unsigned long arg,int flags)976 long fuse_backing_ioctl(struct file *file, unsigned int command, unsigned long arg, int flags)
977 {
978 	struct fuse_file *ff = file->private_data;
979 	long ret;
980 
981 	if (flags & FUSE_IOCTL_COMPAT)
982 		ret = -ENOTTY;
983 	else
984 		ret = vfs_ioctl(ff->backing_file, command, arg);
985 
986 	return ret;
987 }
988 
fuse_file_flock_backing(struct file * file,int cmd,struct file_lock * fl)989 int fuse_file_flock_backing(struct file *file, int cmd, struct file_lock *fl)
990 {
991 	struct fuse_file *ff = file->private_data;
992 	struct file *backing_file = ff->backing_file;
993 	int error;
994 
995 	fl->fl_file = backing_file;
996 	if (backing_file->f_op->flock)
997 		error = backing_file->f_op->flock(backing_file, cmd, fl);
998 	else
999 		error = locks_lock_file_wait(backing_file, fl);
1000 	return error;
1001 }
1002 
fuse_backing_mmap(struct file * file,struct vm_area_struct * vma)1003 ssize_t fuse_backing_mmap(struct file *file, struct vm_area_struct *vma)
1004 {
1005 	int ret;
1006 	struct fuse_file *ff = file->private_data;
1007 	struct inode *fuse_inode = file_inode(file);
1008 	struct file *backing_file = ff->backing_file;
1009 	struct inode *backing_inode = file_inode(backing_file);
1010 
1011 	if (!backing_file->f_op->mmap)
1012 		return -ENODEV;
1013 
1014 	if (WARN_ON(file != vma->vm_file))
1015 		return -EIO;
1016 
1017 	vma->vm_file = get_file(backing_file);
1018 
1019 	ret = call_mmap(vma->vm_file, vma);
1020 
1021 	if (ret)
1022 		fput(backing_file);
1023 	else
1024 		fput(file);
1025 
1026 	if (file->f_flags & O_NOATIME)
1027 		return ret;
1028 
1029 	if ((!timespec64_equal(&fuse_inode->i_mtime,
1030 			       &backing_inode->i_mtime) ||
1031 	     !timespec64_equal(&fuse_inode->i_ctime,
1032 			       &backing_inode->i_ctime))) {
1033 		fuse_inode->i_mtime = backing_inode->i_mtime;
1034 		fuse_inode->i_ctime = backing_inode->i_ctime;
1035 	}
1036 	touch_atime(&file->f_path);
1037 
1038 	return ret;
1039 }
1040 
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)1041 int fuse_file_fallocate_initialize(struct fuse_bpf_args *fa,
1042 		struct fuse_fallocate_in *ffi,
1043 		struct file *file, int mode, loff_t offset, loff_t length)
1044 {
1045 	struct fuse_file *ff = file->private_data;
1046 
1047 	*ffi = (struct fuse_fallocate_in) {
1048 		.fh = ff->fh,
1049 		.offset = offset,
1050 		.length = length,
1051 		.mode = mode
1052 	};
1053 
1054 	*fa = (struct fuse_bpf_args) {
1055 		.opcode = FUSE_FALLOCATE,
1056 		.nodeid = ff->nodeid,
1057 		.in_numargs = 1,
1058 		.in_args[0].size = sizeof(*ffi),
1059 		.in_args[0].value = ffi,
1060 	};
1061 
1062 	return 0;
1063 }
1064 
fuse_file_fallocate_backing(struct fuse_bpf_args * fa,struct file * file,int mode,loff_t offset,loff_t length)1065 int fuse_file_fallocate_backing(struct fuse_bpf_args *fa,
1066 		struct file *file, int mode, loff_t offset, loff_t length)
1067 {
1068 	const struct fuse_fallocate_in *ffi = fa->in_args[0].value;
1069 	struct fuse_file *ff = file->private_data;
1070 
1071 	return vfs_fallocate(ff->backing_file, ffi->mode, ffi->offset,
1072 			     ffi->length);
1073 }
1074 
fuse_file_fallocate_finalize(struct fuse_bpf_args * fa,struct file * file,int mode,loff_t offset,loff_t length)1075 void *fuse_file_fallocate_finalize(struct fuse_bpf_args *fa,
1076 		struct file *file, int mode, loff_t offset, loff_t length)
1077 {
1078 	return NULL;
1079 }
1080 
1081 /*******************************************************************************
1082  * Directory operations after here                                             *
1083  ******************************************************************************/
1084 
fuse_lookup_initialize(struct fuse_bpf_args * fa,struct fuse_lookup_io * fli,struct inode * dir,struct dentry * entry,unsigned int flags)1085 int fuse_lookup_initialize(struct fuse_bpf_args *fa, struct fuse_lookup_io *fli,
1086 	       struct inode *dir, struct dentry *entry, unsigned int flags)
1087 {
1088 	*fa = (struct fuse_bpf_args) {
1089 		.nodeid = get_fuse_inode(dir)->nodeid,
1090 		.opcode = FUSE_LOOKUP,
1091 		.in_numargs = 1,
1092 		.out_numargs = 2,
1093 		.flags = FUSE_BPF_OUT_ARGVAR,
1094 		.in_args[0] = (struct fuse_bpf_in_arg) {
1095 			.size = entry->d_name.len + 1,
1096 			.value = entry->d_name.name,
1097 		},
1098 		.out_args[0] = (struct fuse_bpf_arg) {
1099 			.size = sizeof(fli->feo),
1100 			.value = &fli->feo,
1101 		},
1102 		.out_args[1] = (struct fuse_bpf_arg) {
1103 			.size = sizeof(fli->feb.out),
1104 			.value = &fli->feb.out,
1105 		},
1106 	};
1107 
1108 	return 0;
1109 }
1110 
fuse_lookup_backing(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,unsigned int flags)1111 int fuse_lookup_backing(struct fuse_bpf_args *fa, struct inode *dir,
1112 			  struct dentry *entry, unsigned int flags)
1113 {
1114 	struct fuse_dentry *fuse_entry = get_fuse_dentry(entry);
1115 	struct fuse_dentry *dir_fuse_entry = get_fuse_dentry(entry->d_parent);
1116 	struct dentry *dir_backing_entry = dir_fuse_entry->backing_path.dentry;
1117 	struct inode *dir_backing_inode = dir_backing_entry->d_inode;
1118 	struct dentry *backing_entry;
1119 	struct fuse_entry_out *feo = (void *)fa->out_args[0].value;
1120 	struct kstat stat;
1121 	int err;
1122 
1123 	inode_lock_nested(dir_backing_inode, I_MUTEX_PARENT);
1124 	backing_entry = lookup_one_len(entry->d_name.name, dir_backing_entry,
1125 					strlen(entry->d_name.name));
1126 	inode_unlock(dir_backing_inode);
1127 
1128 	if (IS_ERR(backing_entry))
1129 		return PTR_ERR(backing_entry);
1130 
1131 	fuse_entry->backing_path = (struct path) {
1132 		.dentry = backing_entry,
1133 		.mnt = mntget(dir_fuse_entry->backing_path.mnt),
1134 	};
1135 
1136 	if (d_is_negative(backing_entry)) {
1137 		fa->error_in = -ENOENT;
1138 		return 0;
1139 	}
1140 
1141 	err = follow_down(&fuse_entry->backing_path);
1142 	if (err)
1143 		goto err_out;
1144 
1145 	err = vfs_getattr(&fuse_entry->backing_path, &stat,
1146 				  STATX_BASIC_STATS, 0);
1147 	if (err)
1148 		goto err_out;
1149 
1150 	fuse_stat_to_attr(get_fuse_conn(dir),
1151 			  backing_entry->d_inode, &stat, &feo->attr);
1152 	return 0;
1153 
1154 err_out:
1155 	path_put_init(&fuse_entry->backing_path);
1156 	return err;
1157 }
1158 
fuse_handle_backing(struct fuse_entry_bpf * feb,struct inode ** backing_inode,struct path * backing_path)1159 int fuse_handle_backing(struct fuse_entry_bpf *feb, struct inode **backing_inode,
1160 			struct path *backing_path)
1161 {
1162 	switch (feb->out.backing_action) {
1163 	case FUSE_ACTION_KEEP:
1164 		/* backing inode/path are added in fuse_lookup_backing */
1165 		break;
1166 
1167 	case FUSE_ACTION_REMOVE:
1168 		iput(*backing_inode);
1169 		*backing_inode = NULL;
1170 		path_put_init(backing_path);
1171 		break;
1172 
1173 	case FUSE_ACTION_REPLACE: {
1174 		struct file *backing_file = feb->backing_file;
1175 
1176 		if (!backing_file)
1177 			return -EINVAL;
1178 		if (IS_ERR(backing_file))
1179 			return PTR_ERR(backing_file);
1180 
1181 		if (backing_inode)
1182 			iput(*backing_inode);
1183 		*backing_inode = backing_file->f_inode;
1184 		ihold(*backing_inode);
1185 
1186 		path_put(backing_path);
1187 		*backing_path = backing_file->f_path;
1188 		path_get(backing_path);
1189 		break;
1190 	}
1191 
1192 	default:
1193 		return -EINVAL;
1194 	}
1195 
1196 	return 0;
1197 }
1198 
fuse_handle_bpf_prog(struct fuse_entry_bpf * feb,struct inode * parent,struct bpf_prog ** bpf)1199 int fuse_handle_bpf_prog(struct fuse_entry_bpf *feb, struct inode *parent,
1200 			 struct bpf_prog **bpf)
1201 {
1202 	struct bpf_prog *new_bpf = NULL;
1203 
1204 	switch (feb->out.bpf_action) {
1205 	case FUSE_ACTION_KEEP: {
1206 		/* Parent isn't presented, but we want to keep
1207 		 * Don't touch bpf program at all in this case
1208 		 */
1209 		if (!parent)
1210 			return 0;
1211 
1212 		new_bpf = get_fuse_inode(parent)->bpf;
1213 		if (new_bpf)
1214 			bpf_prog_inc(new_bpf);
1215 		break;
1216 	}
1217 
1218 	case FUSE_ACTION_REMOVE:
1219 		break;
1220 
1221 	case FUSE_ACTION_REPLACE: {
1222 		struct file *bpf_file = feb->bpf_file;
1223 
1224 		if (!bpf_file)
1225 			return -EINVAL;
1226 		if (IS_ERR(bpf_file))
1227 			return PTR_ERR(bpf_file);
1228 
1229 		new_bpf = fuse_get_bpf_prog(bpf_file);
1230 		if (IS_ERR(new_bpf))
1231 			return PTR_ERR(new_bpf);
1232 		break;
1233 	}
1234 
1235 	default:
1236 		return -EINVAL;
1237 	}
1238 
1239 	/* Cannot change existing program */
1240 	if (*bpf) {
1241 		if (new_bpf)
1242 			bpf_prog_put(new_bpf);
1243 		return new_bpf == *bpf ? 0 : -EINVAL;
1244 	}
1245 
1246 	*bpf = new_bpf;
1247 	return 0;
1248 }
1249 
fuse_lookup_finalize(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,unsigned int flags)1250 struct dentry *fuse_lookup_finalize(struct fuse_bpf_args *fa, struct inode *dir,
1251 			   struct dentry *entry, unsigned int flags)
1252 {
1253 	struct fuse_dentry *fuse_entry;
1254 	struct dentry *backing_entry;
1255 	struct inode *inode = NULL, *backing_inode;
1256 	struct inode *entry_inode = entry->d_inode;
1257 	struct fuse_entry_out *feo = fa->out_args[0].value;
1258 	struct fuse_entry_bpf_out *febo = fa->out_args[1].value;
1259 	struct fuse_entry_bpf *feb = container_of(febo, struct fuse_entry_bpf,
1260 						  out);
1261 	int error = -1;
1262 	u64 target_nodeid = 0;
1263 	struct dentry *ret = NULL;
1264 
1265 	fuse_entry = get_fuse_dentry(entry);
1266 	if (!fuse_entry) {
1267 		ret = ERR_PTR(-EIO);
1268 		goto out;
1269 	}
1270 
1271 	backing_entry = fuse_entry->backing_path.dentry;
1272 	if (!backing_entry) {
1273 		ret = ERR_PTR(-ENOENT);
1274 		goto out;
1275 	}
1276 
1277 	if (entry_inode)
1278 		target_nodeid = get_fuse_inode(entry_inode)->nodeid;
1279 
1280 	backing_inode = backing_entry->d_inode;
1281 	if (backing_inode)
1282 		inode = fuse_iget_backing(dir->i_sb, target_nodeid,
1283 					  backing_inode);
1284 
1285 	error = inode ?
1286 		fuse_handle_bpf_prog(feb, dir, &get_fuse_inode(inode)->bpf) :
1287 		fuse_handle_bpf_prog(feb, dir, &fuse_entry->bpf);
1288 	if (error) {
1289 		ret = ERR_PTR(error);
1290 		goto out;
1291 	}
1292 
1293 	if (inode) {
1294 		error = fuse_handle_backing(feb,
1295 					&get_fuse_inode(inode)->backing_inode,
1296 					&fuse_entry->backing_path);
1297 		if (error) {
1298 			ret = ERR_PTR(error);
1299 			goto out;
1300 		}
1301 
1302 		get_fuse_inode(inode)->nodeid = feo->nodeid;
1303 		ret = d_splice_alias(inode, entry);
1304 		if (!IS_ERR(ret))
1305 			inode = NULL;
1306 	}
1307 out:
1308 	iput(inode);
1309 	if (feb->backing_file)
1310 		fput(feb->backing_file);
1311 	return ret;
1312 }
1313 
fuse_revalidate_backing(struct dentry * entry,unsigned int flags)1314 int fuse_revalidate_backing(struct dentry *entry, unsigned int flags)
1315 {
1316 	struct fuse_dentry *fuse_dentry = get_fuse_dentry(entry);
1317 	struct dentry *backing_entry = fuse_dentry->backing_path.dentry;
1318 
1319 	spin_lock(&backing_entry->d_lock);
1320 	if (d_unhashed(backing_entry)) {
1321 		spin_unlock(&backing_entry->d_lock);
1322 			return 0;
1323 	}
1324 	spin_unlock(&backing_entry->d_lock);
1325 
1326 	if (unlikely(backing_entry->d_flags & DCACHE_OP_REVALIDATE))
1327 		return backing_entry->d_op->d_revalidate(backing_entry, flags);
1328 	return 1;
1329 }
1330 
fuse_canonical_path_initialize(struct fuse_bpf_args * fa,struct fuse_dummy_io * fdi,const struct path * path,struct path * canonical_path)1331 int fuse_canonical_path_initialize(struct fuse_bpf_args *fa,
1332 				   struct fuse_dummy_io *fdi,
1333 				   const struct path *path,
1334 				   struct path *canonical_path)
1335 {
1336 	fa->opcode = FUSE_CANONICAL_PATH;
1337 	return 0;
1338 }
1339 
fuse_canonical_path_backing(struct fuse_bpf_args * fa,const struct path * path,struct path * canonical_path)1340 int fuse_canonical_path_backing(struct fuse_bpf_args *fa, const struct path *path,
1341 				struct path *canonical_path)
1342 {
1343 	get_fuse_backing_path(path->dentry, canonical_path);
1344 	return 0;
1345 }
1346 
fuse_canonical_path_finalize(struct fuse_bpf_args * fa,const struct path * path,struct path * canonical_path)1347 void *fuse_canonical_path_finalize(struct fuse_bpf_args *fa,
1348 				   const struct path *path,
1349 				   struct path *canonical_path)
1350 {
1351 	return NULL;
1352 }
1353 
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)1354 int fuse_mknod_initialize(
1355 		struct fuse_bpf_args *fa, struct fuse_mknod_in *fmi,
1356 		struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev)
1357 {
1358 	*fmi = (struct fuse_mknod_in) {
1359 		.mode = mode,
1360 		.rdev = new_encode_dev(rdev),
1361 		.umask = current_umask(),
1362 	};
1363 	*fa = (struct fuse_bpf_args) {
1364 		.nodeid = get_node_id(dir),
1365 		.opcode = FUSE_MKNOD,
1366 		.in_numargs = 2,
1367 		.in_args[0] = (struct fuse_bpf_in_arg) {
1368 			.size = sizeof(*fmi),
1369 			.value = fmi,
1370 		},
1371 		.in_args[1] = (struct fuse_bpf_in_arg) {
1372 			.size = entry->d_name.len + 1,
1373 			.value = entry->d_name.name,
1374 		},
1375 	};
1376 
1377 	return 0;
1378 }
1379 
fuse_mknod_backing(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,umode_t mode,dev_t rdev)1380 int fuse_mknod_backing(
1381 		struct fuse_bpf_args *fa,
1382 		struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev)
1383 {
1384 	int err = 0;
1385 	const struct fuse_mknod_in *fmi = fa->in_args[0].value;
1386 	struct fuse_inode *fuse_inode = get_fuse_inode(dir);
1387 	struct inode *backing_inode = fuse_inode->backing_inode;
1388 	struct path backing_path = {};
1389 	struct inode *inode = NULL;
1390 
1391 	//TODO Actually deal with changing the backing entry in mknod
1392 	get_fuse_backing_path(entry, &backing_path);
1393 	if (!backing_path.dentry)
1394 		return -EBADF;
1395 
1396 	inode_lock_nested(backing_inode, I_MUTEX_PARENT);
1397 	mode = fmi->mode;
1398 	if (!IS_POSIXACL(backing_inode))
1399 		mode &= ~fmi->umask;
1400 	err = vfs_mknod(&init_user_ns, backing_inode, backing_path.dentry,
1401 			mode, new_decode_dev(fmi->rdev));
1402 	inode_unlock(backing_inode);
1403 	if (err)
1404 		goto out;
1405 	if (d_really_is_negative(backing_path.dentry) ||
1406 		unlikely(d_unhashed(backing_path.dentry))) {
1407 		err = -EINVAL;
1408 		/**
1409 		 * TODO: overlayfs responds to this situation with a
1410 		 * lookupOneLen. Should we do that too?
1411 		 */
1412 		goto out;
1413 	}
1414 	inode = fuse_iget_backing(dir->i_sb, fuse_inode->nodeid, backing_inode);
1415 	if (IS_ERR(inode)) {
1416 		err = PTR_ERR(inode);
1417 		goto out;
1418 	}
1419 	d_instantiate(entry, inode);
1420 out:
1421 	path_put(&backing_path);
1422 	return err;
1423 }
1424 
fuse_mknod_finalize(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,umode_t mode,dev_t rdev)1425 void *fuse_mknod_finalize(
1426 		struct fuse_bpf_args *fa,
1427 		struct inode *dir, struct dentry *entry, umode_t mode, dev_t rdev)
1428 {
1429 	return NULL;
1430 }
1431 
fuse_mkdir_initialize(struct fuse_bpf_args * fa,struct fuse_mkdir_in * fmi,struct inode * dir,struct dentry * entry,umode_t mode)1432 int fuse_mkdir_initialize(
1433 		struct fuse_bpf_args *fa, struct fuse_mkdir_in *fmi,
1434 		struct inode *dir, struct dentry *entry, umode_t mode)
1435 {
1436 	*fmi = (struct fuse_mkdir_in) {
1437 		.mode = mode,
1438 		.umask = current_umask(),
1439 	};
1440 	*fa = (struct fuse_bpf_args) {
1441 		.nodeid = get_node_id(dir),
1442 		.opcode = FUSE_MKDIR,
1443 		.in_numargs = 2,
1444 		.in_args[0] = (struct fuse_bpf_in_arg) {
1445 			.size = sizeof(*fmi),
1446 			.value = fmi,
1447 		},
1448 		.in_args[1] = (struct fuse_bpf_in_arg) {
1449 			.size = entry->d_name.len + 1,
1450 			.value = entry->d_name.name,
1451 		},
1452 	};
1453 
1454 	return 0;
1455 }
1456 
fuse_mkdir_backing(struct fuse_bpf_args * fa,struct inode * dir_inode,struct dentry * entry,umode_t mode)1457 int fuse_mkdir_backing(
1458 		struct fuse_bpf_args *fa,
1459 		struct inode *dir_inode, struct dentry *entry, umode_t mode)
1460 {
1461 	int err = 0;
1462 	const struct fuse_mkdir_in *fmi = fa->in_args[0].value;
1463 	struct fuse_inode *dir_fuse_inode = get_fuse_inode(dir_inode);
1464 	struct inode *dir_backing_inode = dir_fuse_inode->backing_inode;
1465 	struct path backing_path = {};
1466 	struct inode *inode = NULL;
1467 
1468 	//TODO Actually deal with changing the backing entry in mkdir
1469 	get_fuse_backing_path(entry, &backing_path);
1470 	if (!backing_path.dentry)
1471 		return -EBADF;
1472 
1473 	inode_lock_nested(dir_backing_inode, I_MUTEX_PARENT);
1474 	mode = fmi->mode;
1475 	if (!IS_POSIXACL(dir_backing_inode))
1476 		mode &= ~fmi->umask;
1477 	err = vfs_mkdir(&init_user_ns, dir_backing_inode, backing_path.dentry,
1478 			mode);
1479 	if (err)
1480 		goto out;
1481 	if (d_really_is_negative(backing_path.dentry) ||
1482 		unlikely(d_unhashed(backing_path.dentry))) {
1483 		struct dentry *d = lookup_one_len(entry->d_name.name,
1484 					backing_path.dentry->d_parent,
1485 					entry->d_name.len);
1486 
1487 		if (IS_ERR(d)) {
1488 			err = PTR_ERR(d);
1489 			goto out;
1490 		}
1491 		dput(backing_path.dentry);
1492 		backing_path.dentry = d;
1493 	}
1494 	inode = fuse_iget_backing(dir_inode->i_sb, 0,
1495 				  backing_path.dentry->d_inode);
1496 	if (IS_ERR(inode)) {
1497 		err = PTR_ERR(inode);
1498 		goto out;
1499 	}
1500 	d_instantiate(entry, inode);
1501 	if (get_fuse_inode(inode)->bpf)
1502 		bpf_prog_put(get_fuse_inode(inode)->bpf);
1503 	get_fuse_inode(inode)->bpf = get_fuse_dentry(entry)->bpf;
1504 	get_fuse_dentry(entry)->bpf = NULL;
1505 out:
1506 	inode_unlock(dir_backing_inode);
1507 	path_put(&backing_path);
1508 	return err;
1509 }
1510 
fuse_mkdir_finalize(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,umode_t mode)1511 void *fuse_mkdir_finalize(
1512 		struct fuse_bpf_args *fa,
1513 		struct inode *dir, struct dentry *entry, umode_t mode)
1514 {
1515 	return NULL;
1516 }
1517 
fuse_rmdir_initialize(struct fuse_bpf_args * fa,struct fuse_dummy_io * dummy,struct inode * dir,struct dentry * entry)1518 int fuse_rmdir_initialize(
1519 		struct fuse_bpf_args *fa, struct fuse_dummy_io *dummy,
1520 		struct inode *dir, struct dentry *entry)
1521 {
1522 	*fa = (struct fuse_bpf_args) {
1523 		.nodeid = get_node_id(dir),
1524 		.opcode = FUSE_RMDIR,
1525 		.in_numargs = 1,
1526 		.in_args[0] = (struct fuse_bpf_in_arg) {
1527 			.size = entry->d_name.len + 1,
1528 			.value = entry->d_name.name,
1529 		},
1530 	};
1531 
1532 	return 0;
1533 }
1534 
fuse_rmdir_backing(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry)1535 int fuse_rmdir_backing(
1536 		struct fuse_bpf_args *fa,
1537 		struct inode *dir, struct dentry *entry)
1538 {
1539 	int err = 0;
1540 	struct path backing_path = {};
1541 	struct dentry *backing_parent_dentry;
1542 	struct inode *backing_inode;
1543 
1544 	/* TODO Actually deal with changing the backing entry in rmdir */
1545 	get_fuse_backing_path(entry, &backing_path);
1546 	if (!backing_path.dentry)
1547 		return -EBADF;
1548 
1549 	/* TODO Not sure if we should reverify like overlayfs, or get inode from d_parent */
1550 	backing_parent_dentry = dget_parent(backing_path.dentry);
1551 	backing_inode = d_inode(backing_parent_dentry);
1552 
1553 	inode_lock_nested(backing_inode, I_MUTEX_PARENT);
1554 	err = vfs_rmdir(&init_user_ns, backing_inode, backing_path.dentry);
1555 	inode_unlock(backing_inode);
1556 
1557 	dput(backing_parent_dentry);
1558 	if (!err)
1559 		d_drop(entry);
1560 	path_put(&backing_path);
1561 	return err;
1562 }
1563 
fuse_rmdir_finalize(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry)1564 void *fuse_rmdir_finalize(
1565 		struct fuse_bpf_args *fa,
1566 		struct inode *dir, struct dentry *entry)
1567 {
1568 	return NULL;
1569 }
1570 
fuse_rename_backing_common(struct inode * olddir,struct dentry * oldent,struct inode * newdir,struct dentry * newent,unsigned int flags)1571 static int fuse_rename_backing_common(
1572 			 struct inode *olddir, struct dentry *oldent,
1573 			 struct inode *newdir, struct dentry *newent,
1574 			 unsigned int flags)
1575 {
1576 	int err = 0;
1577 	struct path old_backing_path;
1578 	struct path new_backing_path;
1579 	struct dentry *old_backing_dir_dentry;
1580 	struct dentry *old_backing_dentry;
1581 	struct dentry *new_backing_dir_dentry;
1582 	struct dentry *new_backing_dentry;
1583 	struct dentry *trap = NULL;
1584 	struct inode *target_inode;
1585 	struct renamedata rd;
1586 
1587 	//TODO Actually deal with changing anything that isn't a flag
1588 	get_fuse_backing_path(oldent, &old_backing_path);
1589 	if (!old_backing_path.dentry)
1590 		return -EBADF;
1591 	get_fuse_backing_path(newent, &new_backing_path);
1592 	if (!new_backing_path.dentry) {
1593 		/*
1594 		 * TODO A file being moved from a backing path to another
1595 		 * backing path which is not yet instrumented with FUSE-BPF.
1596 		 * This may be slow and should be substituted with something
1597 		 * more clever.
1598 		 */
1599 		err = -EXDEV;
1600 		goto put_old_path;
1601 	}
1602 	if (new_backing_path.mnt != old_backing_path.mnt) {
1603 		err = -EXDEV;
1604 		goto put_new_path;
1605 	}
1606 	old_backing_dentry = old_backing_path.dentry;
1607 	new_backing_dentry = new_backing_path.dentry;
1608 	old_backing_dir_dentry = dget_parent(old_backing_dentry);
1609 	new_backing_dir_dentry = dget_parent(new_backing_dentry);
1610 	target_inode = d_inode(newent);
1611 
1612 	trap = lock_rename(old_backing_dir_dentry, new_backing_dir_dentry);
1613 	if (trap == old_backing_dentry) {
1614 		err = -EINVAL;
1615 		goto put_parents;
1616 	}
1617 	if (trap == new_backing_dentry) {
1618 		err = -ENOTEMPTY;
1619 		goto put_parents;
1620 	}
1621 	rd = (struct renamedata) {
1622 		.old_mnt_userns = &init_user_ns,
1623 		.old_dir = d_inode(old_backing_dir_dentry),
1624 		.old_dentry = old_backing_dentry,
1625 		.new_mnt_userns = &init_user_ns,
1626 		.new_dir = d_inode(new_backing_dir_dentry),
1627 		.new_dentry = new_backing_dentry,
1628 		.flags = flags,
1629 	};
1630 	err = vfs_rename(&rd);
1631 	if (err)
1632 		goto unlock;
1633 	if (target_inode)
1634 		fsstack_copy_attr_all(target_inode,
1635 				get_fuse_inode(target_inode)->backing_inode);
1636 	fsstack_copy_attr_all(d_inode(oldent), d_inode(old_backing_dentry));
1637 unlock:
1638 	unlock_rename(old_backing_dir_dentry, new_backing_dir_dentry);
1639 put_parents:
1640 	dput(new_backing_dir_dentry);
1641 	dput(old_backing_dir_dentry);
1642 put_new_path:
1643 	path_put(&new_backing_path);
1644 put_old_path:
1645 	path_put(&old_backing_path);
1646 	return err;
1647 }
1648 
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)1649 int fuse_rename2_initialize(struct fuse_bpf_args *fa, struct fuse_rename2_in *fri,
1650 			    struct inode *olddir, struct dentry *oldent,
1651 			    struct inode *newdir, struct dentry *newent,
1652 			    unsigned int flags)
1653 {
1654 	*fri = (struct fuse_rename2_in) {
1655 		.newdir = get_node_id(newdir),
1656 		.flags = flags,
1657 	};
1658 	*fa = (struct fuse_bpf_args) {
1659 		.nodeid = get_node_id(olddir),
1660 		.opcode = FUSE_RENAME2,
1661 		.in_numargs = 3,
1662 		.in_args[0] = (struct fuse_bpf_in_arg) {
1663 			.size = sizeof(*fri),
1664 			.value = fri,
1665 		},
1666 		.in_args[1] = (struct fuse_bpf_in_arg) {
1667 			.size = oldent->d_name.len + 1,
1668 			.value = oldent->d_name.name,
1669 		},
1670 		.in_args[2] = (struct fuse_bpf_in_arg) {
1671 			.size = newent->d_name.len + 1,
1672 			.value = newent->d_name.name,
1673 		},
1674 	};
1675 
1676 	return 0;
1677 }
1678 
fuse_rename2_backing(struct fuse_bpf_args * fa,struct inode * olddir,struct dentry * oldent,struct inode * newdir,struct dentry * newent,unsigned int flags)1679 int fuse_rename2_backing(struct fuse_bpf_args *fa,
1680 			 struct inode *olddir, struct dentry *oldent,
1681 			 struct inode *newdir, struct dentry *newent,
1682 			 unsigned int flags)
1683 {
1684 	const struct fuse_rename2_in *fri = fa->in_args[0].value;
1685 
1686 	/* TODO: deal with changing dirs/ents */
1687 	return fuse_rename_backing_common(olddir, oldent, newdir, newent, fri->flags);
1688 }
1689 
fuse_rename2_finalize(struct fuse_bpf_args * fa,struct inode * olddir,struct dentry * oldent,struct inode * newdir,struct dentry * newent,unsigned int flags)1690 void *fuse_rename2_finalize(struct fuse_bpf_args *fa,
1691 			    struct inode *olddir, struct dentry *oldent,
1692 			    struct inode *newdir, struct dentry *newent,
1693 			    unsigned int flags)
1694 {
1695 	return NULL;
1696 }
1697 
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)1698 int fuse_rename_initialize(struct fuse_bpf_args *fa, struct fuse_rename_in *fri,
1699 			   struct inode *olddir, struct dentry *oldent,
1700 			   struct inode *newdir, struct dentry *newent)
1701 {
1702 	*fri = (struct fuse_rename_in) {
1703 		.newdir = get_node_id(newdir),
1704 	};
1705 	*fa = (struct fuse_bpf_args) {
1706 		.nodeid = get_node_id(olddir),
1707 		.opcode = FUSE_RENAME,
1708 		.in_numargs = 3,
1709 		.in_args[0] = (struct fuse_bpf_in_arg) {
1710 			.size = sizeof(*fri),
1711 			.value = fri,
1712 		},
1713 		.in_args[1] = (struct fuse_bpf_in_arg) {
1714 			.size = oldent->d_name.len + 1,
1715 			.value = oldent->d_name.name,
1716 		},
1717 		.in_args[2] = (struct fuse_bpf_in_arg) {
1718 			.size = newent->d_name.len + 1,
1719 			.value = newent->d_name.name,
1720 		},
1721 	};
1722 
1723 	return 0;
1724 }
1725 
fuse_rename_backing(struct fuse_bpf_args * fa,struct inode * olddir,struct dentry * oldent,struct inode * newdir,struct dentry * newent)1726 int fuse_rename_backing(struct fuse_bpf_args *fa,
1727 			struct inode *olddir, struct dentry *oldent,
1728 			struct inode *newdir, struct dentry *newent)
1729 {
1730 	/* TODO: deal with changing dirs/ents */
1731 	return fuse_rename_backing_common(olddir, oldent, newdir, newent, 0);
1732 }
1733 
fuse_rename_finalize(struct fuse_bpf_args * fa,struct inode * olddir,struct dentry * oldent,struct inode * newdir,struct dentry * newent)1734 void *fuse_rename_finalize(struct fuse_bpf_args *fa,
1735 			   struct inode *olddir, struct dentry *oldent,
1736 			   struct inode *newdir, struct dentry *newent)
1737 {
1738 	return NULL;
1739 }
1740 
fuse_unlink_initialize(struct fuse_bpf_args * fa,struct fuse_dummy_io * dummy,struct inode * dir,struct dentry * entry)1741 int fuse_unlink_initialize(
1742 		struct fuse_bpf_args *fa, struct fuse_dummy_io *dummy,
1743 		struct inode *dir, struct dentry *entry)
1744 {
1745 	*fa = (struct fuse_bpf_args) {
1746 		.nodeid = get_node_id(dir),
1747 		.opcode = FUSE_UNLINK,
1748 		.in_numargs = 1,
1749 		.in_args[0] = (struct fuse_bpf_in_arg) {
1750 			.size = entry->d_name.len + 1,
1751 			.value = entry->d_name.name,
1752 		},
1753 	};
1754 
1755 	return 0;
1756 }
1757 
fuse_unlink_backing(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry)1758 int fuse_unlink_backing(
1759 		struct fuse_bpf_args *fa,
1760 		struct inode *dir, struct dentry *entry)
1761 {
1762 	int err = 0;
1763 	struct path backing_path = {};
1764 	struct dentry *backing_parent_dentry;
1765 	struct inode *backing_inode;
1766 
1767 	/* TODO Actually deal with changing the backing entry in unlink */
1768 	get_fuse_backing_path(entry, &backing_path);
1769 	if (!backing_path.dentry)
1770 		return -EBADF;
1771 
1772 	/* TODO Not sure if we should reverify like overlayfs, or get inode from d_parent */
1773 	backing_parent_dentry = dget_parent(backing_path.dentry);
1774 	backing_inode = d_inode(backing_parent_dentry);
1775 
1776 	inode_lock_nested(backing_inode, I_MUTEX_PARENT);
1777 	err = vfs_unlink(&init_user_ns, backing_inode, backing_path.dentry, NULL);
1778 	inode_unlock(backing_inode);
1779 
1780 	dput(backing_parent_dentry);
1781 	if (!err)
1782 		d_drop(entry);
1783 	path_put(&backing_path);
1784 	return err;
1785 }
1786 
fuse_unlink_finalize(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry)1787 void *fuse_unlink_finalize(
1788 		struct fuse_bpf_args *fa,
1789 		struct inode *dir, struct dentry *entry)
1790 {
1791 	return NULL;
1792 }
1793 
fuse_link_initialize(struct fuse_bpf_args * fa,struct fuse_link_in * fli,struct dentry * entry,struct inode * dir,struct dentry * newent)1794 int fuse_link_initialize(struct fuse_bpf_args *fa, struct fuse_link_in *fli,
1795 			 struct dentry *entry, struct inode *dir,
1796 			 struct dentry *newent)
1797 {
1798 	struct inode *src_inode = entry->d_inode;
1799 
1800 	*fli = (struct fuse_link_in){
1801 		.oldnodeid = get_node_id(src_inode),
1802 	};
1803 
1804 	fa->opcode = FUSE_LINK;
1805 	fa->in_numargs = 2;
1806 	fa->in_args[0].size = sizeof(*fli);
1807 	fa->in_args[0].value = fli;
1808 	fa->in_args[1].size = newent->d_name.len + 1;
1809 	fa->in_args[1].value = newent->d_name.name;
1810 
1811 	return 0;
1812 }
1813 
fuse_link_backing(struct fuse_bpf_args * fa,struct dentry * entry,struct inode * dir,struct dentry * newent)1814 int fuse_link_backing(struct fuse_bpf_args *fa, struct dentry *entry,
1815 		      struct inode *dir, struct dentry *newent)
1816 {
1817 	int err = 0;
1818 	struct path backing_old_path = {};
1819 	struct path backing_new_path = {};
1820 	struct dentry *backing_dir_dentry;
1821 	struct inode *fuse_new_inode = NULL;
1822 	struct fuse_inode *fuse_dir_inode = get_fuse_inode(dir);
1823 	struct inode *backing_dir_inode = fuse_dir_inode->backing_inode;
1824 
1825 	get_fuse_backing_path(entry, &backing_old_path);
1826 	if (!backing_old_path.dentry)
1827 		return -EBADF;
1828 
1829 	get_fuse_backing_path(newent, &backing_new_path);
1830 	if (!backing_new_path.dentry) {
1831 		err = -EBADF;
1832 		goto err_dst_path;
1833 	}
1834 
1835 	backing_dir_dentry = dget_parent(backing_new_path.dentry);
1836 	backing_dir_inode = d_inode(backing_dir_dentry);
1837 
1838 	inode_lock_nested(backing_dir_inode, I_MUTEX_PARENT);
1839 	err = vfs_link(backing_old_path.dentry,  &init_user_ns,
1840 		       backing_dir_inode, backing_new_path.dentry, NULL);
1841 	inode_unlock(backing_dir_inode);
1842 	if (err)
1843 		goto out;
1844 
1845 	if (d_really_is_negative(backing_new_path.dentry) ||
1846 	    unlikely(d_unhashed(backing_new_path.dentry))) {
1847 		err = -EINVAL;
1848 		/**
1849 		 * TODO: overlayfs responds to this situation with a
1850 		 * lookupOneLen. Should we do that too?
1851 		 */
1852 		goto out;
1853 	}
1854 
1855 	fuse_new_inode = fuse_iget_backing(dir->i_sb, fuse_dir_inode->nodeid, backing_dir_inode);
1856 	if (IS_ERR(fuse_new_inode)) {
1857 		err = PTR_ERR(fuse_new_inode);
1858 		goto out;
1859 	}
1860 	d_instantiate(newent, fuse_new_inode);
1861 
1862 out:
1863 	dput(backing_dir_dentry);
1864 	path_put(&backing_new_path);
1865 err_dst_path:
1866 	path_put(&backing_old_path);
1867 	return err;
1868 }
1869 
fuse_link_finalize(struct fuse_bpf_args * fa,struct dentry * entry,struct inode * dir,struct dentry * newent)1870 void *fuse_link_finalize(struct fuse_bpf_args *fa, struct dentry *entry,
1871 			 struct inode *dir, struct dentry *newent)
1872 {
1873 	return NULL;
1874 }
1875 
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)1876 int fuse_getattr_initialize(struct fuse_bpf_args *fa, struct fuse_getattr_io *fgio,
1877 			const struct dentry *entry, struct kstat *stat,
1878 			u32 request_mask, unsigned int flags)
1879 {
1880 	fgio->fgi = (struct fuse_getattr_in) {
1881 		.getattr_flags = flags,
1882 		.fh = -1, /* TODO is this OK? */
1883 	};
1884 
1885 	fgio->fao = (struct fuse_attr_out) {0};
1886 
1887 	*fa = (struct fuse_bpf_args) {
1888 		.nodeid = get_node_id(entry->d_inode),
1889 		.opcode = FUSE_GETATTR,
1890 		.in_numargs = 1,
1891 		.out_numargs = 1,
1892 		.in_args[0] = (struct fuse_bpf_in_arg) {
1893 			.size = sizeof(fgio->fgi),
1894 			.value = &fgio->fgi,
1895 		},
1896 		.out_args[0] = (struct fuse_bpf_arg) {
1897 			.size = sizeof(fgio->fao),
1898 			.value = &fgio->fao,
1899 		},
1900 	};
1901 
1902 	return 0;
1903 }
1904 
fuse_stat_to_attr(struct fuse_conn * fc,struct inode * inode,struct kstat * stat,struct fuse_attr * attr)1905 static void fuse_stat_to_attr(struct fuse_conn *fc, struct inode *inode,
1906 		struct kstat *stat, struct fuse_attr *attr)
1907 {
1908 	unsigned int blkbits;
1909 
1910 	/* see the comment in fuse_change_attributes() */
1911 	if (fc->writeback_cache && S_ISREG(inode->i_mode)) {
1912 		stat->size = i_size_read(inode);
1913 		stat->mtime.tv_sec = inode->i_mtime.tv_sec;
1914 		stat->mtime.tv_nsec = inode->i_mtime.tv_nsec;
1915 		stat->ctime.tv_sec = inode->i_ctime.tv_sec;
1916 		stat->ctime.tv_nsec = inode->i_ctime.tv_nsec;
1917 	}
1918 
1919 	attr->ino = stat->ino;
1920 	attr->mode = (inode->i_mode & S_IFMT) | (stat->mode & 07777);
1921 	attr->nlink = stat->nlink;
1922 	attr->uid = from_kuid(fc->user_ns, stat->uid);
1923 	attr->gid = from_kgid(fc->user_ns, stat->gid);
1924 	attr->atime = stat->atime.tv_sec;
1925 	attr->atimensec = stat->atime.tv_nsec;
1926 	attr->mtime = stat->mtime.tv_sec;
1927 	attr->mtimensec = stat->mtime.tv_nsec;
1928 	attr->ctime = stat->ctime.tv_sec;
1929 	attr->ctimensec = stat->ctime.tv_nsec;
1930 	attr->size = stat->size;
1931 	attr->blocks = stat->blocks;
1932 
1933 	if (stat->blksize != 0)
1934 		blkbits = ilog2(stat->blksize);
1935 	else
1936 		blkbits = inode->i_sb->s_blocksize_bits;
1937 
1938 	attr->blksize = 1 << blkbits;
1939 }
1940 
fuse_getattr_backing(struct fuse_bpf_args * fa,const struct dentry * entry,struct kstat * stat,u32 request_mask,unsigned int flags)1941 int fuse_getattr_backing(struct fuse_bpf_args *fa,
1942 		const struct dentry *entry, struct kstat *stat,
1943 			u32 request_mask, unsigned int flags)
1944 {
1945 	struct path *backing_path =
1946 		&get_fuse_dentry(entry)->backing_path;
1947 	struct inode *backing_inode = backing_path->dentry->d_inode;
1948 	struct fuse_attr_out *fao = fa->out_args[0].value;
1949 	struct kstat tmp;
1950 	int err;
1951 
1952 	if (!stat)
1953 		stat = &tmp;
1954 
1955 	err = vfs_getattr(backing_path, stat, request_mask, flags);
1956 
1957 	if (!err)
1958 		fuse_stat_to_attr(get_fuse_conn(entry->d_inode),
1959 				  backing_inode, stat, &fao->attr);
1960 
1961 	return err;
1962 }
1963 
fuse_getattr_finalize(struct fuse_bpf_args * fa,const struct dentry * entry,struct kstat * stat,u32 request_mask,unsigned int flags)1964 void *fuse_getattr_finalize(struct fuse_bpf_args *fa,
1965 			const struct dentry *entry, struct kstat *stat,
1966 			u32 request_mask, unsigned int flags)
1967 {
1968 	struct fuse_attr_out *outarg = fa->out_args[0].value;
1969 	struct inode *inode = entry->d_inode;
1970 	u64 attr_version = fuse_get_attr_version(get_fuse_mount(inode)->fc);
1971 	int err = 0;
1972 
1973 	/* TODO: Ensure this doesn't happen if we had an error getting attrs in
1974 	 * backing.
1975 	 */
1976 	err = finalize_attr(inode, outarg, attr_version, stat);
1977 	return ERR_PTR(err);
1978 }
1979 
fattr_to_iattr(struct fuse_conn * fc,const struct fuse_setattr_in * arg,struct iattr * iattr)1980 static void fattr_to_iattr(struct fuse_conn *fc,
1981 			   const struct fuse_setattr_in *arg,
1982 			   struct iattr *iattr)
1983 {
1984 	unsigned int fvalid = arg->valid;
1985 
1986 	if (fvalid & FATTR_MODE)
1987 		iattr->ia_valid |= ATTR_MODE, iattr->ia_mode = arg->mode;
1988 	if (fvalid & FATTR_UID) {
1989 		iattr->ia_valid |= ATTR_UID;
1990 		iattr->ia_uid = make_kuid(fc->user_ns, arg->uid);
1991 	}
1992 	if (fvalid & FATTR_GID) {
1993 		iattr->ia_valid |= ATTR_GID;
1994 		iattr->ia_gid = make_kgid(fc->user_ns, arg->gid);
1995 	}
1996 	if (fvalid & FATTR_SIZE)
1997 		iattr->ia_valid |= ATTR_SIZE,  iattr->ia_size = arg->size;
1998 	if (fvalid & FATTR_ATIME) {
1999 		iattr->ia_valid |= ATTR_ATIME;
2000 		iattr->ia_atime.tv_sec = arg->atime;
2001 		iattr->ia_atime.tv_nsec = arg->atimensec;
2002 		if (!(fvalid & FATTR_ATIME_NOW))
2003 			iattr->ia_valid |= ATTR_ATIME_SET;
2004 	}
2005 	if (fvalid & FATTR_MTIME) {
2006 		iattr->ia_valid |= ATTR_MTIME;
2007 		iattr->ia_mtime.tv_sec = arg->mtime;
2008 		iattr->ia_mtime.tv_nsec = arg->mtimensec;
2009 		if (!(fvalid & FATTR_MTIME_NOW))
2010 			iattr->ia_valid |= ATTR_MTIME_SET;
2011 	}
2012 	if (fvalid & FATTR_CTIME) {
2013 		iattr->ia_valid |= ATTR_CTIME;
2014 		iattr->ia_ctime.tv_sec = arg->ctime;
2015 		iattr->ia_ctime.tv_nsec = arg->ctimensec;
2016 	}
2017 }
2018 
fuse_setattr_initialize(struct fuse_bpf_args * fa,struct fuse_setattr_io * fsio,struct dentry * dentry,struct iattr * attr,struct file * file)2019 int fuse_setattr_initialize(struct fuse_bpf_args *fa, struct fuse_setattr_io *fsio,
2020 		struct dentry *dentry, struct iattr *attr, struct file *file)
2021 {
2022 	struct fuse_conn *fc = get_fuse_conn(dentry->d_inode);
2023 
2024 	*fsio = (struct fuse_setattr_io) {0};
2025 	iattr_to_fattr(fc, attr, &fsio->fsi, true);
2026 
2027 	*fa = (struct fuse_bpf_args) {
2028 		.opcode = FUSE_SETATTR,
2029 		.nodeid = get_node_id(dentry->d_inode),
2030 		.in_numargs = 1,
2031 		.in_args[0].size = sizeof(fsio->fsi),
2032 		.in_args[0].value = &fsio->fsi,
2033 		.out_numargs = 1,
2034 		.out_args[0].size = sizeof(fsio->fao),
2035 		.out_args[0].value = &fsio->fao,
2036 	};
2037 
2038 	return 0;
2039 }
2040 
fuse_setattr_backing(struct fuse_bpf_args * fa,struct dentry * dentry,struct iattr * attr,struct file * file)2041 int fuse_setattr_backing(struct fuse_bpf_args *fa,
2042 		struct dentry *dentry, struct iattr *attr, struct file *file)
2043 {
2044 	struct fuse_conn *fc = get_fuse_conn(dentry->d_inode);
2045 	const struct fuse_setattr_in *fsi = fa->in_args[0].value;
2046 	struct iattr new_attr = {0};
2047 	struct path *backing_path = &get_fuse_dentry(dentry)->backing_path;
2048 	int res;
2049 
2050 	fattr_to_iattr(fc, fsi, &new_attr);
2051 	/* TODO: Some info doesn't get saved by the attr->fattr->attr transition
2052 	 * When we actually allow the bpf to change these, we may have to consider
2053 	 * the extra flags more, or pass more info into the bpf. Until then we can
2054 	 * keep everything except for ATTR_FILE, since we'd need a file on the
2055 	 * lower fs. For what it's worth, neither f2fs nor ext4 make use of that
2056 	 * even if it is present.
2057 	 */
2058 	new_attr.ia_valid = attr->ia_valid & ~ATTR_FILE;
2059 	inode_lock(d_inode(backing_path->dentry));
2060 	res = notify_change(&init_user_ns, backing_path->dentry, &new_attr,
2061 			    NULL);
2062 	inode_unlock(d_inode(backing_path->dentry));
2063 
2064 	if (res == 0 && (new_attr.ia_valid & ATTR_SIZE))
2065 		i_size_write(dentry->d_inode, new_attr.ia_size);
2066 	return res;
2067 }
2068 
fuse_setattr_finalize(struct fuse_bpf_args * fa,struct dentry * dentry,struct iattr * attr,struct file * file)2069 void *fuse_setattr_finalize(struct fuse_bpf_args *fa,
2070 		struct dentry *dentry, struct iattr *attr, struct file *file)
2071 {
2072 	return NULL;
2073 }
2074 
fuse_statfs_initialize(struct fuse_bpf_args * fa,struct fuse_statfs_out * fso,struct dentry * dentry,struct kstatfs * buf)2075 int fuse_statfs_initialize(
2076 		struct fuse_bpf_args *fa, struct fuse_statfs_out *fso,
2077 		struct dentry *dentry, struct kstatfs *buf)
2078 {
2079 	*fso = (struct fuse_statfs_out) {0};
2080 	*fa = (struct fuse_bpf_args) {
2081 		.nodeid = get_node_id(d_inode(dentry)),
2082 		.opcode = FUSE_STATFS,
2083 		.out_numargs = 1,
2084 		.out_numargs = 1,
2085 		.out_args[0].size = sizeof(fso),
2086 		.out_args[0].value = fso,
2087 	};
2088 
2089 	return 0;
2090 }
2091 
fuse_statfs_backing(struct fuse_bpf_args * fa,struct dentry * dentry,struct kstatfs * buf)2092 int fuse_statfs_backing(
2093 		struct fuse_bpf_args *fa,
2094 		struct dentry *dentry, struct kstatfs *buf)
2095 {
2096 	int err = 0;
2097 	struct path backing_path;
2098 	struct fuse_statfs_out *fso = fa->out_args[0].value;
2099 
2100 	get_fuse_backing_path(dentry, &backing_path);
2101 	if (!backing_path.dentry)
2102 		return -EBADF;
2103 	err = vfs_statfs(&backing_path, buf);
2104 	path_put(&backing_path);
2105 	buf->f_type = FUSE_SUPER_MAGIC;
2106 
2107 	//TODO Provide postfilter opportunity to modify
2108 	if (!err)
2109 		convert_statfs_to_fuse(&fso->st, buf);
2110 
2111 	return err;
2112 }
2113 
fuse_statfs_finalize(struct fuse_bpf_args * fa,struct dentry * dentry,struct kstatfs * buf)2114 void *fuse_statfs_finalize(
2115 		struct fuse_bpf_args *fa,
2116 		struct dentry *dentry, struct kstatfs *buf)
2117 {
2118 	struct fuse_statfs_out *fso = fa->out_args[0].value;
2119 
2120 	if (!fa->error_in)
2121 		convert_fuse_statfs(buf, &fso->st);
2122 	return NULL;
2123 }
2124 
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)2125 int fuse_get_link_initialize(struct fuse_bpf_args *fa, struct fuse_dummy_io *unused,
2126 		struct inode *inode, struct dentry *dentry,
2127 		struct delayed_call *callback, const char **out)
2128 {
2129 	/*
2130 	 * TODO
2131 	 * If we want to handle changing these things, we'll need to copy
2132 	 * the lower fs's data into our own buffer, and provide our own callback
2133 	 * to free that buffer.
2134 	 *
2135 	 * Pre could change the name we're looking at
2136 	 * postfilter can change the name we return
2137 	 *
2138 	 * We ought to only make that buffer if it's been requested, so leaving
2139 	 * this unimplemented for the moment
2140 	 */
2141 	*fa = (struct fuse_bpf_args) {
2142 		.opcode = FUSE_READLINK,
2143 		.nodeid = get_node_id(inode),
2144 		.in_numargs = 1,
2145 		.in_args[0] = (struct fuse_bpf_in_arg) {
2146 			.size = dentry->d_name.len + 1,
2147 			.value = dentry->d_name.name,
2148 		},
2149 		/*
2150 		 * .out_argvar = 1,
2151 		 * .out_numargs = 1,
2152 		 * .out_args[0].size = ,
2153 		 * .out_args[0].value = ,
2154 		 */
2155 	};
2156 
2157 	return 0;
2158 }
2159 
fuse_get_link_backing(struct fuse_bpf_args * fa,struct inode * inode,struct dentry * dentry,struct delayed_call * callback,const char ** out)2160 int fuse_get_link_backing(struct fuse_bpf_args *fa,
2161 		struct inode *inode, struct dentry *dentry,
2162 		struct delayed_call *callback, const char **out)
2163 {
2164 	struct path backing_path;
2165 
2166 	if (!dentry) {
2167 		*out = ERR_PTR(-ECHILD);
2168 		return PTR_ERR(*out);
2169 	}
2170 
2171 	get_fuse_backing_path(dentry, &backing_path);
2172 	if (!backing_path.dentry) {
2173 		*out = ERR_PTR(-ECHILD);
2174 		return PTR_ERR(*out);
2175 	}
2176 
2177 	/*
2178 	 * TODO: If we want to do our own thing, copy the data and then call the
2179 	 * callback
2180 	 */
2181 	*out = vfs_get_link(backing_path.dentry, callback);
2182 
2183 	path_put(&backing_path);
2184 	return 0;
2185 }
2186 
fuse_get_link_finalize(struct fuse_bpf_args * fa,struct inode * inode,struct dentry * dentry,struct delayed_call * callback,const char ** out)2187 void *fuse_get_link_finalize(struct fuse_bpf_args *fa,
2188 		struct inode *inode, struct dentry *dentry,
2189 		struct delayed_call *callback,  const char **out)
2190 {
2191 	return NULL;
2192 }
2193 
fuse_symlink_initialize(struct fuse_bpf_args * fa,struct fuse_dummy_io * unused,struct inode * dir,struct dentry * entry,const char * link,int len)2194 int fuse_symlink_initialize(
2195 		struct fuse_bpf_args *fa, struct fuse_dummy_io *unused,
2196 		struct inode *dir, struct dentry *entry, const char *link, int len)
2197 {
2198 	*fa = (struct fuse_bpf_args) {
2199 		.nodeid = get_node_id(dir),
2200 		.opcode = FUSE_SYMLINK,
2201 		.in_numargs = 2,
2202 		.in_args[0] = (struct fuse_bpf_in_arg) {
2203 			.size = entry->d_name.len + 1,
2204 			.value = entry->d_name.name,
2205 		},
2206 		.in_args[1] = (struct fuse_bpf_in_arg) {
2207 			.size = len,
2208 			.value = link,
2209 		},
2210 	};
2211 
2212 	return 0;
2213 }
2214 
fuse_symlink_backing(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,const char * link,int len)2215 int fuse_symlink_backing(
2216 		struct fuse_bpf_args *fa,
2217 		struct inode *dir, struct dentry *entry, const char *link, int len)
2218 {
2219 	int err = 0;
2220 	struct fuse_inode *fuse_inode = get_fuse_inode(dir);
2221 	struct inode *backing_inode = fuse_inode->backing_inode;
2222 	struct path backing_path = {};
2223 	struct inode *inode = NULL;
2224 
2225 	//TODO Actually deal with changing the backing entry in symlink
2226 	get_fuse_backing_path(entry, &backing_path);
2227 	if (!backing_path.dentry)
2228 		return -EBADF;
2229 
2230 	inode_lock_nested(backing_inode, I_MUTEX_PARENT);
2231 	err = vfs_symlink(&init_user_ns, backing_inode, backing_path.dentry,
2232 			  link);
2233 	inode_unlock(backing_inode);
2234 	if (err)
2235 		goto out;
2236 	if (d_really_is_negative(backing_path.dentry) ||
2237 		unlikely(d_unhashed(backing_path.dentry))) {
2238 		err = -EINVAL;
2239 		/**
2240 		 * TODO: overlayfs responds to this situation with a
2241 		 * lookupOneLen. Should we do that too?
2242 		 */
2243 		goto out;
2244 	}
2245 	inode = fuse_iget_backing(dir->i_sb, fuse_inode->nodeid, backing_inode);
2246 	if (IS_ERR(inode)) {
2247 		err = PTR_ERR(inode);
2248 		goto out;
2249 	}
2250 	d_instantiate(entry, inode);
2251 out:
2252 	path_put(&backing_path);
2253 	return err;
2254 }
2255 
fuse_symlink_finalize(struct fuse_bpf_args * fa,struct inode * dir,struct dentry * entry,const char * link,int len)2256 void *fuse_symlink_finalize(
2257 		struct fuse_bpf_args *fa,
2258 		struct inode *dir, struct dentry *entry, const char *link, int len)
2259 {
2260 	return NULL;
2261 }
2262 
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)2263 int fuse_readdir_initialize(struct fuse_bpf_args *fa, struct fuse_read_io *frio,
2264 			    struct file *file, struct dir_context *ctx,
2265 			    bool *force_again, bool *allow_force, bool is_continued)
2266 {
2267 	struct fuse_file *ff = file->private_data;
2268 	u8 *page = (u8 *)__get_free_page(GFP_KERNEL);
2269 
2270 	if (!page)
2271 		return -ENOMEM;
2272 
2273 	*fa = (struct fuse_bpf_args) {
2274 		.nodeid = ff->nodeid,
2275 		.opcode = FUSE_READDIR,
2276 		.in_numargs = 1,
2277 		.flags = FUSE_BPF_OUT_ARGVAR,
2278 		.out_numargs = 2,
2279 		.in_args[0] = (struct fuse_bpf_in_arg) {
2280 			.size = sizeof(frio->fri),
2281 			.value = &frio->fri,
2282 		},
2283 		.out_args[0] = (struct fuse_bpf_arg) {
2284 			.size = sizeof(frio->fro),
2285 			.value = &frio->fro,
2286 		},
2287 		.out_args[1] = (struct fuse_bpf_arg) {
2288 			.size = PAGE_SIZE,
2289 			.value = page,
2290 		},
2291 	};
2292 
2293 	frio->fri = (struct fuse_read_in) {
2294 		.fh = ff->fh,
2295 		.offset = ctx->pos,
2296 		.size = PAGE_SIZE,
2297 	};
2298 	frio->fro = (struct fuse_read_out) {
2299 		.again = 0,
2300 		.offset = 0,
2301 	};
2302 	*force_again = false;
2303 	*allow_force = true;
2304 	return 0;
2305 }
2306 
2307 struct extfuse_ctx {
2308 	struct dir_context ctx;
2309 	u8 *addr;
2310 	size_t offset;
2311 };
2312 
filldir(struct dir_context * ctx,const char * name,int namelen,loff_t offset,u64 ino,unsigned int d_type)2313 static bool filldir(struct dir_context *ctx, const char *name, int namelen,
2314 				   loff_t offset, u64 ino, unsigned int d_type)
2315 {
2316 	struct extfuse_ctx *ec = container_of(ctx, struct extfuse_ctx, ctx);
2317 	struct fuse_dirent *fd = (struct fuse_dirent *) (ec->addr + ec->offset);
2318 
2319 	if (ec->offset + sizeof(struct fuse_dirent) + namelen > PAGE_SIZE)
2320 		return false;
2321 
2322 	*fd = (struct fuse_dirent) {
2323 		.ino = ino,
2324 		.off = offset,
2325 		.namelen = namelen,
2326 		.type = d_type,
2327 	};
2328 
2329 	memcpy(fd->name, name, namelen);
2330 	ec->offset += FUSE_DIRENT_SIZE(fd);
2331 
2332 	return true;
2333 }
2334 
parse_dirfile(char * buf,size_t nbytes,struct dir_context * ctx,loff_t next_offset)2335 static int parse_dirfile(char *buf, size_t nbytes, struct dir_context *ctx,
2336 		loff_t next_offset)
2337 {
2338 	char *buffstart = buf;
2339 
2340 	while (nbytes >= FUSE_NAME_OFFSET) {
2341 		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
2342 		size_t reclen = FUSE_DIRENT_SIZE(dirent);
2343 
2344 		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
2345 			return -EIO;
2346 		if (reclen > nbytes)
2347 			break;
2348 		if (memchr(dirent->name, '/', dirent->namelen) != NULL)
2349 			return -EIO;
2350 
2351 		ctx->pos = dirent->off;
2352 		if (!dir_emit(ctx, dirent->name, dirent->namelen, dirent->ino,
2353 				dirent->type)) {
2354 			// If we can't make any progress, user buffer is too small
2355 			if (buf == buffstart)
2356 				return -EINVAL;
2357 			else
2358 				return 0;
2359 		}
2360 
2361 		buf += reclen;
2362 		nbytes -= reclen;
2363 	}
2364 	ctx->pos = next_offset;
2365 
2366 	return 0;
2367 }
2368 
2369 
fuse_readdir_backing(struct fuse_bpf_args * fa,struct file * file,struct dir_context * ctx,bool * force_again,bool * allow_force,bool is_continued)2370 int fuse_readdir_backing(struct fuse_bpf_args *fa,
2371 			 struct file *file, struct dir_context *ctx,
2372 			 bool *force_again, bool *allow_force, bool is_continued)
2373 {
2374 	struct fuse_file *ff = file->private_data;
2375 	struct file *backing_dir = ff->backing_file;
2376 	struct fuse_read_out *fro = fa->out_args[0].value;
2377 	struct extfuse_ctx ec;
2378 	int err;
2379 
2380 	ec = (struct extfuse_ctx) {
2381 		.ctx.actor = filldir,
2382 		.ctx.pos = ctx->pos,
2383 		.addr = fa->out_args[1].value,
2384 	};
2385 
2386 	if (!ec.addr)
2387 		return -ENOMEM;
2388 
2389 	if (!is_continued)
2390 		backing_dir->f_pos = file->f_pos;
2391 
2392 	err = iterate_dir(backing_dir, &ec.ctx);
2393 	if (ec.offset == 0)
2394 		*allow_force = false;
2395 	fa->out_args[1].size = ec.offset;
2396 
2397 	fro->offset = ec.ctx.pos;
2398 	fro->again = false;
2399 	return err;
2400 }
2401 
fuse_readdir_finalize(struct fuse_bpf_args * fa,struct file * file,struct dir_context * ctx,bool * force_again,bool * allow_force,bool is_continued)2402 void *fuse_readdir_finalize(struct fuse_bpf_args *fa,
2403 			    struct file *file, struct dir_context *ctx,
2404 			    bool *force_again, bool *allow_force, bool is_continued)
2405 {
2406 	struct fuse_read_out *fro = fa->out_args[0].value;
2407 	struct fuse_file *ff = file->private_data;
2408 	struct file *backing_dir = ff->backing_file;
2409 	int err = 0;
2410 
2411 	err = parse_dirfile(fa->out_args[1].value, fa->out_args[1].size, ctx, fro->offset);
2412 	*force_again = !!fro->again;
2413 	if (*force_again && !*allow_force)
2414 		err = -EINVAL;
2415 
2416 	backing_dir->f_pos = ctx->pos;
2417 
2418 	free_page((unsigned long) fa->out_args[1].value);
2419 	return ERR_PTR(err);
2420 }
2421 
fuse_access_initialize(struct fuse_bpf_args * fa,struct fuse_access_in * fai,struct inode * inode,int mask)2422 int fuse_access_initialize(struct fuse_bpf_args *fa, struct fuse_access_in *fai,
2423 			    struct inode *inode, int mask)
2424 {
2425 	*fai = (struct fuse_access_in) {
2426 		.mask = mask,
2427 	};
2428 
2429 	*fa = (struct fuse_bpf_args) {
2430 		.opcode = FUSE_ACCESS,
2431 		.nodeid = get_node_id(inode),
2432 		.in_numargs = 1,
2433 		.in_args[0].size = sizeof(*fai),
2434 		.in_args[0].value = fai,
2435 	};
2436 
2437 	return 0;
2438 }
2439 
fuse_access_backing(struct fuse_bpf_args * fa,struct inode * inode,int mask)2440 int fuse_access_backing(struct fuse_bpf_args *fa, struct inode *inode, int mask)
2441 {
2442 	struct fuse_inode *fi = get_fuse_inode(inode);
2443 	const struct fuse_access_in *fai = fa->in_args[0].value;
2444 
2445 	return inode_permission(&init_user_ns, fi->backing_inode, fai->mask);
2446 }
2447 
fuse_access_finalize(struct fuse_bpf_args * fa,struct inode * inode,int mask)2448 void *fuse_access_finalize(struct fuse_bpf_args *fa, struct inode *inode, int mask)
2449 {
2450 	return NULL;
2451 }
2452 
fuse_bpf_init(void)2453 int __init fuse_bpf_init(void)
2454 {
2455 	fuse_bpf_aio_request_cachep = kmem_cache_create("fuse_bpf_aio_req",
2456 						   sizeof(struct fuse_bpf_aio_req),
2457 						   0, SLAB_HWCACHE_ALIGN, NULL);
2458 	if (!fuse_bpf_aio_request_cachep)
2459 		return -ENOMEM;
2460 
2461 	return 0;
2462 }
2463 
fuse_bpf_cleanup(void)2464 void __exit fuse_bpf_cleanup(void)
2465 {
2466 	kmem_cache_destroy(fuse_bpf_aio_request_cachep);
2467 }
2468 
fuse_bpf_simple_request(struct fuse_mount * fm,struct fuse_bpf_args * bpf_args)2469 ssize_t fuse_bpf_simple_request(struct fuse_mount *fm, struct fuse_bpf_args *bpf_args)
2470 {
2471 	int i;
2472 	ssize_t res;
2473 	struct fuse_args args = {
2474 		.nodeid = bpf_args->nodeid,
2475 		.opcode = bpf_args->opcode,
2476 		.error_in = bpf_args->error_in,
2477 		.in_numargs = bpf_args->in_numargs,
2478 		.out_numargs = bpf_args->out_numargs,
2479 		.force = !!(bpf_args->flags & FUSE_BPF_FORCE),
2480 		.out_argvar = !!(bpf_args->flags & FUSE_BPF_OUT_ARGVAR),
2481 	};
2482 
2483 	for (i = 0; i < args.in_numargs; ++i)
2484 		args.in_args[i] = (struct fuse_in_arg) {
2485 			.size = bpf_args->in_args[i].size,
2486 			.value = bpf_args->in_args[i].value,
2487 		};
2488 	for (i = 0; i < args.out_numargs; ++i)
2489 		args.out_args[i] = (struct fuse_arg) {
2490 			.size = bpf_args->out_args[i].size,
2491 			.value = bpf_args->out_args[i].value,
2492 		};
2493 
2494 	res = fuse_simple_request(fm, &args);
2495 
2496 	*bpf_args = (struct fuse_bpf_args) {
2497 		.nodeid = args.nodeid,
2498 		.opcode = args.opcode,
2499 		.error_in = args.error_in,
2500 		.in_numargs = args.in_numargs,
2501 		.out_numargs = args.out_numargs,
2502 	};
2503 	if (args.force)
2504 		bpf_args->flags |= FUSE_BPF_FORCE;
2505 	if (args.out_argvar)
2506 		bpf_args->flags |= FUSE_BPF_OUT_ARGVAR;
2507 	for (i = 0; i < args.in_numargs; ++i)
2508 		bpf_args->in_args[i] = (struct fuse_bpf_in_arg) {
2509 			.size = args.in_args[i].size,
2510 			.value = args.in_args[i].value,
2511 		};
2512 	for (i = 0; i < args.out_numargs; ++i)
2513 		bpf_args->out_args[i] = (struct fuse_bpf_arg) {
2514 			.size = args.out_args[i].size,
2515 			.value = args.out_args[i].value,
2516 		};
2517 	return res;
2518 }
2519