cache: tighten parent lock scope in parentRefs.release

The layerParent and diffParents cases locked each parent's mutex and
deferred the unlock to the end of the function, so the lock was held
longer than the release it protects -- and in the diffParents case the
lower parent's lock was still held while the upper parent was locked and
released.

Unlock each parent immediately after releasing it so the lock is held
only for that parent's release, matching the mergeParents case in the
same switch which already does this. This narrows the lock scope and
avoids holding one parent's lock while acquiring another's.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This commit is contained in:
Brian Goff
2026-05-29 13:34:46 -07:00
committed by Tonis Tiigi
parent 9051e6b728
commit c78752e9c1

15
cache/refs.go vendored
View File

@@ -151,8 +151,9 @@ func (p parentRefs) release(ctx context.Context) error {
switch {
case p.layerParent != nil:
p.layerParent.mu.Lock()
defer p.layerParent.mu.Unlock()
if err := p.layerParent.release(ctx); err != nil {
err := p.layerParent.release(ctx)
p.layerParent.mu.Unlock()
if err != nil {
errs = append(errs, err)
}
case len(p.mergeParents) > 0:
@@ -171,8 +172,9 @@ func (p parentRefs) release(ctx context.Context) error {
case p.diffParents != nil:
if p.diffParents.lower != nil {
p.diffParents.lower.mu.Lock()
defer p.diffParents.lower.mu.Unlock()
if err := p.diffParents.lower.release(ctx); err != nil {
err := p.diffParents.lower.release(ctx)
p.diffParents.lower.mu.Unlock()
if err != nil {
errs = append(errs, err)
} else {
p.diffParents.lower = nil
@@ -180,8 +182,9 @@ func (p parentRefs) release(ctx context.Context) error {
}
if p.diffParents.upper != nil {
p.diffParents.upper.mu.Lock()
defer p.diffParents.upper.mu.Unlock()
if err := p.diffParents.upper.release(ctx); err != nil {
err := p.diffParents.upper.release(ctx)
p.diffParents.upper.mu.Unlock()
if err != nil {
errs = append(errs, err)
} else {
p.diffParents.upper = nil