fix(heal): do not purge dangling data during a dry-run heal

healObject handles a metadata read-quorum failure before its dry-run
return, so an admin heal with DryRun set still called deleteIfDangling.
When the drives without the version's xl.meta all answered "not found"
and outnumbered its parity blocks, the dry run deleted the version,
data directory included, from every drive that still held it. A
site-wide dry run reaches .minio.sys/config the same way.

When DryRun is set, return the quorum error with a set-level result
built from the observed read errors, before the purge. Real heals are
unchanged.

The production change is the first cmd/erasure-healing.go hunk of
PR #280, unchanged. The tests are the PR's dry-run tests that do not
depend on its parallel deep verification or its dry-run reporting
change; both stay out of this commit. The tests now assert the delete
counter first and the converted error for each quorum case, and drop
the CheckParts stub that only the excluded tests use.

Co-authored-by: Jasper Bernhardt <jasper.bernhardt@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Feng Ruohang <rh@vonng.com>
This commit is contained in:
Feng Ruohang
2026-11-05 01:21:13 +08:00
parent 69fcf50cd2
commit c8dd5678bb
2 changed files with 249 additions and 0 deletions
+5
View File
@@ -343,6 +343,11 @@ func (er *erasureObjects) healObject(ctx context.Context, bucket string, object
readQuorum, _, err := objectQuorumFromMeta(ctx, partsMetadata, errs, er.defaultParityCount)
if err != nil {
if dryRun {
// A metadata quorum failure must not delete dangling data in dry-run.
return er.defaultHealResult(FileInfo{}, storageDisks, storageEndpoints,
errs, bucket, object, versionID), err
}
m, derr := er.deleteIfDangling(ctx, bucket, object, partsMetadata, errs, nil, ObjectOptions{
VersionID: versionID,
})