c517fd6
A user reported a problem where they were getting csum errors when running a
c517fd6
balance and running systemd's journal.  This is because systemd is awesome and
c517fd6
fallocate()'s its log space and writes into it.  Unfortunately we assume that
c517fd6
when we read in all the csums for an extent that they are sequential starting at
c517fd6
the bytenr we care about.  This obviously isn't the case for prealloc extents,
c517fd6
where we could have written to the middle of the prealloc extent only, which
c517fd6
means the csum would be for the bytenr in the middle of our range and not the
c517fd6
front of our range.  Fix this by offsetting the new bytenr we are logging to
c517fd6
based on the original bytenr the csum was for.  With this patch I no longer see
c517fd6
the csum errors I was seeing.  Thanks,
c517fd6
c517fd6
Cc: stable@xxxxxxxxxxxxxxx
c517fd6
Reported-by: Chris Murphy <lists@xxxxxxxxxxxxxxxxx>
c517fd6
Signed-off-by: Josef Bacik <jbacik@xxxxxxxxxxxx>
c517fd6
---
c517fd6
 fs/btrfs/relocation.c | 18 +++++++++++++++---
c517fd6
 1 file changed, 15 insertions(+), 3 deletions(-)
c517fd6
c517fd6
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
c517fd6
index 5ca7ea9..b7afeaa 100644
c517fd6
--- a/fs/btrfs/relocation.c
c517fd6
+++ b/fs/btrfs/relocation.c
c517fd6
@@ -4472,6 +4472,7 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)
c517fd6
 	struct btrfs_root *root = BTRFS_I(inode)->root;
c517fd6
 	int ret;
c517fd6
 	u64 disk_bytenr;
c517fd6
+	u64 new_bytenr;
c517fd6
 	LIST_HEAD(list);
c517fd6
 
c517fd6
 	ordered = btrfs_lookup_ordered_extent(inode, file_pos);
c517fd6
@@ -4483,13 +4484,24 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)
c517fd6
 	if (ret)
c517fd6
 		goto out;
c517fd6
 
c517fd6
-	disk_bytenr = ordered->start;
c517fd6
 	while (!list_empty(&list)) {
c517fd6
 		sums = list_entry(list.next, struct btrfs_ordered_sum, list);
c517fd6
 		list_del_init(&sums->list);
c517fd6
 
c517fd6
-		sums->bytenr = disk_bytenr;
c517fd6
-		disk_bytenr += sums->len;
c517fd6
+		/*
c517fd6
+		 * We need to offset the new_bytenr based on where the csum is.
c517fd6
+		 * We need to do this because we will read in entire prealloc
c517fd6
+		 * extents but we may have written to say the middle of the
c517fd6
+		 * prealloc extent, so we need to make sure the csum goes with
c517fd6
+		 * the right disk offset.
c517fd6
+		 *
c517fd6
+		 * We can do this because the data reloc inode refers strictly
c517fd6
+		 * to the on disk bytes, so we don't have to worry about
c517fd6
+		 * disk_len vs real len like with real inodes since it's all
c517fd6
+		 * disk length.
c517fd6
+		 */
c517fd6
+		new_bytenr = ordered->start + (sums->bytenr - disk_bytenr);
c517fd6
+		sums->bytenr = new_bytenr;
c517fd6
 
c517fd6
 		btrfs_add_ordered_sum(inode, ordered, sums);
c517fd6
 	}
c517fd6
-- 
c517fd6
1.8.3.1