Pārlūkot izejas kodu

Fix race between two ContainerRm

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
Alexander Morozov 9 gadi atpakaļ
vecāks
revīzija
4d1007d75c
3 mainītis faili ar 20 papildinājumiem un 12 dzēšanām
  1. 1 1
      daemon/create.go
  2. 15 10
      daemon/delete.go
  3. 4 1
      daemon/delete_test.go

+ 1 - 1
daemon/create.go

@@ -76,7 +76,7 @@ func (daemon *Daemon) create(params *ContainerCreateConfig) (retC *Container, re
 	}
 	defer func() {
 		if retErr != nil {
-			if err := daemon.rm(container, true); err != nil {
+			if err := daemon.ContainerRm(container.ID, &ContainerRmConfig{ForceRemove: true}); err != nil {
 				logrus.Errorf("Clean up Error! Cannot destroy container %s: %v", container.ID, err)
 			}
 		}

+ 15 - 10
daemon/delete.go

@@ -25,6 +25,21 @@ func (daemon *Daemon) ContainerRm(name string, config *ContainerRmConfig) error
 		return err
 	}
 
+	// Container state RemovalInProgress should be used to avoid races.
+	if err = container.setRemovalInProgress(); err != nil {
+		if err == derr.ErrorCodeAlreadyRemoving {
+			// do not fail when the removal is in progress started by other request.
+			return nil
+		}
+		return derr.ErrorCodeRmState.WithArgs(err)
+	}
+	defer container.resetRemovalInProgress()
+
+	// check if container wasn't deregistered by previous rm since Get
+	if c := daemon.containers.Get(container.ID); c == nil {
+		return nil
+	}
+
 	if config.RemoveLink {
 		name, err := GetFullContainerName(name)
 		if err != nil {
@@ -76,16 +91,6 @@ func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) {
 		}
 	}
 
-	// Container state RemovalInProgress should be used to avoid races.
-	if err = container.setRemovalInProgress(); err != nil {
-		if err == derr.ErrorCodeAlreadyRemoving {
-			// do not fail when the removal is in progress started by other request.
-			return nil
-		}
-		return derr.ErrorCodeRmState.WithArgs(err)
-	}
-	defer container.resetRemovalInProgress()
-
 	// stop collection of stats for the container regardless
 	// if stats are currently getting collected.
 	daemon.statsCollector.stopCollection(container)

+ 4 - 1
daemon/delete_test.go

@@ -18,13 +18,16 @@ func TestContainerDoubleDelete(t *testing.T) {
 		repository: tmp,
 		root:       tmp,
 	}
+	daemon.containers = &contStore{s: make(map[string]*Container)}
 
 	container := &Container{
 		CommonContainer: CommonContainer{
+			ID:     "test",
 			State:  NewState(),
 			Config: &runconfig.Config{},
 		},
 	}
+	daemon.containers.Add(container.ID, container)
 
 	// Mark the container as having a delete in progress
 	if err := container.setRemovalInProgress(); err != nil {
@@ -33,7 +36,7 @@ func TestContainerDoubleDelete(t *testing.T) {
 
 	// Try to remove the container when it's start is removalInProgress.
 	// It should ignore the container and not return an error.
-	if err := daemon.rm(container, true); err != nil {
+	if err := daemon.ContainerRm(container.ID, &ContainerRmConfig{ForceRemove: true}); err != nil {
 		t.Fatal(err)
 	}
 }