Skip to contentSkip to conversation

Patch "Btrfs: fix race when checking if we can skip fsync'ing an inode" has been added to the 4.5-stable tree

PATCH [email protected] 1 participant 1 message May 17, 2016

Subsystems (2)
lore
Share & tools
lore

[email protected]

author maintainer Applied
#0 lore raw

This is a note to let you know that I've just added the patch titled

Btrfs: fix race when checking if we can skip fsync'ing an inode

to the 4.5-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
btrfs-fix-race-when-checking-if-we-can-skip-fsync-ing-an-inode.patch
and it can be found in the queue-4.5 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.

Quoted 1 line

From affc0ff902d539ebe9bba405d330410314f46e9f Mon Sep 17 00:00:00 2001

From: Filipe Manana <[email protected]>
Date: Wed, 24 Feb 2016 07:35:05 +0000
Subject: Btrfs: fix race when checking if we can skip fsync'ing an inode

From: Filipe Manana <[email protected]>

commit affc0ff902d539ebe9bba405d330410314f46e9f upstream.

If we're about to do a fast fsync for an inode and btrfs_inode_in_log() returns false, it's possible that we had an ordered extent in progress (btrfs_finish_ordered_io() not run yet) when we noticed that the inode's last_trans field was not greater than the id of the last committed transaction, but shortly after, before we checked if there were any ongoing ordered extents, the ordered extent had just completed and removed itself from the inode's ordered tree, in which case we end up not logging the inode, losing some data if a power failure or crash happens after the fsync handler returns and before the transaction is committed.

Fix this by checking first if there are any ongoing ordered extents before comparing the inode's last_trans with the id of the last committed transaction - when it completes, an ordered extent always updates the inode's last_trans before it removes itself from the inode's ordered tree (at btrfs_finish_ordered_io()).

---
 fs/btrfs/file.c |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)
fs/btrfs/file.c +5 -4
@@ -1996,10 +1996,11 @@ int btrfs_sync_file(struct file *file, l
 	 */
 	smp_mb();
 	if (btrfs_inode_in_log(inode, root->fs_info->generation) ||
-	    (BTRFS_I(inode)->last_trans <=
-	     root->fs_info->last_trans_committed &&
-	     (full_sync ||
-	      !btrfs_have_ordered_extents_in_range(inode, start, len)))) {
+	    (full_sync && BTRFS_I(inode)->last_trans <=
+	     root->fs_info->last_trans_committed) ||
+	    (!btrfs_have_ordered_extents_in_range(inode, start, len) &&
+	     BTRFS_I(inode)->last_trans
+	     <= root->fs_info->last_trans_committed)) {
 		/*
 		 * We'v had everything committed since the last time we were
 		 * modified so clear this flag in case it was set for whatever

Patches currently in stable-queue which might be from [email protected] are

queue-4.5/btrfs-do-not-collect-ordered-extents-when-logging-that-inode-exists.patch queue-4.5/btrfs-fix-extent_same-allowing-destination-offset-beyond-i_size.patch queue-4.5/btrfs-fix-file-loss-on-log-replay-after-renaming-a-file-and-fsync.patch queue-4.5/btrfs-fix-deadlock-between-direct-io-reads-and-buffered-writes.patch queue-4.5/btrfs-fix-unreplayable-log-after-snapshot-delete-parent-dir-fsync.patch queue-4.5/btrfs-fix-race-when-checking-if-we-can-skip-fsync-ing-an-inode.patch