From cdcaf9f39ebde63ed3fce4d062224e4198589368 Mon Sep 17 00:00:00 2001 From: liuzekun Date: Mon, 9 Dec 2019 04:02:10 -0500 Subject: [PATCH] docker: fix mount loop on "docker cp" reason: fix mount loop on "docker cp" Cherry-pick from upstream: https://github.com/moby/moby/pull/38993 --- components/engine/container/container_unix.go | 9 ++++++++- components/engine/daemon/archive.go | 15 +++++++++++++-- components/engine/daemon/volumes_unix.go | 9 +++++++++ components/engine/pkg/mount/mount.go | 5 +++++ 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/components/engine/container/container_unix.go b/components/engine/container/container_unix.go index 5a21b8c..43dd759 100644 --- a/components/engine/container/container_unix.go +++ b/components/engine/container/container_unix.go @@ -385,7 +385,14 @@ func (container *Container) DetachAndUnmount(volumeEventLog func(name, action st logrus.Warnf("%s unmountVolumes: Failed to do lazy umount fo volume '%s': %v", container.ID, mountPath, err) } } - return container.UnmountVolumes(volumeEventLog) + err := container.UnmountVolumes(volumeEventLog) + // (daemon *).mountVolumes() calls mount.MakeMountAndRUnbindable() for + // container root, which results in an extra bind mount, unmount it. + if root, err := container.GetResourcePath(""); err == nil { + mount.Unmount(root) + } + + return err } // copyExistingContents copies from the source to the destination and diff --git a/components/engine/daemon/archive.go b/components/engine/daemon/archive.go index 0053e53..0bac763 100644 --- a/components/engine/daemon/archive.go +++ b/components/engine/daemon/archive.go @@ -12,6 +12,7 @@ import ( "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/chrootarchive" "github.com/docker/docker/pkg/ioutils" + "github.com/docker/docker/pkg/mount" "github.com/docker/docker/pkg/system" "github.com/pkg/errors" ) @@ -172,6 +173,9 @@ func (daemon *Daemon) containerStatPath(container *container.Container, path str defer daemon.Unmount(container) err = daemon.mountVolumes(container) + if err == mount.ErrMountAndRUnbindFailed { + return nil, err + } defer container.DetachAndUnmount(daemon.LogVolumeEvent) if err != nil { return nil, err @@ -208,9 +212,11 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path } defer func() { - if err != nil { + if err != nil && err != mount.ErrMountAndRUnbindFailed { // unmount any volumes container.DetachAndUnmount(daemon.LogVolumeEvent) + } + if err != nil { // unmount the container's rootfs daemon.Unmount(container) } @@ -286,6 +292,9 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path defer daemon.Unmount(container) err = daemon.mountVolumes(container) + if err == mount.ErrMountAndRUnbindFailed { + return err + } defer container.DetachAndUnmount(daemon.LogVolumeEvent) if err != nil { return err @@ -410,9 +419,11 @@ func (daemon *Daemon) containerCopy(container *container.Container, resource str } defer func() { - if err != nil { + if err != nil && err != mount.ErrMountAndRUnbindFailed { // unmount any volumes container.DetachAndUnmount(daemon.LogVolumeEvent) + } + if err != nil { // unmount the container's rootfs daemon.Unmount(container) } diff --git a/components/engine/daemon/volumes_unix.go b/components/engine/daemon/volumes_unix.go index 5ddb926..e9a6d37 100644 --- a/components/engine/daemon/volumes_unix.go +++ b/components/engine/daemon/volumes_unix.go @@ -109,6 +109,15 @@ func setBindModeIfNull(bind *volumemounts.MountPoint) { } func (daemon *Daemon) mountVolumes(container *container.Container) error { + if root, err := container.GetResourcePath(""); err == nil { + err = mount.ForceMount(root, root, "none", "bind") + if err != nil { + return mount.ErrMountAndRUnbindFailed + } else { + mount.ForceMount("", root, "none", "runbindable") + } + } + mounts, err := daemon.setupMounts(container) if err != nil { return err diff --git a/components/engine/pkg/mount/mount.go b/components/engine/pkg/mount/mount.go index 874aff6..a784e0d 100644 --- a/components/engine/pkg/mount/mount.go +++ b/components/engine/pkg/mount/mount.go @@ -1,6 +1,7 @@ package mount // import "github.com/docker/docker/pkg/mount" import ( + "errors" "sort" "strings" "syscall" @@ -8,6 +9,10 @@ import ( "github.com/sirupsen/logrus" ) +var ( + ErrMountAndRUnbindFailed = errors.New("make mount and runbind failed") +) + // FilterFunc is a type defining a callback function // to filter out unwanted entries. It takes a pointer // to an Info struct (not fully populated, currently -- 2.20.1