浏览代码

daemon/c8d: Unmount container fs after unclean shutdown

BaseFS is not serialized and is lost after an unclean shutdown. Unmount
method in the containerd image service implementation will not work
correctly in that case.
This patch will allow Unmount to restore the BaseFS if the target is
still mounted.

The reason it works with graphdrivers is that it doesn't directly
operate on BaseFS. It uses RWLayer, which is explicitly restored
immediately as soon as container is loaded.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
Paweł Gronowski 1 年之前
父节点
当前提交
203bac0ec4
共有 2 个文件被更改,包括 44 次插入3 次删除
  1. 14 3
      daemon/containerd/mount.go
  2. 30 0
      daemon/snapshotter/mount.go

+ 14 - 3
daemon/containerd/mount.go

@@ -2,6 +2,7 @@ package containerd
 
 import (
 	"context"
+	"errors"
 	"fmt"
 
 	"github.com/containerd/log"
@@ -30,11 +31,21 @@ func (i *ImageService) Mount(ctx context.Context, container *container.Container
 
 // Unmount unmounts the container base filesystem
 func (i *ImageService) Unmount(ctx context.Context, container *container.Container) error {
-	root := container.BaseFS
+	baseFS := container.BaseFS
+	if baseFS == "" {
+		target, err := i.refCountMounter.Mounted(container.ID)
+		if err != nil {
+			log.G(ctx).WithField("containerID", container.ID).Warn("failed to determine if container is already mounted")
+		}
+		if target == "" {
+			return errors.New("BaseFS is empty")
+		}
+		baseFS = target
+	}
 
-	if err := i.refCountMounter.Unmount(root); err != nil {
+	if err := i.refCountMounter.Unmount(baseFS); err != nil {
 		log.G(ctx).WithField("container", container.ID).WithError(err).Error("error unmounting container")
-		return fmt.Errorf("failed to unmount %s: %w", root, err)
+		return fmt.Errorf("failed to unmount %s: %w", baseFS, err)
 	}
 
 	return nil

+ 30 - 0
daemon/snapshotter/mount.go

@@ -10,6 +10,7 @@ import (
 	"github.com/docker/docker/daemon/graphdriver"
 	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/locker"
+	"github.com/moby/sys/mountinfo"
 )
 
 // List of known filesystems that can't be re-mounted or have shared layers
@@ -22,6 +23,8 @@ type Mounter interface {
 	Mount(mounts []mount.Mount, containerID string) (string, error)
 	// Unmount unmounts the container rootfs
 	Unmount(target string) error
+	// Mounted returns a target mountpoint if it's already mounted
+	Mounted(containerID string) (string, error)
 }
 
 // inSlice tests whether a string is contained in a slice of strings or not.
@@ -110,6 +113,23 @@ func (m *refCountMounter) Unmount(target string) error {
 	return nil
 }
 
+func (m *refCountMounter) Mounted(containerID string) (string, error) {
+	mounted, err := m.base.Mounted(containerID)
+	if err != nil || mounted == "" {
+		return mounted, err
+	}
+
+	target := m.base.target(containerID)
+
+	// Check if the refcount is non-zero.
+	m.rc.Increment(target)
+	if m.rc.Decrement(target) > 0 {
+		return mounted, nil
+	}
+
+	return "", nil
+}
+
 type mounter struct {
 	home        string
 	snapshotter string
@@ -137,6 +157,16 @@ func (m mounter) Unmount(target string) error {
 	return unmount(target)
 }
 
+func (m mounter) Mounted(containerID string) (string, error) {
+	target := m.target(containerID)
+
+	mounted, err := mountinfo.Mounted(target)
+	if err != nil || !mounted {
+		return "", err
+	}
+	return target, nil
+}
+
 func (m mounter) target(containerID string) string {
 	return filepath.Join(m.home, "rootfs", m.snapshotter, containerID)
 }