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>
| ... | ... |
@@ -357,6 +357,15 @@ func (s *State) ResetRemovalInProgress() {
|
| 357 | 357 |
s.Unlock() |
| 358 | 358 |
} |
| 359 | 359 |
|
| 360 |
+// IsRemovalInProgress returns whether the RemovalInProgress flag is set. |
|
| 361 |
+// Used by Container to check whether a container is being removed. |
|
| 362 |
+func (s *State) IsRemovalInProgress() bool {
|
|
| 363 |
+ s.Lock() |
|
| 364 |
+ res := s.RemovalInProgress |
|
| 365 |
+ s.Unlock() |
|
| 366 |
+ return res |
|
| 367 |
+} |
|
| 368 |
+ |
|
| 360 | 369 |
// SetDead sets the container state to "dead" |
| 361 | 370 |
func (s *State) SetDead() {
|
| 362 | 371 |
s.Lock() |
| ... | ... |
@@ -364,6 +373,14 @@ func (s *State) SetDead() {
|
| 364 | 364 |
s.Unlock() |
| 365 | 365 |
} |
| 366 | 366 |
|
| 367 |
+// IsDead returns whether the Dead flag is set. Used by Container to check whether a container is dead. |
|
| 368 |
+func (s *State) IsDead() bool {
|
|
| 369 |
+ s.Lock() |
|
| 370 |
+ res := s.Dead |
|
| 371 |
+ s.Unlock() |
|
| 372 |
+ return res |
|
| 373 |
+} |
|
| 374 |
+ |
|
| 367 | 375 |
// SetRemoved assumes this container is already in the "dead" state and |
| 368 | 376 |
// closes the internal waitRemove channel to unblock callers waiting for a |
| 369 | 377 |
// container to be removed. |
| ... | ... |
@@ -2,6 +2,7 @@ package daemon |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"encoding/json" |
| 5 |
+ "fmt" |
|
| 5 | 6 |
"io" |
| 6 | 7 |
"runtime" |
| 7 | 8 |
"strings" |
| ... | ... |
@@ -133,6 +134,16 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str |
| 133 | 133 |
return "", errors.Errorf("%+v does not support commit of a running container", runtime.GOOS)
|
| 134 | 134 |
} |
| 135 | 135 |
|
| 136 |
+ if container.IsDead() {
|
|
| 137 |
+ err := fmt.Errorf("You cannot commit container %s which is Dead", container.ID)
|
|
| 138 |
+ return "", stateConflictError{err}
|
|
| 139 |
+ } |
|
| 140 |
+ |
|
| 141 |
+ if container.IsRemovalInProgress() {
|
|
| 142 |
+ err := fmt.Errorf("You cannot commit container %s which is being removed", container.ID)
|
|
| 143 |
+ return "", stateConflictError{err}
|
|
| 144 |
+ } |
|
| 145 |
+ |
|
| 136 | 146 |
if c.Pause && !container.IsPaused() {
|
| 137 | 147 |
daemon.containerPause(container) |
| 138 | 148 |
defer daemon.containerUnpause(container) |
| ... | ... |
@@ -234,19 +245,36 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str |
| 234 | 234 |
return id.String(), nil |
| 235 | 235 |
} |
| 236 | 236 |
|
| 237 |
-func (daemon *Daemon) exportContainerRw(container *container.Container) (io.ReadCloser, error) {
|
|
| 238 |
- if err := daemon.Mount(container); err != nil {
|
|
| 237 |
+func (daemon *Daemon) exportContainerRw(container *container.Container) (arch io.ReadCloser, err error) {
|
|
| 238 |
+ rwlayer, err := daemon.stores[container.Platform].layerStore.GetRWLayer(container.ID) |
|
| 239 |
+ if err != nil {
|
|
| 240 |
+ return nil, err |
|
| 241 |
+ } |
|
| 242 |
+ defer func() {
|
|
| 243 |
+ if err != nil {
|
|
| 244 |
+ daemon.stores[container.Platform].layerStore.ReleaseRWLayer(rwlayer) |
|
| 245 |
+ } |
|
| 246 |
+ }() |
|
| 247 |
+ |
|
| 248 |
+ // TODO: this mount call is not necessary as we assume that TarStream() should |
|
| 249 |
+ // mount the layer if needed. But the Diff() function for windows requests that |
|
| 250 |
+ // the layer should be mounted when calling it. So we reserve this mount call |
|
| 251 |
+ // until windows driver can implement Diff() interface correctly. |
|
| 252 |
+ _, err = rwlayer.Mount(container.GetMountLabel()) |
|
| 253 |
+ if err != nil {
|
|
| 239 | 254 |
return nil, err |
| 240 | 255 |
} |
| 241 | 256 |
|
| 242 |
- archive, err := container.RWLayer.TarStream() |
|
| 257 |
+ archive, err := rwlayer.TarStream() |
|
| 243 | 258 |
if err != nil {
|
| 244 |
- daemon.Unmount(container) // logging is already handled in the `Unmount` function |
|
| 259 |
+ rwlayer.Unmount() |
|
| 245 | 260 |
return nil, err |
| 246 | 261 |
} |
| 247 | 262 |
return ioutils.NewReadCloserWrapper(archive, func() error {
|
| 248 | 263 |
archive.Close() |
| 249 |
- return container.RWLayer.Unmount() |
|
| 264 |
+ err = rwlayer.Unmount() |
|
| 265 |
+ daemon.stores[container.Platform].layerStore.ReleaseRWLayer(rwlayer) |
|
| 266 |
+ return err |
|
| 250 | 267 |
}), |
| 251 | 268 |
nil |
| 252 | 269 |
} |
| ... | ... |
@@ -22,6 +22,16 @@ func (daemon *Daemon) ContainerExport(name string, out io.Writer) error {
|
| 22 | 22 |
return fmt.Errorf("the daemon on this platform does not support exporting Windows containers")
|
| 23 | 23 |
} |
| 24 | 24 |
|
| 25 |
+ if container.IsDead() {
|
|
| 26 |
+ err := fmt.Errorf("You cannot export container %s which is Dead", container.ID)
|
|
| 27 |
+ return stateConflictError{err}
|
|
| 28 |
+ } |
|
| 29 |
+ |
|
| 30 |
+ if container.IsRemovalInProgress() {
|
|
| 31 |
+ err := fmt.Errorf("You cannot export container %s which is being removed", container.ID)
|
|
| 32 |
+ return stateConflictError{err}
|
|
| 33 |
+ } |
|
| 34 |
+ |
|
| 25 | 35 |
data, err := daemon.containerExport(container) |
| 26 | 36 |
if err != nil {
|
| 27 | 37 |
return fmt.Errorf("Error exporting container %s: %v", name, err)
|
| ... | ... |
@@ -35,8 +45,19 @@ func (daemon *Daemon) ContainerExport(name string, out io.Writer) error {
|
| 35 | 35 |
return nil |
| 36 | 36 |
} |
| 37 | 37 |
|
| 38 |
-func (daemon *Daemon) containerExport(container *container.Container) (io.ReadCloser, error) {
|
|
| 39 |
- if err := daemon.Mount(container); err != nil {
|
|
| 38 |
+func (daemon *Daemon) containerExport(container *container.Container) (arch io.ReadCloser, err error) {
|
|
| 39 |
+ rwlayer, err := daemon.stores[container.Platform].layerStore.GetRWLayer(container.ID) |
|
| 40 |
+ if err != nil {
|
|
| 41 |
+ return nil, err |
|
| 42 |
+ } |
|
| 43 |
+ defer func() {
|
|
| 44 |
+ if err != nil {
|
|
| 45 |
+ daemon.stores[container.Platform].layerStore.ReleaseRWLayer(rwlayer) |
|
| 46 |
+ } |
|
| 47 |
+ }() |
|
| 48 |
+ |
|
| 49 |
+ _, err = rwlayer.Mount(container.GetMountLabel()) |
|
| 50 |
+ if err != nil {
|
|
| 40 | 51 |
return nil, err |
| 41 | 52 |
} |
| 42 | 53 |
|
| ... | ... |
@@ -46,12 +67,13 @@ func (daemon *Daemon) containerExport(container *container.Container) (io.ReadCl |
| 46 | 46 |
GIDMaps: daemon.idMappings.GIDs(), |
| 47 | 47 |
}) |
| 48 | 48 |
if err != nil {
|
| 49 |
- daemon.Unmount(container) |
|
| 49 |
+ rwlayer.Unmount() |
|
| 50 | 50 |
return nil, err |
| 51 | 51 |
} |
| 52 |
- arch := ioutils.NewReadCloserWrapper(archive, func() error {
|
|
| 52 |
+ arch = ioutils.NewReadCloserWrapper(archive, func() error {
|
|
| 53 | 53 |
err := archive.Close() |
| 54 |
- daemon.Unmount(container) |
|
| 54 |
+ rwlayer.Unmount() |
|
| 55 |
+ daemon.stores[container.Platform].layerStore.ReleaseRWLayer(rwlayer) |
|
| 55 | 56 |
return err |
| 56 | 57 |
}) |
| 57 | 58 |
daemon.LogContainerEvent(container, "export") |