linux/fs/xfs
Brian Foster f374505b79 xfs: trim writepage mapping to within eof
commit 40214d128e upstream.

The writeback rework in commit fbcc025613 ("xfs: Introduce
writeback context for writepages") introduced a subtle change in
behavior with regard to the block mapping used across the
->writepages() sequence. The previous xfs_cluster_write() code would
only flush pages up to EOF at the time of the writepage, thus
ensuring that any pages due to file-extending writes would be
handled on a separate cycle and with a new, updated block mapping.

The updated code establishes a block mapping in xfs_writepage_map()
that could extend beyond EOF if the file has post-eof preallocation.
Because we now use the generic writeback infrastructure and pass the
cached mapping to each writepage call, there is no implicit EOF
limit in place. If eofblocks trimming occurs during ->writepages(),
any post-eof portion of the cached mapping becomes invalid. The
eofblocks code has no means to serialize against writeback because
there are no pages associated with post-eof blocks. Therefore if an
eofblocks trim occurs and is followed by a file-extending buffered
write, not only has the mapping become invalid, but we could end up
writing a page to disk based on the invalid mapping.

Consider the following sequence of events:

- A buffered write creates a delalloc extent and post-eof
  speculative preallocation.
- Writeback starts and on the first writepage cycle, the delalloc
  extent is converted to real blocks (including the post-eof blocks)
  and the mapping is cached.
- The file is closed and xfs_release() trims post-eof blocks. The
  cached writeback mapping is now invalid.
- Another buffered write appends the file with a delalloc extent.
- The concurrent writeback cycle picks up the just written page
  because the writeback range end is LLONG_MAX. xfs_writepage_map()
  attributes it to the (now invalid) cached mapping and writes the
  data to an incorrect location on disk (and where the file offset is
  still backed by a delalloc extent).

This problem is reproduced by xfstests test generic/464, which
triggers racing writes, appends, open/closes and writeback requests.

To address this problem, trim the mapping used during writeback to
within EOF when the mapping is validated. This ensures the mapping
is revalidated for any pages encountered beyond EOF as of the time
the current mapping was cached or last validated.

Reported-by: Eryu Guan <eguan@redhat.com>
Diagnosed-by: Eryu Guan <eguan@redhat.com>
Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
History 2017-10-27 10:38:10 +02:00
..
libxfs xfs: trim writepage mapping to within eof 2017-10-27 10:38:10 +02:00
Kconfig xfs: implement iomap based buffered write path 2016-06-21 09:53:44 +10:00
kmem.c xfs: remove kmem_zalloc_greedy 2017-10-08 10:26:11 +02:00
kmem.h xfs: remove kmem_zalloc_greedy 2017-10-08 10:26:11 +02:00
Makefile xfs: introduce the CoW fork 2016-10-04 18:06:40 -07:00
mrlock.h xfs: introduce CONFIG_XFS_WARN 2013-05-07 18:45:36 -05:00
uuid.c xfs: remove subdirectories 2011-08-12 16:21:35 -05:00
uuid.h xfs: add CRC infrastructure 2012-11-19 20:11:24 -06:00
xfs.h xfs: introduce CONFIG_XFS_WARN 2013-05-07 18:45:36 -05:00
xfs_acl.c xfs: don't change inode mode if ACL update fails 2017-10-27 10:38:10 +02:00
xfs_acl.h xfs: Don't clear SGID when inheriting ACLs 2017-07-27 15:08:03 -07:00
xfs_aops.c xfs: trim writepage mapping to within eof 2017-10-27 10:38:10 +02:00
xfs_aops.h xfs: allocate delayed extents in CoW fork 2016-10-04 18:06:41 -07:00
xfs_attr.h xfs: remove put_value from attr ->put_listent context 2016-04-06 07:57:45 +10:00
xfs_attr_inactive.c xfs: reinit btree pointer on attr tree inactivation walk 2017-10-27 10:38:10 +02:00
xfs_attr_list.c xfs: make several functions static 2016-06-01 17:38:15 +10:00
xfs_bmap_item.c xfs: try to avoid blowing out the transaction reservation when bunmaping a shared extent 2017-09-20 08:19:57 +02:00
xfs_bmap_item.h xfs: log bmap intent items 2016-10-04 11:05:44 -07:00
xfs_bmap_util.c xfs: move more RT specific code under CONFIG_XFS_RT 2017-10-27 10:38:10 +02:00
xfs_bmap_util.h xfs: move more RT specific code under CONFIG_XFS_RT 2017-10-27 10:38:10 +02:00
xfs_buf.c xfs: push buffer of flush locked dquot to avoid quotacheck deadlock 2017-09-20 08:19:57 +02:00
xfs_buf.h xfs: push buffer of flush locked dquot to avoid quotacheck deadlock 2017-09-20 08:19:57 +02:00
xfs_buf_item.c xfs: fix compiler warnings 2017-09-20 08:20:02 +02:00
xfs_buf_item.h xfs: remove unnecessary dirty bli format check for ordered bufs 2017-09-20 08:20:01 +02:00
xfs_dir2_readdir.c xfs: prevent multi-fsb dir readahead from reading random blocks 2017-06-07 12:07:51 +02:00
xfs_discard.c xfs: rmap btree requires more reserved free space 2016-08-03 11:38:24 +10:00
xfs_discard.h xfs: remove subdirectories 2011-08-12 16:21:35 -05:00
xfs_dquot.c xfs: don't wrap ID in xfs_dq_get_next_id 2017-02-04 09:47:12 +01:00
xfs_dquot.h xfs: fix implicit bool to int conversion 2015-01-09 10:48:58 +11:00
xfs_dquot_item.c xfs: allocate log vector buffers outside CIL context lock 2016-07-22 09:52:35 +10:00
xfs_dquot_item.h xfs: remove the quotaoff log format from the quotaoff log item 2013-12-13 11:34:08 +11:00
xfs_error.c fs/xfs: Use %pS printk format for direct addresses 2017-10-27 10:38:09 +02:00
xfs_error.h xfs: simulate per-AG reservations being critically low 2016-10-05 16:26:31 -07:00
xfs_export.c xfs: abstract block export operations from nfsd layouts 2016-07-15 15:31:29 -04:00
xfs_export.h xfs: remove subdirectories 2011-08-12 16:21:35 -05:00
xfs_extent_busy.c xfs: don't fail xfs_extent_busy allocation 2017-04-08 09:30:31 +02:00
xfs_extent_busy.h xfs: decouple inode and bmap btree header files 2013-10-23 16:28:49 -05:00
xfs_extfree_item.c xfs: remove unnecessary parentheses from log redo item recovery functions 2016-08-03 12:29:32 +10:00
xfs_extfree_item.h xfs: refactor redo intent item processing 2016-08-03 11:23:49 +10:00
xfs_file.c xfs: report zeroed or not correctly in xfs_zero_range() 2017-10-27 10:38:09 +02:00
xfs_filestream.c Merge branch 'xfs-4.9-log-recovery-fixes' into for-next 2016-10-03 09:56:28 +11:00
xfs_filestream.h xfs: add filestream allocator tracepoints 2014-04-23 07:11:52 +10:00
xfs_fsops.c xfs: use the actual AG length when reserving blocks 2017-01-12 11:39:44 +01:00
xfs_fsops.h xfs: preallocate blocks for worst-case btree expansion 2016-10-05 16:26:27 -07:00
xfs_globals.c xfs: garbage collect old cowextsz reservations 2016-10-05 16:26:28 -07:00
xfs_icache.c xfs: check for race with xfs_reclaim_inode() in xfs_ifree_cluster() 2017-09-20 08:20:01 +02:00
xfs_icache.h xfs: update ag iterator to support wait on new inodes 2017-06-07 12:07:52 +02:00
xfs_icreate_item.c xfs: move most of xfs_sb.h to xfs_format.h 2014-11-28 14:27:09 +11:00
xfs_icreate_item.h xfs: separate icreate log format definitions from xfs_icreate_item.h 2013-08-12 16:10:35 -05:00
xfs_inode.c xfs: don't unconditionally clear the reflink flag on zero-block files 2017-10-27 10:38:08 +02:00
xfs_inode.h xfs: support ability to wait on new inodes 2017-06-07 12:07:51 +02:00
xfs_inode_item.c xfs: Don't log uninitialised fields in inode structures 2017-10-27 10:38:09 +02:00
xfs_inode_item.h xfs: remove timestamps from incore inode 2016-02-09 16:54:58 +11:00
xfs_ioctl.c xfs: validate bdev support for DAX inode flag 2017-10-05 09:44:03 +02:00
xfs_ioctl.h xfs: don't pass ioflags around in the ioctl path 2016-07-20 11:29:35 +10:00
xfs_ioctl32.c xfs: don't pass ioflags around in the ioctl path 2016-07-20 11:29:35 +10:00
xfs_ioctl32.h xfs: compat_xfs_bstat does not have forkoff 2014-10-02 09:17:58 +10:00
xfs_iomap.c xfs: update i_size after unwritten conversion in dio completion 2017-10-27 10:38:09 +02:00
xfs_iomap.h xfs: update i_size after unwritten conversion in dio completion 2017-10-27 10:38:09 +02:00
xfs_iops.c xfs: fix compiler warnings 2017-09-20 08:20:02 +02:00
xfs_iops.h xfs: Propagate dentry down to inode_change_ok() 2016-09-22 10:56:19 +02:00
xfs_itable.c xfs: remove kmem_zalloc_greedy 2017-10-08 10:26:11 +02:00
xfs_itable.h xfs: bulkstat chunk formatting cursor is broken 2014-11-07 08:30:30 +11:00
xfs_linux.h xfs: XFS_IS_REALTIME_INODE() should be false if no rt device present 2017-09-13 14:13:37 -07:00
xfs_log.c xfs: fix incorrect log_flushed on fsync 2017-09-20 08:20:02 +02:00
xfs_log.h xfs: make several functions static 2016-06-01 17:38:15 +10:00
xfs_log_cil.c xfs: allocate log vector buffers outside CIL context lock 2016-07-22 09:52:35 +10:00
xfs_log_priv.h xfs: rework log recovery to submit buffers on LSN boundaries 2016-09-26 08:22:16 +10:00
xfs_log_recover.c xfs: fix compiler warnings 2017-09-20 08:20:02 +02:00
xfs_message.c xfs: more info from kmem deadlocks and high-level error msgs 2015-10-12 16:04:45 +11:00
xfs_message.h xfs: introduce CONFIG_XFS_WARN 2013-05-07 18:45:36 -05:00
xfs_mount.c xfs: don't leak quotacheck dquots when cow recovery 2017-09-20 08:19:59 +02:00
xfs_mount.h xfs: use dedicated log worker wq to avoid deadlock with cil wq 2017-06-07 12:07:51 +02:00
xfs_mru_cache.c xfs: xfs_mru_cache_insert() should use GFP_NOFS 2015-03-25 14:57:53 +11:00
xfs_mru_cache.h xfs: embedd mru_elem into parent structure 2014-04-23 07:11:51 +10:00
xfs_ondisk.h xfs: Don't log uninitialised fields in inode structures 2017-10-27 10:38:09 +02:00
xfs_pnfs.c xfs: update i_size after unwritten conversion in dio completion 2017-10-27 10:38:09 +02:00
xfs_pnfs.h xfs: abstract block export operations from nfsd layouts 2016-07-15 15:31:29 -04:00
xfs_qm.c xfs: fix quotacheck dquot id overflow infinite loop 2017-09-20 08:19:59 +02:00
xfs_qm.h xfs: Split default quota limits by quota type 2016-02-08 11:27:55 +11:00
xfs_qm_bhv.c xfs: move most of xfs_sb.h to xfs_format.h 2014-11-28 14:27:09 +11:00
xfs_qm_syscalls.c xfs: wait on new inodes during quotaoff dquot release 2017-06-07 12:07:52 +02:00
xfs_quota.h xfs: fix quota block reservation leak when tp allocates and frees blocks 2015-06-01 07:15:37 +10:00
xfs_quotaops.c xfs: wire up Q_XGETNEXTQUOTA / get_nextdqblk 2016-02-08 11:27:38 +11:00
xfs_refcount_item.c xfs: fix double-cleanup when CUI recovery fails 2017-01-12 11:39:44 +01:00
xfs_refcount_item.h xfs: log refcount intent items 2016-10-03 09:11:21 -07:00
xfs_reflink.c xfs: handle racy AIO in xfs_reflink_end_cow 2017-10-27 10:38:09 +02:00
xfs_reflink.h xfs: only reclaim unwritten COW extents periodically 2017-04-08 09:30:32 +02:00
xfs_rmap_item.c xfs: convert unwritten status of reverse mappings for shared files 2016-10-05 16:26:29 -07:00
xfs_rmap_item.h xfs: convert RUI log formats to use variable length arrays 2016-09-19 10:24:27 +10:00
xfs_rtalloc.c xfs: rename flist/free_list to dfops 2016-08-03 11:19:29 +10:00
xfs_rtalloc.h xfs: make several functions static 2016-06-01 17:38:15 +10:00
xfs_stats.c xfs: introduce refcount btree definitions 2016-10-03 09:11:16 -07:00
xfs_stats.h xfs: introduce refcount btree definitions 2016-10-03 09:11:16 -07:00
xfs_super.c xfs: use kmem_free to free return value of kmem_zalloc 2017-09-20 08:20:02 +02:00
xfs_super.h xfs: quiesce the filesystem after recovery on readonly mount 2016-09-26 08:21:44 +10:00
xfs_symlink.c xfs: rename flist/free_list to dfops 2016-08-03 11:19:29 +10:00
xfs_symlink.h xfs: push down inactive transaction mgmt for remote symlinks 2013-10-08 14:53:02 -05:00
xfs_sysctl.c xfs: garbage collect old cowextsz reservations 2016-10-05 16:26:28 -07:00
xfs_sysctl.h xfs: garbage collect old cowextsz reservations 2016-10-05 16:26:28 -07:00
xfs_sysfs.c xfs: fix max_retries _show and _store functions 2017-01-12 11:39:45 +01:00
xfs_sysfs.h xfs: configurable error behavior via sysfs 2016-05-18 10:58:51 +10:00
xfs_trace.c xfs: rework xfs_bmap_free callers to use xfs_defer_ops 2016-08-03 11:15:38 +10:00
xfs_trace.h xfs: ordered buffer log items are never formatted 2017-09-20 08:20:01 +02:00
xfs_trans.c xfs: xfs_trans_alloc_empty 2017-06-07 12:07:52 +02:00
xfs_trans.h xfs: disallow marking previously dirty buffers as ordered 2017-09-20 08:20:02 +02:00
xfs_trans_ail.c xfs: Properly retry failed inode items in case of error during buffer writeback 2017-09-20 08:20:00 +02:00
xfs_trans_bmap.c xfs: try to avoid blowing out the transaction reservation when bunmaping a shared extent 2017-09-20 08:19:57 +02:00
xfs_trans_buf.c xfs: disallow marking previously dirty buffers as ordered 2017-09-20 08:20:02 +02:00
xfs_trans_dquot.c xfs: Split default quota limits by quota type 2016-02-08 11:27:55 +11:00
xfs_trans_extfree.c xfs: set up per-AG free space reservations 2016-09-19 10:30:52 +10:00
xfs_trans_inode.c fs: Replace current_fs_time() with current_time() 2016-09-27 21:06:22 -04:00
xfs_trans_priv.h xfs: Properly retry failed inode items in case of error during buffer writeback 2017-09-20 08:20:00 +02:00
xfs_trans_refcount.c xfs: connect refcount adjust functions to upper layers 2016-10-03 09:11:22 -07:00
xfs_trans_rmap.c xfs: add shared rmap map/unmap/convert log item types 2016-10-05 16:26:29 -07:00
xfs_xattr.c Make __xfs_xattr_put_listen preperly report errors. 2016-09-14 07:40:35 +10:00