Prechádzať zdrojové kódy

Fix race condition between container register and mount

When a container is created it is registered before the mount is created. This can lead to mount does not exist errors when inspecting between create and mount.

Fixes #18753

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
Derek McGowan 9 rokov pred
rodič
commit
d8e090669e
3 zmenil súbory, kde vykonal 37 pridanie a 30 odobranie
  1. 9 5
      daemon/create.go
  2. 25 25
      daemon/daemon.go
  3. 3 0
      daemon/start.go

+ 9 - 5
daemon/create.go

@@ -74,6 +74,15 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig) (*container.Con
 		}
 	}()
 
+	if err := daemon.setSecurityOptions(container, params.HostConfig); err != nil {
+		return nil, err
+	}
+
+	// Set RWLayer for container after mount labels have been set
+	if err := daemon.setRWLayer(container); err != nil {
+		return nil, err
+	}
+
 	if err := daemon.Register(container); err != nil {
 		return nil, err
 	}
@@ -96,11 +105,6 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig) (*container.Con
 		}
 	}()
 
-	// Set RWLayer for container after mount labels have been set
-	if err := daemon.setRWLayer(container); err != nil {
-		return nil, err
-	}
-
 	if err := daemon.createContainerPlatformSpecificSettings(container, params.Config, params.HostConfig, img); err != nil {
 		return nil, err
 	}

+ 25 - 25
daemon/daemon.go

@@ -226,18 +226,30 @@ func (daemon *Daemon) load(id string) (*container.Container, error) {
 	return container, nil
 }
 
-// Register makes a container object usable by the daemon as <container.ID>
-func (daemon *Daemon) Register(container *container.Container) error {
+func (daemon *Daemon) registerName(container *container.Container) error {
 	if daemon.Exists(container.ID) {
 		return fmt.Errorf("Container is already loaded")
 	}
 	if err := validateID(container.ID); err != nil {
 		return err
 	}
-	if err := daemon.ensureName(container); err != nil {
-		return err
+	if container.Name == "" {
+		name, err := daemon.generateNewName(container.ID)
+		if err != nil {
+			return err
+		}
+		container.Name = name
+
+		if err := container.ToDiskLocking(); err != nil {
+			logrus.Errorf("Error saving container name to disk: %v", err)
+		}
 	}
 
+	return nil
+}
+
+// Register makes a container object usable by the daemon as <container.ID>
+func (daemon *Daemon) Register(container *container.Container) error {
 	// Attach to stdout and stderr
 	if container.Config.OpenStdin {
 		container.NewInputPipes()
@@ -277,21 +289,6 @@ func (daemon *Daemon) Register(container *container.Container) error {
 	return nil
 }
 
-func (daemon *Daemon) ensureName(container *container.Container) error {
-	if container.Name == "" {
-		name, err := daemon.generateNewName(container.ID)
-		if err != nil {
-			return err
-		}
-		container.Name = name
-
-		if err := container.ToDiskLocking(); err != nil {
-			logrus.Errorf("Error saving container name to disk: %v", err)
-		}
-	}
-	return nil
-}
-
 func (daemon *Daemon) restore() error {
 	type cr struct {
 		container  *container.Container
@@ -368,6 +365,10 @@ func (daemon *Daemon) restore() error {
 					logrus.Debugf("Setting default id - %s", err)
 				}
 			}
+			if err := daemon.registerName(container); err != nil {
+				logrus.Errorf("Failed to register container %s: %s", container.ID, err)
+				return
+			}
 
 			if err := daemon.Register(container); err != nil {
 				logrus.Errorf("Failed to register container %s: %s", container.ID, err)
@@ -1392,14 +1393,13 @@ func tempDir(rootDir string, rootUID, rootGID int) (string, error) {
 	return tmpDir, idtools.MkdirAllAs(tmpDir, 0700, rootUID, rootGID)
 }
 
-func (daemon *Daemon) setHostConfig(container *container.Container, hostConfig *containertypes.HostConfig) error {
+func (daemon *Daemon) setSecurityOptions(container *container.Container, hostConfig *containertypes.HostConfig) error {
 	container.Lock()
-	if err := parseSecurityOpt(container, hostConfig); err != nil {
-		container.Unlock()
-		return err
-	}
-	container.Unlock()
+	defer container.Unlock()
+	return parseSecurityOpt(container, hostConfig)
+}
 
+func (daemon *Daemon) setHostConfig(container *container.Container, hostConfig *containertypes.HostConfig) error {
 	// Do not lock while creating volumes since this could be calling out to external plugins
 	// Don't want to block other actions, like `docker ps` because we're waiting on an external plugin
 	if err := daemon.registerMountPoints(container, hostConfig); err != nil {

+ 3 - 0
daemon/start.go

@@ -31,6 +31,9 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos
 		// creating a container, not during start.
 		if hostConfig != nil {
 			logrus.Warn("DEPRECATED: Setting host configuration options when the container starts is deprecated and will be removed in Docker 1.12")
+			if err := daemon.setSecurityOptions(container, hostConfig); err != nil {
+				return err
+			}
 			if err := daemon.setHostConfig(container, hostConfig); err != nil {
 				return err
 			}