aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2018-10-05 21:44:19 -0400
committerDave Chinner <david@fromorbit.com>2018-10-05 21:44:19 -0400
commitdceeb47b0ed65e14de53507a8a9c32a90831cfa1 (patch)
treea7f1a07a5d322830639a3406723b118bfd3f6cd3
parent7debbf015f580693680f3d2a3cef0cf99dcef688 (diff)
xfs: fix data corruption w/ unaligned dedupe ranges
A deduplication data corruption is Exposed by fstests generic/505 on XFS. It is caused by extending the block match range to include the partial EOF block, but then allowing unknown data beyond EOF to be considered a "match" to data in the destination file because the comparison is only made to the end of the source file. This corrupts the destination file when the source extent is shared with it. XFS only supports whole block dedupe, but we still need to appear to support whole file dedupe correctly. Hence if the dedupe request includes the last block of the souce file, don't include it in the actual XFS dedupe operation. If the rest of the range dedupes successfully, then report the partial last block as deduped, too, so that userspace sees it as a successful dedupe rather than return EINVAL because we can't dedupe unaligned blocks. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r--fs/xfs/xfs_reflink.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
index 59da9708e9c1..f889398e25d6 100644
--- a/fs/xfs/xfs_reflink.c
+++ b/fs/xfs/xfs_reflink.c
@@ -1265,6 +1265,19 @@ xfs_reflink_zero_posteof(
1265 * will have the iolock and mmaplock held, the page cache of the out file 1265 * will have the iolock and mmaplock held, the page cache of the out file
1266 * will be truncated, and any leases on the out file will have been broken. 1266 * will be truncated, and any leases on the out file will have been broken.
1267 * This function borrows heavily from xfs_file_aio_write_checks. 1267 * This function borrows heavily from xfs_file_aio_write_checks.
1268 *
1269 * The VFS allows partial EOF blocks to "match" for dedupe even though it hasn't
1270 * checked that the bytes beyond EOF physically match. Hence we cannot use the
1271 * EOF block in the source dedupe range because it's not a complete block match,
1272 * hence can introduce a corruption into the file that has it's
1273 * block replaced.
1274 *
1275 * Despite this issue, we still need to report that range as successfully
1276 * deduped to avoid confusing userspace with EINVAL errors on completely
1277 * matching file data. The only time that an unaligned length will be passed to
1278 * us is when it spans the EOF block of the source file, so if we simply mask it
1279 * down to be block aligned here the we will dedupe everything but that partial
1280 * EOF block.
1268 */ 1281 */
1269STATIC int 1282STATIC int
1270xfs_reflink_remap_prep( 1283xfs_reflink_remap_prep(
@@ -1307,6 +1320,14 @@ xfs_reflink_remap_prep(
1307 if (ret <= 0) 1320 if (ret <= 0)
1308 goto out_unlock; 1321 goto out_unlock;
1309 1322
1323 /*
1324 * If the dedupe data matches, chop off the partial EOF block
1325 * from the source file so we don't try to dedupe the partial
1326 * EOF block.
1327 */
1328 if (is_dedupe)
1329 *len &= ~((u64)i_blocksize(inode_in) - 1);
1330
1310 /* Attach dquots to dest inode before changing block map */ 1331 /* Attach dquots to dest inode before changing block map */
1311 ret = xfs_qm_dqattach(dest); 1332 ret = xfs_qm_dqattach(dest);
1312 if (ret) 1333 if (ret)