diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index 269a4dfd76d8..435b83893944 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -295,44 +295,19 @@ void *fuse_create_open_finalize( } int fuse_release_initialize(struct fuse_bpf_args *fa, struct fuse_release_in *fri, - struct inode *inode, struct file *file) + struct inode *inode, struct fuse_file *ff) { - struct fuse_file *fuse_file = file->private_data; - /* Always put backing file whatever bpf/userspace says */ - fput(fuse_file->backing_file); + fput(ff->backing_file); *fri = (struct fuse_release_in) { - .fh = ((struct fuse_file *)(file->private_data))->fh, + .fh = ff->fh, }; *fa = (struct fuse_bpf_args) { .nodeid = get_fuse_inode(inode)->nodeid, - .opcode = FUSE_RELEASE, - .in_numargs = 1, - .in_args[0].size = sizeof(*fri), - .in_args[0].value = fri, - }; - - return 0; -} - -int fuse_releasedir_initialize(struct fuse_bpf_args *fa, - struct fuse_release_in *fri, - struct inode *inode, struct file *file) -{ - struct fuse_file *fuse_file = file->private_data; - - /* Always put backing file whatever bpf/userspace says */ - fput(fuse_file->backing_file); - - *fri = (struct fuse_release_in) { - .fh = ((struct fuse_file *)(file->private_data))->fh, - }; - - *fa = (struct fuse_bpf_args) { - .nodeid = get_fuse_inode(inode)->nodeid, - .opcode = FUSE_RELEASEDIR, + .opcode = S_ISDIR(inode->i_mode) ? FUSE_RELEASEDIR + : FUSE_RELEASE, .in_numargs = 1, .in_args[0].size = sizeof(*fri), .in_args[0].value = fri, @@ -342,15 +317,14 @@ int fuse_releasedir_initialize(struct fuse_bpf_args *fa, } int fuse_release_backing(struct fuse_bpf_args *fa, - struct inode *inode, struct file *file) + struct inode *inode, struct fuse_file *ff) { return 0; } void *fuse_release_finalize(struct fuse_bpf_args *fa, - struct inode *inode, struct file *file) + struct inode *inode, struct fuse_file *ff) { - fuse_file_free(file->private_data); return NULL; } diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index dd184a36dc55..933e4a727505 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1790,17 +1790,6 @@ static int fuse_dir_open(struct inode *inode, struct file *file) static int fuse_dir_release(struct inode *inode, struct file *file) { -#ifdef CONFIG_FUSE_BPF - struct fuse_err_ret fer; - - fer = fuse_bpf_backing(inode, struct fuse_release_in, - fuse_releasedir_initialize, fuse_release_backing, - fuse_release_finalize, - inode, file); - if (fer.ret) - return PTR_ERR(fer.result); -#endif - fuse_release_common(file, true); return 0; } diff --git a/fs/fuse/file.c b/fs/fuse/file.c index d37f90b3c59f..923a0fbc698f 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -104,25 +104,39 @@ static void fuse_release_end(struct fuse_mount *fm, struct fuse_args *args, kfree(ra); } -static void fuse_file_put(struct fuse_file *ff, bool sync, bool isdir) +static void fuse_file_put(struct inode *inode, struct fuse_file *ff, + bool sync, bool isdir) { - if (refcount_dec_and_test(&ff->count)) { - struct fuse_args *args = &ff->release_args->args; + struct fuse_args *args = &ff->release_args->args; +#ifdef CONFIG_FUSE_BPF + struct fuse_err_ret fer; +#endif - if (isdir ? ff->fm->fc->no_opendir : ff->fm->fc->no_open) { - /* Do nothing when client does not implement 'open' */ - fuse_release_end(ff->fm, args, 0); - } else if (sync) { - fuse_simple_request(ff->fm, args); - fuse_release_end(ff->fm, args, 0); - } else { - args->end = fuse_release_end; - if (fuse_simple_background(ff->fm, args, - GFP_KERNEL | __GFP_NOFAIL)) - fuse_release_end(ff->fm, args, -ENOTCONN); - } - kfree(ff); + if (!refcount_dec_and_test(&ff->count)) + return; + +#ifdef CONFIG_FUSE_BPF + fer = fuse_bpf_backing(inode, struct fuse_release_in, + fuse_release_initialize, fuse_release_backing, + fuse_release_finalize, + inode, ff); + if (fer.ret) { + fuse_release_end(ff->fm, args, 0); + } else +#endif + if (isdir ? ff->fm->fc->no_opendir : ff->fm->fc->no_open) { + /* Do nothing when client does not implement 'open' */ + fuse_release_end(ff->fm, args, 0); + } else if (sync) { + fuse_simple_request(ff->fm, args); + fuse_release_end(ff->fm, args, 0); + } else { + args->end = fuse_release_end; + if (fuse_simple_background(ff->fm, args, + GFP_KERNEL | __GFP_NOFAIL)) + fuse_release_end(ff->fm, args, -ENOTCONN); } + kfree(ff); } struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid, @@ -343,7 +357,7 @@ void fuse_file_release(struct inode *inode, struct fuse_file *ff, * synchronous RELEASE is allowed (and desirable) in this case * because the server can be trusted not to screw up. */ - fuse_file_put(ff, ff->fm->fc->destroy, isdir); + fuse_file_put(ra->inode, ff, ff->fm->fc->destroy, isdir); } void fuse_release_common(struct file *file, bool isdir) @@ -361,17 +375,6 @@ static int fuse_release(struct inode *inode, struct file *file) { struct fuse_conn *fc = get_fuse_conn(inode); -#ifdef CONFIG_FUSE_BPF - struct fuse_err_ret fer; - - fer = fuse_bpf_backing(inode, struct fuse_release_in, - fuse_release_initialize, fuse_release_backing, - fuse_release_finalize, - inode, file); - if (fer.ret) - return PTR_ERR(fer.result); -#endif - /* * Dirty pages might remain despite write_inode_now() call from * fuse_flush() due to writes racing with the close. @@ -394,7 +397,7 @@ void fuse_sync_release(struct fuse_inode *fi, struct fuse_file *ff, * iput(NULL) is a no-op and since the refcount is 1 and everything's * synchronous, we are fine with not doing igrab() here" */ - fuse_file_put(ff, true, false); + fuse_file_put(&fi->inode, ff, true, false); } EXPORT_SYMBOL_GPL(fuse_sync_release); @@ -972,8 +975,11 @@ static void fuse_readpages_end(struct fuse_mount *fm, struct fuse_args *args, unlock_page(page); put_page(page); } - if (ia->ff) - fuse_file_put(ia->ff, false, false); + if (ia->ff) { + WARN_ON(!mapping); + fuse_file_put(mapping ? mapping->host : NULL, ia->ff, + false, false); + } fuse_io_free(ia); } @@ -1716,7 +1722,7 @@ static void fuse_writepage_free(struct fuse_writepage_args *wpa) __free_page(ap->pages[i]); if (wpa->ia.ff) - fuse_file_put(wpa->ia.ff, false, false); + fuse_file_put(wpa->inode, wpa->ia.ff, false, false); kfree(ap->pages); kfree(wpa); @@ -1971,7 +1977,7 @@ int fuse_write_inode(struct inode *inode, struct writeback_control *wbc) ff = __fuse_write_file_get(fi); err = fuse_flush_times(inode, ff); if (ff) - fuse_file_put(ff, false, false); + fuse_file_put(inode, ff, false, false); return err; } @@ -2369,7 +2375,7 @@ static int fuse_writepages(struct address_space *mapping, fuse_writepages_send(&data); } if (data.ff) - fuse_file_put(data.ff, false, false); + fuse_file_put(inode, data.ff, false, false); kfree(data.orig_pages); out: diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index a659c89cc685..af20800db6c2 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1536,14 +1536,11 @@ void *fuse_link_finalize(struct fuse_bpf_args *fa, struct dentry *entry, struct inode *dir, struct dentry *newent); int fuse_release_initialize(struct fuse_bpf_args *fa, struct fuse_release_in *fri, - struct inode *inode, struct file *file); -int fuse_releasedir_initialize(struct fuse_bpf_args *fa, - struct fuse_release_in *fri, - struct inode *inode, struct file *file); + struct inode *inode, struct fuse_file *ff); int fuse_release_backing(struct fuse_bpf_args *fa, - struct inode *inode, struct file *file); + struct inode *inode, struct fuse_file *ff); void *fuse_release_finalize(struct fuse_bpf_args *fa, - struct inode *inode, struct file *file); + struct inode *inode, struct fuse_file *ff); int fuse_flush_initialize(struct fuse_bpf_args *fa, struct fuse_flush_in *ffi, struct file *file, fl_owner_t id);