From 60340beefd465ed86a543b2956e59ac48e85340a Mon Sep 17 00:00:00 2001 From: Stefan Wernli Date: Wed, 19 Jul 2017 14:35:23 -0700 Subject: [PATCH] Fixing releaseableLayer handling of layer streams and mounts. Original PR message: releaseableLayer includes automatic handling for creating a read/write layer and mounting it on a call to Mount(), but then does not correspondingly unmount the layer before trying to delete it, which will fail for some graphdrivers. Commit on a releaseable layer also leaks the tarstream for the layer. To fix this, the stream close is deferred in Commit and releaseRWLayer now correctly handles unmounting the layer before trying to delete it. In addition, the changes include better error handling in Release() to make sure that errors are returned to the caller for failures on read/write layers instead of being ignored.# Please enter the commit message for your changes. Lines starting Cherry-Pick note: This version of the change was edited to merge with docker-ce 17.06, which did not include the releasableLayer.Commit code, requiring that part of the merge to be removed. (cherry picked from commit 1d457999c4540aacda68f834bdb3c6f220ce3fd5) Signed-off-by: Stefan Wernli --- components/engine/daemon/build.go | 37 +++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/components/engine/daemon/build.go b/components/engine/daemon/build.go index 63006235f7..dd77e8c6f2 100644 --- a/components/engine/daemon/build.go +++ b/components/engine/daemon/build.go @@ -23,33 +23,58 @@ type releaseableLayer struct { } func (rl *releaseableLayer) Mount() (string, error) { + var err error + var mountPath string if rl.roLayer == nil { return "", errors.New("can not mount an image with no root FS") } - var err error mountID := stringid.GenerateRandomID() rl.rwLayer, err = rl.layerStore.CreateRWLayer(mountID, rl.roLayer.ChainID(), nil) if err != nil { return "", errors.Wrap(err, "failed to create rwlayer") } - return rl.rwLayer.Mount("") + mountPath, err = rl.rwLayer.Mount("") + if err != nil { + // Clean up the layer if we fail to mount it here. + metadata, err := rl.layerStore.ReleaseRWLayer(rl.rwLayer) + layer.LogReleaseMetadata(metadata) + if err != nil { + logrus.Errorf("Failed to release RWLayer: %s", err) + } + rl.rwLayer = nil + return "", err + } + + return mountPath, nil } func (rl *releaseableLayer) Release() error { - rl.releaseRWLayer() - return rl.releaseROLayer() + if err := rl.releaseRWLayer(); err != nil { + // Best effort attempt at releasing read-only layer before returning original error. + rl.releaseROLayer() + return err + } + if err := rl.releaseROLayer(); err != nil { + return err + } + return nil } func (rl *releaseableLayer) releaseRWLayer() error { if rl.rwLayer == nil { return nil } + if err := rl.rwLayer.Unmount(); err != nil { + logrus.Errorf("Failed to unmount RWLayer: %s", err) + return err + } metadata, err := rl.layerStore.ReleaseRWLayer(rl.rwLayer) layer.LogReleaseMetadata(metadata) if err != nil { logrus.Errorf("Failed to release RWLayer: %s", err) } + rl.rwLayer = nil return err } @@ -59,6 +84,10 @@ func (rl *releaseableLayer) releaseROLayer() error { } metadata, err := rl.layerStore.Release(rl.roLayer) layer.LogReleaseMetadata(metadata) + if err != nil { + logrus.Errorf("Failed to release ROLayer: %s", err) + } + rl.roLayer = nil return err }