diff options
author | Brian Foster <bfoster@redhat.com> | 2023-09-27 07:23:37 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:10:15 -0400 |
commit | 3c40841cdcf374d661ff14e7a707681342565166 (patch) | |
tree | 301da3c0036dbad011f4c99f83f4bf981dbbb5eb /fs/bcachefs/checksum.c | |
parent | 4220666398de7f5127bab5437b5276b3eb155282 (diff) | |
download | linux-3c40841cdcf374d661ff14e7a707681342565166.tar.gz linux-3c40841cdcf374d661ff14e7a707681342565166.tar.bz2 linux-3c40841cdcf374d661ff14e7a707681342565166.zip |
bcachefs: fix crc32c checksum merge byte order problem
An fsstress task on a big endian system (s390x) quickly produces a
bunch of CRC errors in the system logs. Most of these are related to
the narrow CRCs path, but the fundamental problem can be reduced to
a single write and re-read (after dropping caches) of a previously
merged extent.
The key merge path that handles extent merges eventually calls into
bch2_checksum_merge() to combine the CRCs of the associated extents.
This code attempts to avoid a byte order swap by feeding the le64
values into the crc32c code, but the latter casts the resulting u64
value down to a u32, which truncates the high bytes where the actual
crc value ends up. This results in a CRC value that does not change
(since it is merged with a CRC of 0), and checksum failures ensue.
Fix the checksum merge code to swap to cpu byte order on the
boundaries to the external crc code such that any value casting is
handled properly.
Signed-off-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/checksum.c')
-rw-r--r-- | fs/bcachefs/checksum.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/fs/bcachefs/checksum.c b/fs/bcachefs/checksum.c index 50bf4a58f37d..839f00dce50f 100644 --- a/fs/bcachefs/checksum.c +++ b/fs/bcachefs/checksum.c @@ -362,7 +362,7 @@ struct bch_csum bch2_checksum_merge(unsigned type, struct bch_csum a, state.type = type; bch2_checksum_init(&state); - state.seed = (u64 __force) a.lo; + state.seed = le64_to_cpu(a.lo); BUG_ON(!bch2_checksum_mergeable(type)); @@ -373,7 +373,7 @@ struct bch_csum bch2_checksum_merge(unsigned type, struct bch_csum a, page_address(ZERO_PAGE(0)), page_len); b_len -= page_len; } - a.lo = (__le64 __force) bch2_checksum_final(&state); + a.lo = cpu_to_le64(bch2_checksum_final(&state)); a.lo ^= b.lo; a.hi ^= b.hi; return a; |