|
@@ -3469,6 +3469,25 @@ static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 olen,
|
|
|
|
|
|
same_lock_start = min_t(u64, loff, dst_loff);
|
|
|
same_lock_len = max_t(u64, loff, dst_loff) + len - same_lock_start;
|
|
|
+ } else {
|
|
|
+ /*
|
|
|
+ * If the source and destination inodes are different, the
|
|
|
+ * source's range end offset matches the source's i_size, that
|
|
|
+ * i_size is not a multiple of the sector size, and the
|
|
|
+ * destination range does not go past the destination's i_size,
|
|
|
+ * we must round down the length to the nearest sector size
|
|
|
+ * multiple. If we don't do this adjustment we end replacing
|
|
|
+ * with zeroes the bytes in the range that starts at the
|
|
|
+ * deduplication range's end offset and ends at the next sector
|
|
|
+ * size multiple.
|
|
|
+ */
|
|
|
+ if (loff + olen == i_size_read(src) &&
|
|
|
+ dst_loff + len < i_size_read(dst)) {
|
|
|
+ const u64 sz = BTRFS_I(src)->root->fs_info->sectorsize;
|
|
|
+
|
|
|
+ len = round_down(i_size_read(src), sz) - loff;
|
|
|
+ olen = len;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
again:
|