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 <[email protected]> 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 <[email protected]> > --- > 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) _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
