diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c index 19e690aaffb1..aad46ab272f7 100644 --- a/fs/fuse/backing.c +++ b/fs/fuse/backing.c @@ -348,44 +348,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, @@ -395,15 +370,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 b1ee3a6b5b83..e6fcb5c55f9e 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1726,17 +1726,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 bb76ba48ef32..26dd29c54cfb 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -110,25 +110,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); } int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file, @@ -346,7 +360,7 @@ void fuse_release_common(struct file *file, bool isdir) * 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); } static int fuse_open(struct inode *inode, struct file *file) @@ -358,17 +372,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 - /* see fuse_vma_close() for !writeback_cache case */ if (fc->writeback_cache) write_inode_now(inode, 1); @@ -387,7 +390,7 @@ void fuse_sync_release(struct fuse_inode *fi, struct fuse_file *ff, int flags) * 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); @@ -969,8 +972,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); } @@ -1753,7 +1759,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); @@ -2007,7 +2013,7 @@ int fuse_write_inode(struct inode *inode, struct writeback_control *wbc) ff = __fuse_write_file_get(fc, fi); err = fuse_flush_times(inode, ff); if (ff) - fuse_file_put(ff, false, false); + fuse_file_put(inode, ff, false, false); return err; } @@ -2379,7 +2385,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 ec46be93c6b5..7e4a24b2d5f7 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1452,14 +1452,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);