Patch "xfs: update i_size after unwritten conversion in dio completion" has been added to the 4.9-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
xfs: update i_size after unwritten conversion in dio completion
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-update-i_size-after-unwritten-conversion-in-dio-completion.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
ee70daaba82d70766d0723b743d9fdeb3b06102aMon Sep 17 00:00:00 2001
From: Eryu Guan <[email protected]>
Date: Thu, 21 Sep 2017 11:26:18 -0700
Subject: xfs: update i_size after unwritten conversion in dio completion
From: Eryu Guan <[email protected]>
commit ee70daaba82d70766d0723b743d9fdeb3b06102a upstream.
Since commit d531d91d6990 ("xfs: always use unwritten extents for direct I/O writes"), we start allocating unwritten extents for all direct writes to allow appending aio in XFS.
But for dio writes that could extend file size we update the in-core inode size first, then convert the unwritten extents to real allocations at dio completion time in xfs_dio_write_end_io(). Thus a racing direct read could see the new i_size and find the unwritten extents first and read zeros instead of actual data, if the direct writer also takes a shared iolock.
Fix it by updating the in-core inode size after the unwritten extent conversion. To do this, introduce a new boolean argument to xfs_iomap_write_unwritten() to tell if we want to update in-core i_size or not.
--- fs/xfs/xfs_aops.c | 25 +++++++++++++++++-------- fs/xfs/xfs_iomap.c | 7 +++++-- fs/xfs/xfs_iomap.h | 2 +- fs/xfs/xfs_pnfs.c | 2 +- 4 files changed, 24 insertions(+), 12 deletions(-)
fs/xfs/xfs_aops.c +17 -8
@@ -335,7 +335,8 @@ xfs_end_io( error =xfs_reflink_end_cow (ip, offset, size);break ;case XFS_IO_UNWRITTEN : - error =xfs_iomap_write_unwritten (ip, offset, size); +/* writeback should never update isize */ + error =xfs_iomap_write_unwritten (ip, offset, size, false);break ;default :ASSERT (!xfs_ioend_is_append (ioend) || ioend->io_append_trans);
@@ -1532,6 +1533,21 @@ xfs_end_io_direct_write(return 0 ; } +if (flags &XFS_DIO_FLAG_COW ) + error =xfs_reflink_end_cow (ip, offset, size); + +/* +* Unwritten conversion updates the in-core isize after extent +* conversion but before updating the on-disk size. Updating isize any +* earlier allows a racing dio read to find unwritten extents before +* they are converted. +*/ +if (flags &XFS_DIO_FLAG_UNWRITTEN ) { +trace_xfs_end_io_direct_write_unwritten (ip, offset, size); + +return xfs_iomap_write_unwritten (ip, offset, size, true); + } +/* * We need to update the in-core inode size here so that we don't end up * with the on-disk inode size being outside the in-core inode size. We
@@ -1548,13 +1564,6 @@ xfs_end_io_direct_write(i_size_write (inode, offset + size);spin_unlock (&ip->i_flags_lock); -if (flags &XFS_DIO_FLAG_COW ) - error =xfs_reflink_end_cow (ip, offset, size); -if (flags &XFS_DIO_FLAG_UNWRITTEN ) { -trace_xfs_end_io_direct_write_unwritten (ip, offset, size); - - error =xfs_iomap_write_unwritten (ip, offset, size); - }if (flags &XFS_DIO_FLAG_APPEND ) {trace_xfs_end_io_direct_write_append (ip, offset, size);
fs/xfs/xfs_iomap.c +5 -2
@@ -836,7 +836,8 @@ intxfs_iomap_write_unwritten ( xfs_inode_t *ip, xfs_off_t offset, - xfs_off_t count) + xfs_off_t count, + bool update_isize) {xfs_mount_t *mp = ip->i_mount;xfs_fileoff_t offset_fsb;
@@ -847,6 +848,7 @@ xfs_iomap_write_unwritten(xfs_trans_t *tp;xfs_bmbt_irec_t imap;struct xfs_defer_ops dfops; +struct inode *inode =VFS_I (ip);xfs_fsize_t i_size;uint resblks;int error;
@@ -906,7 +908,8 @@ xfs_iomap_write_unwritten( i_size =XFS_FSB_TO_B (mp, offset_fsb + count_fsb);if (i_size > offset + count) i_size = offset + count; - +if (update_isize && i_size >i_size_read (inode)) +i_size_write (inode, i_size); i_size =xfs_new_eof (ip, i_size);if (i_size) { ip->i_d.di_size = i_size;
fs/xfs/xfs_iomap.h +1 -1
@@ -27,7 +27,7 @@ int xfs_iomap_write_direct(struct xfs_in struct xfs_bmbt_irec *, int);int xfs_iomap_write_allocate (struct xfs_inode *,int ,xfs_off_t ,struct xfs_bmbt_irec *); -int xfs_iomap_write_unwritten (struct xfs_inode *,xfs_off_t ,xfs_off_t ); +int xfs_iomap_write_unwritten (struct xfs_inode *,xfs_off_t ,xfs_off_t ,bool );void xfs_bmbt_to_iomap (struct xfs_inode *,struct iomap *,struct xfs_bmbt_irec *);
fs/xfs/xfs_pnfs.c +1 -1
@@ -279,7 +279,7 @@ xfs_fs_commit_blocks( (end - 1) >> PAGE_SHIFT);WARN_ON_ONCE (error); - error =xfs_iomap_write_unwritten (ip, start, length); + error =xfs_iomap_write_unwritten (ip, start, length, false);if (error) goto out_drop_iolock; }
Patches currently in stable-queue which might be from [email protected] are
queue-4.9/xfs-report-zeroed-or-not-correctly-in-xfs_zero_range.patch queue-4.9/xfs-update-i_size-after-unwritten-conversion-in-dio-completion.patch queue-4.9/xfs-trim-writepage-mapping-to-within-eof.patch