The commit is pushed to "branch-rh10-6.12.0-55.13.1.2.x.vz10-ovz" and will 
appear at [email protected]:openvz/vzkernel.git
after rh10-6.12.0-55.13.1.2.26.vz10
------>
commit acd31bc9817a263ceced79bf43c56c58ef65a46d
Author: Alexey Kuznetsov <[email protected]>
Date:   Mon Dec 22 18:08:32 2025 +0800

    fs/fuse: vstorage specific file attribute maintenance
    
    rhel10 has a few of changes which broke inode attributes consistency.
    
    An explanation is needed. Long ago we merged our support of writeback cache
    to mainstream in hope it is maintained w/o our further efforts.
    This did not work. Not that it did not, it is maintained, unfortunately
    it has very few, if any, users but us, nobody actually needs for fuse
    to perform decently. AFAIK ntfs-3g was the only backend using it,
    if someone knows another backend, please, tell me,
    we need to keep track of them.
    
    Actually, changes in rhel10 are not invalid, they are even good, but
    they rely on assumption that backend fs has no external impact.
    If fs is mounted, only this instanse of fuse can change it.
    The assumption is fair, but this is not actually the thing
    we need. Our fs is kind of hybrid: we must behave as genuine
    writeback_cache fs on files which are open by us, but we still behave
    as not cacheing fuse when file is not open. Obviously, mainstream
    is not able to maintain such mode.
    
    So, fix it. In fact this patch is 99% pure cleanup, it undoes our
    previous hacks and reduces differences of mainstream
    and replaces them with oneliner, see function fuse_get_cache_mask().
    
    Also, partial audit of our use of fc->writeback_cache flag has
    been done and in places where it actually had nothing to do with
    mainstream writeback_cache, they are replaced with our private
    flag fc->close_wait, which is strictly specific to vstorage.
    Remember, if this mode still has other users we have no right
    to violate their assumptions.
    
    Also, while audit an old bug has been discovered. After an inode
    is revoked we did some efforts to refresh its attributes, neverthless
    the procedure was incorrect and actually we always had the same
    problem that we got in rhel10 after plain reopen.
    
    https://virtuozzo.atlassian.net/browse/VSTOR-120894
    
    Signed-off-by: Alexey Kuznetsov <[email protected]>
    
    Feature: vStorage
---
 fs/fuse/dir.c    | 28 ++++++----------------------
 fs/fuse/file.c   | 13 +++++--------
 fs/fuse/fuse_i.h |  2 --
 fs/fuse/inode.c  | 15 +++++++++++----
 4 files changed, 22 insertions(+), 36 deletions(-)

diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 5355ee72eadea..6637914c8f282 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -721,7 +721,7 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct 
inode *dir,
                        invalidate_inode_pages2(inode->i_mapping);
        }
 
-       if (fm->fc->writeback_cache) {
+       if (fm->fc->close_wait) {
                struct fuse_inode *fi = get_fuse_inode(inode);
                bool need_open;
 
@@ -1274,8 +1274,7 @@ static int fuse_do_statx(struct mnt_idmap *idmap, struct 
inode *inode,
 }
 
 static int fuse_do_getattr(struct mnt_idmap *idmap, struct inode *inode,
-                          struct kstat *stat, struct file *file,
-                          int get_size_form_attr)
+                          struct kstat *stat, struct file *file)
 {
        int err;
        struct fuse_getattr_in inarg;
@@ -1314,28 +1313,13 @@ static int fuse_do_getattr(struct mnt_idmap *idmap, 
struct inode *inode,
                        fuse_change_attributes(inode, &outarg.attr, NULL,
                                               ATTR_TIMEOUT(&outarg),
                                               attr_version);
-                       if (get_size_form_attr)
-                               stat->size = outarg.attr.size;
-                       else if (stat)
+                       if (stat)
                                fuse_fillattr(idmap, inode, &outarg.attr, stat);
                }
        }
        return err;
 }
 
-int fuse_getattr_size(struct inode *inode, struct file *file, u64 *size)
-{
-       struct kstat stat;
-       int err;
-
-       err = fuse_do_getattr(&nop_mnt_idmap, inode, &stat, file, 1);
-       if (err)
-               return err;
-
-       *size = stat.size;
-       return 0;
-}
-
 static int fuse_update_get_attr(struct mnt_idmap *idmap, struct inode *inode,
                                struct file *file, struct kstat *stat,
                                u32 request_mask, unsigned int flags)
@@ -1376,7 +1360,7 @@ static int fuse_update_get_attr(struct mnt_idmap *idmap, 
struct inode *inode,
                                goto retry;
                        }
                } else {
-                       err = fuse_do_getattr(idmap, inode, stat, file, 0);
+                       err = fuse_do_getattr(idmap, inode, stat, file);
                }
        } else if (stat) {
                generic_fillattr(idmap, request_mask, inode, stat);
@@ -1545,7 +1529,7 @@ static int fuse_perm_getattr(struct inode *inode, int 
mask)
                return -ECHILD;
 
        forget_all_cached_acls(inode);
-       return fuse_do_getattr(&nop_mnt_idmap, inode, NULL, NULL, 0);
+       return fuse_do_getattr(&nop_mnt_idmap, inode, NULL, NULL);
 }
 
 /*
@@ -2138,7 +2122,7 @@ static int fuse_setattr(struct mnt_idmap *idmap, struct 
dentry *entry,
                         * ia_mode calculation may have used stale i_mode.
                         * Refresh and recalculate.
                         */
-                       ret = fuse_do_getattr(idmap, inode, NULL, file, 0);
+                       ret = fuse_do_getattr(idmap, inode, NULL, file);
                        if (ret)
                                return ret;
 
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 5722cd4414318..0860996c19ad3 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -360,17 +360,17 @@ static int fuse_open(struct inode *inode, struct file 
*file)
        if (is_wb_truncate || dax_truncate)
                inode_unlock(inode);
 
-       if (!err && fc->writeback_cache) {
+       if (!err && fc->close_wait) {
                struct fuse_inode *fi = get_fuse_inode(inode);
-               u64 size;
 
                inode_lock(inode);
                spin_lock(&fi->lock);
 
-               if (++fi->num_openers == 1) {
+               if (++fi->num_openers == 1 || fi->i_size_unstable) {
                        fi->i_size_unstable = 1;
+                       fi->inval_mask = ~0;
                        spin_unlock(&fi->lock);
-                       err = fuse_getattr_size(inode, file, &size);
+                       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);
@@ -379,12 +379,9 @@ static int fuse_open(struct inode *inode, struct file 
*file)
                        fi->i_size_unstable = 0;
                        if (err)
                                fi->num_openers--;
-                       else
-                               i_size_write(inode, size);
                }
 
-               if (fc->close_wait)
-                       file->f_mode |= FMODE_NOWAIT;
+               file->f_mode |= FMODE_NOWAIT;
 
                spin_unlock(&fi->lock);
                inode_unlock(inode);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index d6c7c5fd2bdcc..853bf12e282d9 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1495,8 +1495,6 @@ void fuse_update_ctime(struct inode *inode);
 
 int fuse_update_attributes(struct inode *inode, struct file *file, u32 mask);
 
-int fuse_getattr_size(struct inode *inode, struct file *file, u64 *size);
-
 void fuse_flush_writepages(struct inode *inode);
 
 void fuse_set_nowrite(struct inode *inode);
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index c067c5922b5df..f167d275885bf 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -321,6 +321,13 @@ u32 fuse_get_cache_mask(struct inode *inode)
        if (!fc->writeback_cache || !S_ISREG(inode->i_mode))
                return 0;
 
+       if (fc->close_wait) {
+               struct fuse_inode *fi = get_fuse_inode(inode);
+
+               if (!fi->num_openers || fi->i_size_unstable)
+                       return 0;
+       }
+
        return STATX_MTIME | STATX_CTIME | STATX_SIZE;
 }
 
@@ -362,18 +369,17 @@ void fuse_change_attributes(struct inode *inode, struct 
fuse_attr *attr,
        old_mtime = inode_get_mtime(inode);
        fuse_change_attributes_common(inode, attr, sx, attr_valid, cache_mask);
 
-       oldsize = inode->i_size;
+       oldsize = i_size_read(inode);
        /*
         * In case of writeback_cache enabled, the cached writes beyond EOF
         * extend local i_size without keeping userspace server in sync. So,
         * attr->size coming from server can be stale. We cannot trust it.
         */
-       if (!(cache_mask & STATX_SIZE) ||
-           !fi->num_openers || fi->i_size_unstable)
+       if (!(cache_mask & STATX_SIZE))
                i_size_write(inode, attr->size);
        spin_unlock(&fi->lock);
 
-       if (!cache_mask && S_ISREG(inode->i_mode)) {
+       if (!cache_mask && S_ISREG(inode->i_mode) && !fc->close_wait) {
                bool inval = false;
 
                if (oldsize != attr->size) {
@@ -624,6 +630,7 @@ int fuse_invalidate_files(struct fuse_conn *fc, u64 nodeid)
                set_bit(FUSE_S_FAIL_IMMEDIATELY, &ff->ff_state);
                spin_unlock(&ff->lock);
        }
+       fi->i_size_unstable = 1;
        spin_unlock(&fi->lock);
 
        /* let them see FUSE_S_FAIL_IMMEDIATELY */
_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to