diff mbox series

[3/3] xfs: ensure log flush at the end of a synchronous fallocate call

Message ID 164316354060.2600373.8627019780419133722.stgit@magnolia (mailing list archive)
State New
Headers show
Series xfs: fix permission drop and flushing in fallocate | expand

Commit Message

Darrick J. Wong Jan. 26, 2022, 2:19 a.m. UTC
From: Darrick J. Wong <djwong@kernel.org>

If the caller wanted us to persist the preallocation to disk before
returning to userspace, make sure we force the log to disk after making
all metadata updates.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 fs/xfs/xfs_file.c |   23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index fb82a61696f0..8f2372b96fc4 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -929,6 +929,7 @@  xfs_file_fallocate(
 	uint			iolock = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL;
 	loff_t			new_size = 0;
 	bool			do_file_insert = false;
+	bool			flush_log;
 
 	if (!S_ISREG(inode->i_mode))
 		return -EINVAL;
@@ -1081,12 +1082,14 @@  xfs_file_fallocate(
 	 * If we need to change the PREALLOC flag, do so.  We already updated
 	 * the timestamps and cleared the suid flags, so we don't need to do
 	 * that again.  This must be committed before the size change so that
-	 * we don't trim post-EOF preallocations.
+	 * we don't trim post-EOF preallocations.  If this is the last
+	 * transaction we're going to make, make the update synchronous too.
 	 */
+	flush_log = xfs_file_sync_writes(file);
 	if (flags) {
 		flags |= XFS_PREALLOC_INVISIBLE;
 
-		if (xfs_file_sync_writes(file))
+		if (flush_log && !(do_file_insert || new_size))
 			flags |= XFS_PREALLOC_SYNC;
 
 		error = xfs_update_prealloc_flags(ip, flags);
@@ -1112,8 +1115,22 @@  xfs_file_fallocate(
 	 * leave shifted extents past EOF and hence losing access to
 	 * the data that is contained within them.
 	 */
-	if (do_file_insert)
+	if (do_file_insert) {
 		error = xfs_insert_file_space(ip, offset, len);
+		if (error)
+			goto out_unlock;
+	}
+
+	/*
+	 * If the caller wants us to flush the log and either we've made
+	 * changes since updating the PREALLOC flag or we didn't need to
+	 * update the PREALLOC flag, then flush the log now.
+	 */
+	if (flush_log && (do_file_insert || new_size || flags == 0)) {
+		error = xfs_log_force_inode(ip);
+		if (error)
+			goto out_unlock;
+	}
 
 out_unlock:
 	xfs_iunlock(ip, iolock);