[Devel] [PATCH VZ10 v2] fs/fuse: align fuse_create_open()'s open path with fuse_open()
Alexey Kuznetsov
kuznet at virtuozzo.com
Tue Jun 23 17:10:13 MSK 2026
Acknowledged
This was awful place traced back to day zero. fuse_create_open branch
was completely broken,
would oops or corrupt the state on any error and was left without attention.
It is just plain luck these error paths were not triggered ever, any
failure would have major consequences.
On Tue, Jun 23, 2026 at 2:56 PM Liu Kui <kui.liu at virtuozzo.com> wrote:
>
> fuse_create_open()'s close_wait branch was not correct -- in particular
> the fput() in its error path was wrong; fuse_open()'s close_wait branch
> should apply instead. Refactor the close_wait branch into a new
> function used in both places. fuse_sync_release() applies to the
> close_wait error path in both places.
>
> Signed-off-by: Liu Kui <kui.liu at virtuozzo.com>
> ---
> Changes in v2:
> - Factor the close_wait open branch into fuse_open_close_wait();
> call it from both fuse_open() and fuse_create_open() instead of
> duplicating the block in each.
> - Use fuse_sync_release() on the close_wait error path for both
> callers. It is functionally equivalent to fuse_release_common()
> used in fuse_open().
>
> fs/fuse/dir.c | 18 ++-----------
> fs/fuse/file.c | 67 +++++++++++++++++++++++++++---------------------
> fs/fuse/fuse_i.h | 1 +
> 3 files changed, 41 insertions(+), 45 deletions(-)
>
> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> index 45ee4f1e4b68..2faf052632d6 100644
> --- a/fs/fuse/dir.c
> +++ b/fs/fuse/dir.c
> @@ -722,22 +722,8 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir,
> invalidate_inode_pages2(inode->i_mapping);
> }
>
> - if (fm->fc->close_wait) {
> - struct fuse_inode *fi = get_fuse_inode(inode);
> - bool need_open;
> -
> - inode_lock(inode);
> - spin_lock(&fi->lock);
> - need_open = (++fi->num_openers == 1);
> - spin_unlock(&fi->lock);
> -
> - if (need_open && fm->fc->kio.op && fm->fc->kio.op->file_open) {
> - err = fm->fc->kio.op->file_open(file, inode);
> - if (err)
> - fput(file);
> - }
> - inode_unlock(inode);
> - }
> + if (!err && fm->fc->close_wait)
> + err = fuse_open_close_wait(inode, file);
>
> return err;
>
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index 58202a96517e..faf39887125a 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -337,6 +337,42 @@ static void fuse_truncate_update_attr(struct inode *inode, struct file *file)
> fuse_invalidate_attr_mask(inode, FUSE_STATX_MODSIZE);
> }
>
> +int fuse_open_close_wait(struct inode *inode, struct file *file)
> +{
> + struct fuse_conn *fc = get_fuse_conn(inode);
> + struct fuse_inode *fi = get_fuse_inode(inode);
> + struct fuse_file *ff = file->private_data;
> + int err = 0;
> +
> + inode_lock(inode);
> + spin_lock(&fi->lock);
> +
> + if (++fi->num_openers == 1 || fi->i_size_unstable) {
> + fi->i_size_unstable = 1;
> + fi->inval_mask = ~0;
> + spin_unlock(&fi->lock);
> + err = fuse_update_attributes(inode, file, ~0);
> +
> + if (!err && fc->kio.op && fc->kio.op->file_open)
> + err = fc->kio.op->file_open(file, inode);
> +
> + spin_lock(&fi->lock);
> + fi->i_size_unstable = 0;
> + if (err)
> + fi->num_openers--;
> + }
> +
> + file->f_mode |= FMODE_NOWAIT;
> +
> + spin_unlock(&fi->lock);
> + inode_unlock(inode);
> +
> + if (err)
> + fuse_sync_release(fi, ff, file->f_flags);
> +
> + return err;
> +}
> +
> static int fuse_open(struct inode *inode, struct file *file)
> {
> struct fuse_mount *fm = get_fuse_mount(inode);
> @@ -399,35 +435,8 @@ static int fuse_open(struct inode *inode, struct file *file)
> if (is_wb_truncate || dax_truncate)
> inode_unlock(inode);
>
> - if (!err && fc->close_wait) {
> - inode_lock(inode);
> - spin_lock(&fi->lock);
> -
> - if (++fi->num_openers == 1 || fi->i_size_unstable) {
> - fi->i_size_unstable = 1;
> - fi->inval_mask = ~0;
> - spin_unlock(&fi->lock);
> - err = fuse_update_attributes(inode, file, ~0);
> -
> - if (!err && fc->kio.op && fc->kio.op->file_open)
> - err = fc->kio.op->file_open(file, inode);
> -
> - spin_lock(&fi->lock);
> - fi->i_size_unstable = 0;
> - if (err)
> - fi->num_openers--;
> - }
> -
> - file->f_mode |= FMODE_NOWAIT;
> -
> - spin_unlock(&fi->lock);
> - inode_unlock(inode);
> -
> - if (err) {
> - fuse_release_common(file, false);
> - return err;
> - }
> - }
> + if (!err && fc->close_wait)
> + err = fuse_open_close_wait(inode, file);
>
> return err;
> }
> diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> index a834a5b4dfe2..6f462f0c4c3c 100644
> --- a/fs/fuse/fuse_i.h
> +++ b/fs/fuse/fuse_i.h
> @@ -1317,6 +1317,7 @@ void fuse_read_args_fill(struct fuse_io_args *ia, struct file *file, loff_t pos,
> struct fuse_file *fuse_file_alloc(struct fuse_mount *fm, bool release);
> void fuse_file_free(struct fuse_file *ff);
> int fuse_finish_open(struct inode *inode, struct file *file);
> +int fuse_open_close_wait(struct inode *inode, struct file *file);
>
> void fuse_sync_release(struct fuse_inode *fi, struct fuse_file *ff,
> unsigned int flags);
> --
> 2.50.1 (Apple Git-155)
More information about the Devel
mailing list