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