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