xfs: convert inode to extent format after extent merge due to shift
authorBrian Foster <bfoster@redhat.com>
Thu, 19 Sep 2019 00:50:45 +0000 (17:50 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Mon, 23 Sep 2019 20:00:14 +0000 (13:00 -0700)
commite20e174ca1bd98241b42d5ccfa228d8c6522e4e7
tree8f95974eea648200a5ea04d00801bda4dced5ac3
parent14e15f1bcd738dc13dd7c1e78e4800e8bc577980
xfs: convert inode to extent format after extent merge due to shift

The collapse range operation can merge extents if two newly adjacent
extents are physically contiguous. If the extent count is reduced on
a btree format inode, a change to extent format might be necessary.
This format change currently occurs as a side effect of the file
size update after extents have been shifted for the collapse. This
codepath ultimately calls xfs_bunmapi(), which happens to check for
and execute the format conversion even if there were no blocks
removed from the mapping.

While this ultimately puts the inode into the correct state, the
fact the format conversion occurs in a separate transaction from the
change that called for it is a problem. If an extent shift
transaction commits and the filesystem happens to crash before the
format conversion, the inode fork is left in a corrupted state after
log recovery. The inode fork verifier fails and xfs_repair
ultimately nukes the inode. This problem was originally reproduced
by generic/388.

Similar to how the insert range extent split code handles extent to
btree conversion, update the collapse range extent merge code to
handle btree to extent format conversion in the same transaction
that merges the extents. This ensures that the inode fork format
remains consistent if the filesystem happens to crash in the middle
of a collapse range operation that changes the inode fork format.

Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
fs/xfs/libxfs/xfs_bmap.c