Patch "xfs: update i_size after unwritten conversion in dio completion" has been added to the 4.13-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.13-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.13 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 | 3 ++- fs/xfs/xfs_file.c | 33 +++++++++++++++++++-------------- fs/xfs/xfs_iomap.c | 7 +++++-- fs/xfs/xfs_iomap.h | 2 +- fs/xfs/xfs_pnfs.c | 2 +- 5 files changed, 28 insertions(+), 19 deletions(-)
fs/xfs/xfs_aops.c +2 -1
@@ -330,7 +330,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);
fs/xfs/xfs_file.c +19 -14
@@ -432,7 +432,6 @@ xfs_dio_write_end_io(struct inode *inode =file_inode (iocb->ki_filp);struct xfs_inode *ip =XFS_I (inode);loff_t offset = iocb->ki_pos; -bool update_size = false;int error =0 ;trace_xfs_end_io_direct_write (ip, offset, size);
@@ -443,6 +442,21 @@ xfs_dio_write_end_io(if (size <=0 )return size; +if (flags &IOMAP_DIO_COW ) { + error =xfs_reflink_end_cow (ip, offset, size); +if (error) +return error; + } + +/* +* 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 &IOMAP_DIO_UNWRITTEN ) +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
@@ -457,20 +471,11 @@ xfs_dio_write_end_io(spin_lock (&ip->i_flags_lock);if (offset + size >i_size_read (inode)) {i_size_write (inode, offset + size); - update_size = true; - } -spin_unlock (&ip->i_flags_lock); - -if (flags &IOMAP_DIO_COW ) { - error =xfs_reflink_end_cow (ip, offset, size); -if (error) -return error; - } - -if (flags &IOMAP_DIO_UNWRITTEN ) - error =xfs_iomap_write_unwritten (ip, offset, size); -else if (update_size) +spin_unlock (&ip->i_flags_lock); error =xfs_setfilesize (ip, offset, size); + }else { +spin_unlock (&ip->i_flags_lock); + }return error; }
fs/xfs/xfs_iomap.c +5 -2
@@ -829,7 +829,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;
@@ -840,6 +841,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;
@@ -899,7 +901,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
@@ -274,7 +274,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.13/xfs-report-zeroed-or-not-correctly-in-xfs_zero_range.patch queue-4.13/iomap_dio_rw-allocate-aio-completion-queue-before-submitting-dio.patch queue-4.13/xfs-update-i_size-after-unwritten-conversion-in-dio-completion.patch queue-4.13/xfs-trim-writepage-mapping-to-within-eof.patch