mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-26 05:56:50 +00:00
fix(filemeta): classify xl.meta CRC mismatch as FileCorrupt so heal repairs it (#5838)
A failed CRC means the metadata bytes on disk are not the bytes that were written — bitrot. Raising it as Error::other() surfaces a generic Io error, which should_heal_object_on_disk does not recognise as heal-worthy: the drive is skipped, disks_to_heal_count stays 0, heal_object returns ok, and the corrupted xl.meta is never rewritten — while the scanner re-submits the same no-op heal every deep-scan cycle. An explicit admin deep heal fails the same way, so no heal path repairs metadata bitrot, and every one of them reports success. check_xl2_v1 already classifies a short or wrong-magic header as FileCorrupt for exactly this reason (#5716); this completes the pattern for the two CRC sites. The existing From<rustfs_filemeta::Error> for DiskError conversion maps the variant to DiskError::FileCorrupt, which the heal path already handles. The previously silent is_indexed_meta site now logs the mismatch (structured event shape) like unmarshal_msg does. Regression test: corrupt one byte of a marshalled FileMeta and assert unmarshal_msg reports FileCorrupt; fails on the previous code, which returned Io(Other). Verified end-to-end on a 3-node / 12-drive EC:4 cluster: xl.meta corrupted on 2 of 12 drives via dd, admin deep heal — before this change the heal returns ok with the corruption intact and the scanner loops forever; with it, both copies are rewritten (decode-identical to the healthy quorum), the object reads back byte-correct, and a follow-up heal reports all twelve drives clean.
This commit is contained in:
@@ -97,7 +97,20 @@ impl FileMeta {
|
||||
let meta_crc = xxh64::xxh64(meta, XXHASH_SEED) as u32;
|
||||
|
||||
if crc != meta_crc {
|
||||
return Err(Error::other("xl file crc check failed"));
|
||||
error!(
|
||||
event = "filemeta_xl_crc_mismatch",
|
||||
component = "filemeta",
|
||||
expected_crc = meta_crc,
|
||||
actual_crc = crc,
|
||||
"xl.meta payload failed its CRC check"
|
||||
);
|
||||
// Error::FileCorrupt, not a generic error, for the same reason
|
||||
// check_xl2_v1 classifies a bad magic as FileCorrupt: heal
|
||||
// classification (should_heal_object_on_disk) recognises
|
||||
// corruption only by the DiskError::FileCorrupt variant this
|
||||
// converts to. As a generic error the drive is skipped,
|
||||
// heal_object reports ok, and on-disk bitrot is never repaired.
|
||||
return Err(Error::FileCorrupt);
|
||||
}
|
||||
|
||||
Ok((meta, inline_data))
|
||||
@@ -163,8 +176,16 @@ impl FileMeta {
|
||||
let meta_crc = xxh64::xxh64(meta, XXHASH_SEED) as u32;
|
||||
|
||||
if crc != meta_crc {
|
||||
error!("xl file crc check failed: expected CRC {:#x}, got {:#x}", meta_crc, crc);
|
||||
return Err(Error::other("xl file crc check failed"));
|
||||
error!(
|
||||
event = "filemeta_xl_crc_mismatch",
|
||||
component = "filemeta",
|
||||
expected_crc = meta_crc,
|
||||
actual_crc = crc,
|
||||
"xl.meta payload failed its CRC check"
|
||||
);
|
||||
// See is_indexed_meta: the FileCorrupt variant is what makes heal
|
||||
// classify this drive as needing metadata repair.
|
||||
return Err(Error::FileCorrupt);
|
||||
}
|
||||
|
||||
if !buf.is_empty() {
|
||||
|
||||
Reference in New Issue
Block a user