[Devel] [PATCH RHEL10 COMMIT] ext4: rework mfsync support

Konstantin Khorenko khorenko at virtuozzo.com
Mon Aug 25 11:12:35 MSK 2025


The commit is pushed to "branch-rh10-6.12.0-55.13.1.vz10.2.x-ovz" and will appear at git at bitbucket.org:openvz/vzkernel.git
after rh10-6.12.0-55.13.1.el10
------>
commit c6c508d868017d32a6580464e211f89ddcbd8433
Author: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
Date:   Fri Aug 1 12:07:12 2025 +0800

    ext4: rework mfsync support
    
    General improvements:
    
    * Remove unused datawriteback.
    * Check nr_files before accesing members in files[0].
    * Remove excess {} in oneliner if condition.
    * Check lack of journal early.
    * Remove and add some newlines and spaces to improve readability.
    * Add err3 to fix error handling in blkdev_issue_flush error path.
    * Fix multi-line comment stile.
    
    Make similar changes like in mainstream in ext4_sync_file:
    
    * Replace J_ASSERT to ASSERT similar to [1].
    * Remove inode_lock as it's not needed after [2].
    * Force commit only for non-regular files, similar to [3] + [4].
    * Use ext4_fc_commit instead of jbd2_complete_transaction as in [5].
    * Track writeback errors in ext4_sync_files as in [6].
    
    837c23fbc1b8 ("ext4: use ASSERT() to replace J_ASSERT()") [1]
    92e6222dfb85 ("ext4: remove i_mutex from ext4_file_sync()") [2]
    e360c6ed7274 ("ext4: Drop special handling of journalled data from ext4_sync_file()") [3]
    1077b2d53ef5 ("ext4: fix fsync for non-directories") [4]
    aa75f4d3daae ("ext4: main fast-commit commit path") [5]
    95cb67138746 ("ext4: track writeback errors using the generic trackinginfrastructure") [6]
    
    https://virtuozzo.atlassian.net/browse/VSTOR-107255
    Fixes: 26337aacaafa9 ("ext4: add mfsync support")
    Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
    
    Feature: ext4: optimized sync of a set of files - mfsync()
---
 fs/ext4/fsync.c | 55 +++++++++++++++++++++++++++++++++----------------------
 1 file changed, 33 insertions(+), 22 deletions(-)

diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
index 9819848c17a3..7c583d709167 100644
--- a/fs/ext4/fsync.c
+++ b/fs/ext4/fsync.c
@@ -180,40 +180,45 @@ int ext4_sync_files(struct file **files, unsigned int *flags, unsigned int nr_fi
 {
 	struct super_block *sb;
 	journal_t *journal;
-	int err = 0, err2 = 0, i = 0, j = 0;
-	int force_commit = 0, datawriteback = 0;
+	int err = 0, err2 = 0, err3 = 0;
+	int i = 0, j = 0;
+	int force_commit = 0;
 	tid_t commit_tid = 0;
 	int need_barrier = 0;
 	int ret;
 
+	if (!nr_files)
+		return 0;
 	sb = files[0]->f_mapping->host->i_sb;
+
 	ret = ext4_emergency_state(sb);
 	if (unlikely(ret))
 		return ret;
 
-	J_ASSERT(ext4_journal_current_handle() == NULL);
-	if (!nr_files)
+	ASSERT(ext4_journal_current_handle() == NULL);
+
+	if (sb_rdonly(sb))
 		return 0;
 
 	journal = EXT4_SB(sb)->s_journal;
-	if (sb_rdonly(sb)) {
-		return 0;
-	}
+	if (!journal)
+		 return -ENOTSUPP;
+
 	for (i = 0; i < nr_files; i++) {
-		struct address_space * mapping = files[i]->f_mapping;
+		struct address_space *mapping = files[i]->f_mapping;
 		struct inode *inode = mapping->host;
 
 		if (sb != inode->i_sb) {
 			err = -EINVAL;
 			goto out;
 		}
+
 		if (!mapping->nrpages)
 			continue;
 
 		err = filemap_fdatawrite(mapping);
 		if (err)
 			break;
-
 	}
 	/*
 	 * Even if the above returned error, the pages may be
@@ -225,7 +230,7 @@ int ext4_sync_files(struct file **files, unsigned int *flags, unsigned int nr_fi
 		goto out;
 
 	for (j = 0; j < i; j++) {
-		struct address_space * mapping = files[j]->f_mapping;
+		struct address_space *mapping = files[j]->f_mapping;
 		struct inode *inode = mapping->host;
 		struct ext4_inode_info *ei = EXT4_I(inode);
 		unsigned int datasync = flags[j];
@@ -237,21 +242,17 @@ int ext4_sync_files(struct file **files, unsigned int *flags, unsigned int nr_fi
 				err = err2;
 		}
 
-		inode_lock_shared(inode);
-		force_commit  |= ext4_should_journal_data(inode);
-		datawriteback |= ext4_should_writeback_data(inode);
+		force_commit |= !S_ISREG(inode->i_mode);
 		tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid;
-		inode_unlock_shared(inode);
 		trace_ext4_sync_files_iterate(files[j]->f_path.dentry, tid, datasync);
 		if (j == 0 || !tid_geq(commit_tid, tid))
 			commit_tid = tid;
 	}
 
 	/* Ext4 specific stuff starts here */
-	if (!journal) {
-		 return -ENOTSUPP;
-	} else if (force_commit) {
-		/* data=journal:
+	if (force_commit) {
+		/*
+		 * data=journal:
 		 *  filemap_fdatawrite won't do anything (the buffers are clean).
 		 *  ext4_force_commit will write the file data into the journal and
 		 *  will wait on that.
@@ -271,17 +272,27 @@ int ext4_sync_files(struct file **files, unsigned int *flags, unsigned int nr_fi
 		    !jbd2_trans_will_send_data_barrier(journal, commit_tid))
 			need_barrier = true;
 
-		err2 = jbd2_complete_transaction(journal, commit_tid);
-		/* Even if we had to wait for commit completion, it does not
+		err2 = ext4_fc_commit(journal, commit_tid);
+		/*
+		 * Even if we had to wait for commit completion, it does not
 		 * mean a flush has been issued after data demanded by this
 		 * fsync were written back. Commit could be in state after
 		 * it is already done, but not yet in state where we should
 		 * not wait.
 		 */
-		if (need_barrier)
-			err2 = blkdev_issue_flush(sb->s_bdev);
+		if (need_barrier) {
+			err3 = blkdev_issue_flush(sb->s_bdev);
+			if (!err2 || err3 == -EIO)
+				err2 = err3;
+		}
 	}
 out:
+	for (i = 0; i < nr_files; i++) {
+		err3 = file_check_and_advance_wb_err(files[i]);
+		if (!err2 || err3 == -EIO)
+			err2 = err3;
+	}
+
 	trace_ext4_sync_files_exit(files[0]->f_path.dentry, commit_tid, need_barrier);
 	if (!err || err2 == -EIO)
 		err = err2;


More information about the Devel mailing list