volume: Don't decrement refcount below 0

With both rootless and live restore enabled, there's some race condition
which causes the container to be `Unmount`ed before the refcount is
restored.

This makes sure we don't underflow the refcount (uint64) when
decrementing it.

The root cause of this race condition still needs to be investigated and
fixed, but at least this unflakies the `TestLiveRestore`.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This commit is contained in:
Paweł Gronowski 2023-10-20 11:58:26 +02:00
parent 608d77d740
commit 294fc9762e
No known key found for this signature in database
GPG key ID: B85EFCFE26DEF92A
2 changed files with 22 additions and 2 deletions

View file

@ -9,6 +9,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
"runtime/debug"
"strings" "strings"
"sync" "sync"
@ -334,8 +335,15 @@ func (v *localVolume) Unmount(id string) error {
// ultimately there's nothing that can be done. If we don't decrement the count // ultimately there's nothing that can be done. If we don't decrement the count
// this volume can never be removed until a daemon restart occurs. // this volume can never be removed until a daemon restart occurs.
if v.needsMount() { if v.needsMount() {
v.active.count-- // TODO: Remove once the real bug is fixed: https://github.com/moby/moby/issues/46508
logger.WithField("active mounts", v.active).Debug("Decremented active mount count") if v.active.count > 0 {
v.active.count--
logger.WithField("active mounts", v.active).Debug("Decremented active mount count")
} else {
logger.Error("An attempt to decrement a zero mount count")
logger.Error(string(debug.Stack()))
return nil
}
} }
if v.active.count > 0 { if v.active.count > 0 {

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"runtime/debug"
"syscall" "syscall"
"github.com/containerd/log" "github.com/containerd/log"
@ -88,6 +89,15 @@ func (m *MountPoint) Cleanup(ctx context.Context) error {
return nil return nil
} }
logger := log.G(ctx).WithFields(log.Fields{"active": m.active, "id": m.ID})
// TODO: Remove once the real bug is fixed: https://github.com/moby/moby/issues/46508
if m.active == 0 {
logger.Error("An attempt to decrement a zero mount count")
logger.Error(string(debug.Stack()))
return nil
}
for _, p := range m.safePaths { for _, p := range m.safePaths {
if !p.IsValid() { if !p.IsValid() {
continue continue
@ -108,6 +118,8 @@ func (m *MountPoint) Cleanup(ctx context.Context) error {
} }
m.active-- m.active--
logger.Debug("MountPoint.Cleanup Decrement active count")
if m.active == 0 { if m.active == 0 {
m.ID = "" m.ID = ""
} }