Fixes #29654: take reference to RWLayer while committing/exporting

Take an extra reference to rwlayer while the container is being
committed or exported to avoid the removal of that layer.

Also add some checks before commit/export.

Signed-off-by: Yuanhong Peng <pengyuanhong@huawei.com>
This commit is contained in:
Yuanhong Peng 2017-05-20 10:38:45 +08:00
parent 777d4a1bf4
commit 8c32659979
3 changed files with 77 additions and 10 deletions

View File

@ -357,6 +357,15 @@ func (s *State) ResetRemovalInProgress() {
s.Unlock() s.Unlock()
} }
// IsRemovalInProgress returns whether the RemovalInProgress flag is set.
// Used by Container to check whether a container is being removed.
func (s *State) IsRemovalInProgress() bool {
s.Lock()
res := s.RemovalInProgress
s.Unlock()
return res
}
// SetDead sets the container state to "dead" // SetDead sets the container state to "dead"
func (s *State) SetDead() { func (s *State) SetDead() {
s.Lock() s.Lock()
@ -364,6 +373,14 @@ func (s *State) SetDead() {
s.Unlock() s.Unlock()
} }
// IsDead returns whether the Dead flag is set. Used by Container to check whether a container is dead.
func (s *State) IsDead() bool {
s.Lock()
res := s.Dead
s.Unlock()
return res
}
// SetRemoved assumes this container is already in the "dead" state and // SetRemoved assumes this container is already in the "dead" state and
// closes the internal waitRemove channel to unblock callers waiting for a // closes the internal waitRemove channel to unblock callers waiting for a
// container to be removed. // container to be removed.

View File

@ -2,6 +2,7 @@ package daemon
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"runtime" "runtime"
"strings" "strings"
@ -133,6 +134,16 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
return "", errors.Errorf("%+v does not support commit of a running container", runtime.GOOS) return "", errors.Errorf("%+v does not support commit of a running container", runtime.GOOS)
} }
if container.IsDead() {
err := fmt.Errorf("You cannot commit container %s which is Dead", container.ID)
return "", stateConflictError{err}
}
if container.IsRemovalInProgress() {
err := fmt.Errorf("You cannot commit container %s which is being removed", container.ID)
return "", stateConflictError{err}
}
if c.Pause && !container.IsPaused() { if c.Pause && !container.IsPaused() {
daemon.containerPause(container) daemon.containerPause(container)
defer daemon.containerUnpause(container) defer daemon.containerUnpause(container)
@ -234,19 +245,36 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
return id.String(), nil return id.String(), nil
} }
func (daemon *Daemon) exportContainerRw(container *container.Container) (io.ReadCloser, error) { func (daemon *Daemon) exportContainerRw(container *container.Container) (arch io.ReadCloser, err error) {
if err := daemon.Mount(container); err != nil { rwlayer, err := daemon.stores[container.Platform].layerStore.GetRWLayer(container.ID)
if err != nil {
return nil, err
}
defer func() {
if err != nil {
daemon.stores[container.Platform].layerStore.ReleaseRWLayer(rwlayer)
}
}()
// TODO: this mount call is not necessary as we assume that TarStream() should
// mount the layer if needed. But the Diff() function for windows requests that
// the layer should be mounted when calling it. So we reserve this mount call
// until windows driver can implement Diff() interface correctly.
_, err = rwlayer.Mount(container.GetMountLabel())
if err != nil {
return nil, err return nil, err
} }
archive, err := container.RWLayer.TarStream() archive, err := rwlayer.TarStream()
if err != nil { if err != nil {
daemon.Unmount(container) // logging is already handled in the `Unmount` function rwlayer.Unmount()
return nil, err return nil, err
} }
return ioutils.NewReadCloserWrapper(archive, func() error { return ioutils.NewReadCloserWrapper(archive, func() error {
archive.Close() archive.Close()
return container.RWLayer.Unmount() err = rwlayer.Unmount()
daemon.stores[container.Platform].layerStore.ReleaseRWLayer(rwlayer)
return err
}), }),
nil nil
} }

View File

@ -22,6 +22,16 @@ func (daemon *Daemon) ContainerExport(name string, out io.Writer) error {
return fmt.Errorf("the daemon on this platform does not support exporting Windows containers") return fmt.Errorf("the daemon on this platform does not support exporting Windows containers")
} }
if container.IsDead() {
err := fmt.Errorf("You cannot export container %s which is Dead", container.ID)
return stateConflictError{err}
}
if container.IsRemovalInProgress() {
err := fmt.Errorf("You cannot export container %s which is being removed", container.ID)
return stateConflictError{err}
}
data, err := daemon.containerExport(container) data, err := daemon.containerExport(container)
if err != nil { if err != nil {
return fmt.Errorf("Error exporting container %s: %v", name, err) return fmt.Errorf("Error exporting container %s: %v", name, err)
@ -35,8 +45,19 @@ func (daemon *Daemon) ContainerExport(name string, out io.Writer) error {
return nil return nil
} }
func (daemon *Daemon) containerExport(container *container.Container) (io.ReadCloser, error) { func (daemon *Daemon) containerExport(container *container.Container) (arch io.ReadCloser, err error) {
if err := daemon.Mount(container); err != nil { rwlayer, err := daemon.stores[container.Platform].layerStore.GetRWLayer(container.ID)
if err != nil {
return nil, err
}
defer func() {
if err != nil {
daemon.stores[container.Platform].layerStore.ReleaseRWLayer(rwlayer)
}
}()
_, err = rwlayer.Mount(container.GetMountLabel())
if err != nil {
return nil, err return nil, err
} }
@ -46,12 +67,13 @@ func (daemon *Daemon) containerExport(container *container.Container) (io.ReadCl
GIDMaps: daemon.idMappings.GIDs(), GIDMaps: daemon.idMappings.GIDs(),
}) })
if err != nil { if err != nil {
daemon.Unmount(container) rwlayer.Unmount()
return nil, err return nil, err
} }
arch := ioutils.NewReadCloserWrapper(archive, func() error { arch = ioutils.NewReadCloserWrapper(archive, func() error {
err := archive.Close() err := archive.Close()
daemon.Unmount(container) rwlayer.Unmount()
daemon.stores[container.Platform].layerStore.ReleaseRWLayer(rwlayer)
return err return err
}) })
daemon.LogContainerEvent(container, "export") daemon.LogContainerEvent(container, "export")