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