linux/fs/xfs/libxfs
Brian Foster 40214d128e xfs: trim writepage mapping to within eof
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>
2017-10-16 12:26:50 -07:00
..
xfs_ag_resv.c xfs: perag initialization should only touch m_ag_max_usable for AG 0 2017-09-26 10:55:19 -07:00
xfs_ag_resv.h xfs: set up per-AG free space reservations 2016-09-19 10:30:52 +10:00
xfs_alloc.c xfs: handle error if xfs_btree_get_bufs fails 2017-10-11 10:21:07 -07:00
xfs_alloc.h xfs: export various function for the online scrubber 2017-06-19 14:11:34 -07:00
xfs_alloc_btree.c xfs: always compile the btree inorder check functions 2017-06-19 14:11:33 -07:00
xfs_alloc_btree.h
xfs_attr.c xfs: remove the ip argument to xfs_defer_finish 2017-09-01 10:55:30 -07:00
xfs_attr_leaf.c xfs: refactor xfs_trans_roll 2017-09-01 10:55:30 -07:00
xfs_attr_leaf.h Merge branch 'xfs-4.10-misc-fixes-3' into for-next 2016-12-07 17:42:30 +11:00
xfs_attr_remote.c xfs: remove the ip argument to xfs_defer_finish 2017-09-01 10:55:30 -07:00
xfs_attr_remote.h
xfs_attr_sf.h xfs: remove double-underscore integer types 2017-06-19 14:11:33 -07:00
xfs_bit.c libxfs: Optimize the loop for xfs_bitmap_empty 2016-01-04 16:10:19 +11:00
xfs_bit.h xfs: remove double-underscore integer types 2017-06-19 14:11:33 -07:00
xfs_bmap.c xfs: trim writepage mapping to within eof 2017-10-16 12:26:50 -07:00
xfs_bmap.h xfs: trim writepage mapping to within eof 2017-10-16 12:26:50 -07:00
xfs_bmap_btree.c xfs: skip bmbt block ino validation during owner change 2017-09-01 10:55:30 -07:00
xfs_bmap_btree.h xfs: simplify validation of the unwritten extent bit 2017-04-25 09:40:41 -07:00
xfs_btree.c xfs: relog dirty buffers during swapext bmbt owner change 2017-09-01 10:55:30 -07:00
xfs_btree.h xfs: skip bmbt block ino validation during owner change 2017-09-01 10:55:30 -07:00
xfs_cksum.h xfs: remove double-underscore integer types 2017-06-19 14:11:33 -07:00
xfs_da_btree.c xfs: don't crash on unexpected holes in dir/attr btrees 2017-07-07 18:55:17 -07:00
xfs_da_btree.h xfs: remove double-underscore integer types 2017-06-19 14:11:33 -07:00
xfs_da_format.c xfs: remove double-underscore integer types 2017-06-19 14:11:33 -07:00
xfs_da_format.h xfs: remove double-underscore integer types 2017-06-19 14:11:33 -07:00
xfs_defer.c xfs: remove the ip argument to xfs_defer_finish 2017-09-01 10:55:30 -07:00
xfs_defer.h xfs: remove the ip argument to xfs_defer_finish 2017-09-01 10:55:30 -07:00
xfs_dir2.c xfs: remove unneeded parameter from XFS_TEST_ERROR 2017-06-27 18:23:20 -07:00
xfs_dir2.h xfs: remove double-underscore integer types 2017-06-19 14:11:33 -07:00
xfs_dir2_block.c xfs: don't crash on unexpected holes in dir/attr btrees 2017-07-07 18:55:17 -07:00
xfs_dir2_data.c xfs: check that dir block entries don't off the end of the buffer 2017-07-25 08:36:35 -07:00
xfs_dir2_leaf.c xfs: don't crash on unexpected holes in dir/attr btrees 2017-07-07 18:55:17 -07:00
xfs_dir2_node.c xfs: return the hash value of a leaf1 directory block 2017-06-20 10:45:21 -07:00
xfs_dir2_priv.h xfs: pass along transaction context when reading directory block buffers 2017-06-20 10:45:22 -07:00
xfs_dir2_sf.c xfs: remove double-underscore integer types 2017-06-19 14:11:33 -07:00
xfs_dquot_buf.c xfs: simplify xfs_calc_dquots_per_chunk 2017-04-12 08:42:51 -07:00
xfs_format.h xfs: rename MAXPATHLEN to XFS_SYMLINK_MAXLEN 2017-07-07 08:37:26 -07:00
xfs_fs.h xfs: remove double-underscore integer types 2017-06-19 14:11:33 -07:00
xfs_ialloc.c xfs: Fix bool initialization/comparison 2017-10-11 10:21:06 -07:00
xfs_ialloc.h xfs: export _inobt_btrec_to_irec and _ialloc_cluster_alignment for scrub 2017-06-19 14:11:34 -07:00
xfs_ialloc_btree.c xfs: plumb in needed functions for range querying of various btrees 2017-06-19 14:11:34 -07:00
xfs_ialloc_btree.h xfs: use per-AG reservations for the finobt 2017-01-25 07:49:35 -08:00
xfs_inode_buf.c xfs: remove unneeded parameter from XFS_TEST_ERROR 2017-06-27 18:23:20 -07:00
xfs_inode_buf.h xfs: export various function for the online scrubber 2017-06-19 14:11:34 -07:00
xfs_inode_fork.c xfs: fix compiler warnings 2017-09-02 08:22:19 -07:00
xfs_inode_fork.h xfs: add a xfs_iext_update_extent helper 2017-09-01 10:55:30 -07:00
xfs_log_format.h xfs: Don't log uninitialised fields in inode structures 2017-10-11 10:21:06 -07:00
xfs_log_recover.h xfs: remove double-underscore integer types 2017-06-19 14:11:33 -07:00
xfs_log_rlimit.c xfs: move most of xfs_sb.h to xfs_format.h 2014-11-28 14:27:09 +11:00
xfs_quota_defs.h Revert "xfs: grab dquots without taking the ilock" 2017-07-13 14:55:05 -07:00
xfs_refcount.c xfs: remove the ip argument to xfs_defer_finish 2017-09-01 10:55:30 -07:00
xfs_refcount.h xfs: try to avoid blowing out the transaction reservation when bunmaping a shared extent 2017-06-19 08:59:10 -07:00
xfs_refcount_btree.c xfs: always compile the btree inorder check functions 2017-06-19 14:11:33 -07:00
xfs_refcount_btree.h xfs: use the actual AG length when reserving blocks 2017-01-03 18:39:33 -08:00
xfs_rmap.c xfs: remove unneeded parameter from XFS_TEST_ERROR 2017-06-27 18:23:20 -07:00
xfs_rmap.h xfs: export various function for the online scrubber 2017-06-19 14:11:34 -07:00
xfs_rmap_btree.c xfs: always compile the btree inorder check functions 2017-06-19 14:11:33 -07:00
xfs_rmap_btree.h xfs: use the actual AG length when reserving blocks 2017-01-03 18:39:33 -08:00
xfs_rtbitmap.c xfs: export various function for the online scrubber 2017-06-19 14:11:34 -07:00
xfs_sb.c xfs: remove double-underscore integer types 2017-06-19 14:11:33 -07:00
xfs_sb.h xfs: remove unused function definitions 2016-02-08 14:58:07 +11:00
xfs_shared.h xfs: define the on-disk refcount btree format 2016-10-03 09:11:18 -07:00
xfs_symlink_remote.c xfs: rename MAXPATHLEN to XFS_SYMLINK_MAXLEN 2017-07-07 08:37:26 -07:00
xfs_trans_resv.c xfs: rename MAXPATHLEN to XFS_SYMLINK_MAXLEN 2017-07-07 08:37:26 -07:00
xfs_trans_resv.h xfs: increase log reservations for reflink 2016-10-05 16:26:29 -07:00
xfs_trans_space.h xfs: reserve enough blocks to handle btree splits when remapping 2017-05-03 13:21:40 -07:00
xfs_types.h xfs: remove double-underscore integer types 2017-06-19 14:11:33 -07:00