fix(ec): reject an unstamped shard when the caller has an encode identity

The read guard required both identities nonzero, so a current (stamped)
caller accepted a holder with identity 0 and could be served a stale
pre-upgrade shard. Reject when the caller is stamped and the holder
differs (including unstamped); stay lenient only when the caller itself
has no identity (pre-upgrade reader). A skipped shard recovers from parity.
This commit is contained in:
Chris Lu
2026-06-08 22:57:39 -07:00
parent a47ee6fd93
commit 63607d810c
2 changed files with 10 additions and 6 deletions
+5 -3
View File
@@ -657,9 +657,11 @@ func (vs *VolumeServer) VolumeEcShardRead(req *volume_server_pb.VolumeEcShardRea
if !found {
return fmt.Errorf("not found ec shard %d.%d", req.VolumeId, req.ShardId)
}
// Reject a shard from a different encode run than the caller's index; the
// caller then recovers from parity. 0 on either side = pre-upgrade volume.
if req.EncodeTsNs != 0 && ecVolume.EncodeTsNs != 0 && req.EncodeTsNs != ecVolume.EncodeTsNs {
// Reject a shard whose identity doesn't match the caller's index; the caller
// then recovers from parity. Lenient only when the caller has no identity
// (pre-upgrade reader): a known caller must not accept an unstamped holder,
// which would serve a stale pre-upgrade shard.
if req.EncodeTsNs != 0 && req.EncodeTsNs != ecVolume.EncodeTsNs {
return fmt.Errorf("ec shard %d.%d belongs to a different encode run", req.VolumeId, req.ShardId)
}
+5 -3
View File
@@ -527,9 +527,11 @@ func (s *Store) readLocalEcShardInterval(ecVolume *erasure_coding.EcVolume, shar
if !found {
return fmt.Errorf("shard %d for volume %d: %w", shardId, ecVolume.VolumeId, errShardNotLocal)
}
// Skip a local shard from a different encode run than the caller's index;
// treat it as not-local so the read recovers from the correct generation.
if ecVolume.EncodeTsNs != 0 && ownerVolume.EncodeTsNs != 0 && ecVolume.EncodeTsNs != ownerVolume.EncodeTsNs {
// Skip a local shard whose identity doesn't match the caller's index, so the
// read recovers from the correct generation. Lenient only when the caller has
// no identity (pre-upgrade): a known caller must not accept an unstamped local
// shard, which would serve a stale pre-upgrade generation.
if ecVolume.EncodeTsNs != 0 && ecVolume.EncodeTsNs != ownerVolume.EncodeTsNs {
glog.V(1).Infof("skip local ec shard %d.%d from a different encode run: caller EncodeTsNs %d, local %d", ecVolume.VolumeId, shardId, ecVolume.EncodeTsNs, ownerVolume.EncodeTsNs)
return fmt.Errorf("shard %d for volume %d: %w", shardId, ecVolume.VolumeId, errShardNotLocal)
}