浏览代码

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>
Paweł Gronowski 1 年之前
父节点
当前提交
294fc9762e
共有 2 个文件被更改,包括 22 次插入2 次删除
  1. 10 2
      volume/local/local.go
  2. 12 0
      volume/mounts/mounts.go

+ 10 - 2
volume/local/local.go

@@ -9,6 +9,7 @@ import (
 	"os"
 	"path/filepath"
 	"reflect"
+	"runtime/debug"
 	"strings"
 	"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
 	// this volume can never be removed until a daemon restart occurs.
 	if v.needsMount() {
-		v.active.count--
-		logger.WithField("active mounts", v.active).Debug("Decremented active mount count")
+		// TODO: Remove once the real bug is fixed: https://github.com/moby/moby/issues/46508
+		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 {

+ 12 - 0
volume/mounts/mounts.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"os"
 	"path/filepath"
+	"runtime/debug"
 	"syscall"
 
 	"github.com/containerd/log"
@@ -88,6 +89,15 @@ func (m *MountPoint) Cleanup(ctx context.Context) error {
 		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 {
 		if !p.IsValid() {
 			continue
@@ -108,6 +118,8 @@ func (m *MountPoint) Cleanup(ctx context.Context) error {
 	}
 
 	m.active--
+	logger.Debug("MountPoint.Cleanup Decrement active count")
+
 	if m.active == 0 {
 		m.ID = ""
 	}