Skip to contentSkip to conversation

Patch "xfs: fix eofblocks race with file extending async dio writes" has been added to the 4.9-stable tree

PATCH [email protected] 1 participant 1 message Apr 1, 2017

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

xfs: fix eofblocks race with file extending async dio writes

to the 4.9-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:
xfs-fix-eofblocks-race-with-file-extending-async-dio-writes.patch
and it can be found in the queue-4.9 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 e4229d6b0bc9280f29624faf170cf76a9f1ca60e Mon Sep 17 00:00:00 2001

From: Brian Foster <[email protected]>
Date: Fri, 27 Jan 2017 23:22:57 -0800
Subject: xfs: fix eofblocks race with file extending async dio writes

From: Brian Foster <[email protected]>

commit e4229d6b0bc9280f29624faf170cf76a9f1ca60e upstream.

It's possible for post-eof blocks to end up being used for direct I/O writes. dio write performs an upfront unwritten extent allocation, sends the dio and then updates the inode size (if necessary) on write completion. If a file release occurs while a file extending dio write is in flight, it is possible to mistake the post-eof blocks for speculative preallocation and incorrectly truncate them from the inode. This means that the resulting dio write completion can discover a hole and allocate new blocks rather than perform unwritten extent conversion.

This requires a strange mix of I/O and is thus not likely to reproduce in real world workloads. It is intermittently reproduced by generic/299. The error manifests as an assert failure due to transaction overrun because the aforementioned write completion transaction has only reserved enough blocks for btree operations:

  XFS: Assertion failed: tp->t_blk_res_used <= tp->t_blk_res, \
   file: fs/xfs//xfs_trans.c, line: 309

The root cause is that xfs_free_eofblocks() uses i_size to truncate post-eof blocks from the inode, but async, file extending direct writes do not update i_size until write completion, long after inode locks are dropped. Therefore, xfs_free_eofblocks() effectively truncates the inode to the incorrect size.

Update xfs_free_eofblocks() to serialize against dio similar to how extending writes are serialized against i_size updates before post-eof block zeroing. Specifically, wait on dio while under the iolock. This ensures that dio write completions have updated i_size before post-eof blocks are processed.

---
 fs/xfs/xfs_bmap_util.c |    3 +++
 1 file changed, 3 insertions(+)
fs/xfs/xfs_bmap_util.c +3 -0
@@ -959,6 +959,9 @@ xfs_free_eofblocks(
 		if (error)
 			return error;
 
+		/* wait on dio to ensure i_size has settled */
+		inode_dio_wait(VFS_I(ip));
+
 		error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0,
 				&tp);
 		if (error) {

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

queue-4.9/xfs-use-iomap-new-flag-for-newly-allocated-delalloc-blocks.patch queue-4.9/xfs-handle-indlen-shortage-on-delalloc-extent-merge.patch queue-4.9/xfs-reject-all-unaligned-direct-writes-to-reflinked-files.patch queue-4.9/xfs-don-t-fail-xfs_extent_busy-allocation.patch queue-4.9/xfs-sync-eofblocks-scans-under-iolock-are-livelock-prone.patch queue-4.9/xfs-pull-up-iolock-from-xfs_free_eofblocks.patch queue-4.9/xfs-split-indlen-reservations-fairly-when-under-reserved.patch queue-4.9/xfs-fix-eofblocks-race-with-file-extending-async-dio-writes.patch queue-4.9/xfs-fix-uninitialized-variable-in-_reflink_convert_cow.patch queue-4.9/xfs-don-t-reserve-blocks-for-right-shift-transactions.patch