Forráskód Böngészése

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 éve
szülő
commit
203bac0ec4
2 módosított fájl, 44 hozzáadás és 3 törlés
  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)
 }