[Devel] [PATCH RHEL8 COMMIT] fs/fuse kio: avoid race condition at file expand

Konstantin Khorenko khorenko at virtuozzo.com
Fri Apr 23 11:55:00 MSK 2021


The commit is pushed to "branch-rh8-4.18.0-240.1.1.vz8.5.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh8-4.18.0-240.1.1.vz8.5.19
------>
commit 6661b1614b64cb6d377d595e85c2f72bd7834726
Author: Alexey Kuznetsov <kuznet at acronis.com>
Date:   Fri Apr 23 11:55:00 2021 +0300

    fs/fuse kio: avoid race condition at file expand
    
    Update inode size after mappings are invalidated, not before.
    
    It was possible that new write request arrives right after
    inode size increased, but before maps are invalidated.
    This will result in write using an orphaned map.
    
    https://pmc.acronis.com/browse/VSTOR-36154
    
    Signed-off-by: Alexey Kuznetsov <kuznet at acronis.com>
    Reviewed-by: Ildar Ismagilov <ildar.ismagilov at virtuozzo.com>
    Signed-off-by: Ildar Ismagilov <ildar.ismagilov at virtuozzo.com>
---
 fs/fuse/kio/pcs/pcs_fuse_kdirect.c | 13 ++++++-------
 fs/fuse/kio/pcs/pcs_map.c          |  4 ++--
 fs/fuse/kio/pcs/pcs_map.h          |  2 +-
 3 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
index 7c703b6bf8fc..67132d4dc8c4 100644
--- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
+++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
@@ -1041,7 +1041,6 @@ static void kpcs_setattr_end(struct fuse_conn *fc, struct fuse_args *args, int e
 	struct fuse_setattr_in *inarg = (void*) args->in_args[0].value;
 	struct fuse_attr_out *outarg = (void*) args->out_args[0].value;
 	struct pcs_dentry_info *di = pcs_inode_from_fuse(fi);
-	u64 old_size;
 
 	BUG_ON(req->in.h.opcode != FUSE_SETATTR);
 	TRACE("update size: ino:%lu old_sz:%lld new:%lld, error: %d\n",
@@ -1051,18 +1050,18 @@ static void kpcs_setattr_end(struct fuse_conn *fc, struct fuse_args *args, int e
 	if (error)
 		goto fail;
 
-	spin_lock(&di->lock);
-	old_size = di->fileinfo.attr.size;
-	di->fileinfo.attr.size = outarg->attr.size;
-	spin_unlock(&di->lock);
-
 	if (outarg->attr.size == inarg->size)
-		pcs_mapping_truncate(di, old_size);
+		pcs_mapping_truncate(di, outarg->attr.size);
 	else {
 		pr_err("kio: failed to set requested size: %llu %llu\n",
 			outarg->attr.size, inarg->size);
 		error = req->out.h.error = -EIO;
 	}
+
+	spin_lock(&di->lock);
+	di->fileinfo.attr.size = outarg->attr.size;
+	spin_unlock(&di->lock);
+
 fail:
 	if(r->end)
 		r->end(fc, args, error);
diff --git a/fs/fuse/kio/pcs/pcs_map.c b/fs/fuse/kio/pcs/pcs_map.c
index 4819fff742fa..592cc3a55847 100644
--- a/fs/fuse/kio/pcs/pcs_map.c
+++ b/fs/fuse/kio/pcs/pcs_map.c
@@ -2507,9 +2507,9 @@ void process_ireq_truncate(struct pcs_int_request *ireq)
  * user space already has good map with newer version it will return it
  * immediately and kernel/user will be in sync again.
  */
-noinline void pcs_mapping_truncate(struct pcs_dentry_info *di, u64 old_size)
+noinline void pcs_mapping_truncate(struct pcs_dentry_info *di, u64 new_size)
 {
-	u64 new_size = DENTRY_SIZE(di), offset;
+	u64 old_size = DENTRY_SIZE(di), offset;
 	struct pcs_map_entry *m;
 
 	di->local_mtime = get_real_time_ms();
diff --git a/fs/fuse/kio/pcs/pcs_map.h b/fs/fuse/kio/pcs/pcs_map.h
index 93cc04199845..a6a4ee877bff 100644
--- a/fs/fuse/kio/pcs/pcs_map.h
+++ b/fs/fuse/kio/pcs/pcs_map.h
@@ -164,7 +164,7 @@ void pcs_mapping_init(struct pcs_cluster_core *cc, struct pcs_mapping * mapping)
 void pcs_mapping_open(struct pcs_mapping * mapping);
 void pcs_mapping_invalidate(struct pcs_mapping * mapping);
 void pcs_mapping_deinit(struct pcs_mapping * mapping);
-void pcs_mapping_truncate(struct pcs_dentry_info *di, u64 old_size);
+void pcs_mapping_truncate(struct pcs_dentry_info *di, u64 new_size);
 void process_ireq_truncate(struct pcs_int_request *ireq);
 
 struct pcs_map_entry * pcs_find_get_map(struct pcs_dentry_info * de, u64 chunk);


More information about the Devel mailing list