From a47ee6fd93e2b5df16c8326c1960d7131c718bad Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Mon, 8 Jun 2026 22:57:09 -0700 Subject: [PATCH] fix(ec): guard ecjFile under its lock in the EC delete path EcVolume.Close nils ecjFile under ecjFileAccessLock; a delete that resolved its .ecx lookup before a concurrent eviction (the generate-time UnloadEcVolume) could then reach the journal append with a nil fd. Bail with a clear "volume closed" error under the lock instead. --- weed/storage/erasure_coding/ec_volume_delete.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/weed/storage/erasure_coding/ec_volume_delete.go b/weed/storage/erasure_coding/ec_volume_delete.go index 55490fc67..5ddd506db 100644 --- a/weed/storage/erasure_coding/ec_volume_delete.go +++ b/weed/storage/erasure_coding/ec_volume_delete.go @@ -64,6 +64,14 @@ func (ev *EcVolume) DeleteNeedleFromEcx(needleId types.NeedleId) (err error) { return nil } + // Close nils ecjFile under this same lock, so a delete that resolved its + // .ecx lookup before an eviction (e.g. the generate-time UnloadEcVolume) + // can reach here with no journal fd. Bail with a clear error rather than + // operating on the closed/nil handle. + if ev.ecjFile == nil { + return fmt.Errorf("ec volume %d closed", ev.VolumeId) + } + b := make([]byte, types.NeedleIdSize) types.NeedleIdToBytes(b, needleId)