Browse Source

Merge pull request #35316 from kolyshkin/facepalm

Fix honoring tmpfs-size for user /dev/shm mount
Vincent Demeester 7 years ago
parent
commit
f70c715be0
2 changed files with 76 additions and 17 deletions
  1. 55 0
      daemon/daemon_linux_test.go
  2. 21 17
      daemon/oci_linux.go

+ 55 - 0
daemon/daemon_linux_test.go

@@ -5,6 +5,13 @@ package daemon
 import (
 import (
 	"strings"
 	"strings"
 	"testing"
 	"testing"
+
+	containertypes "github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/container"
+	"github.com/docker/docker/oci"
+	"github.com/docker/docker/pkg/idtools"
+
+	"github.com/stretchr/testify/assert"
 )
 )
 
 
 const mountsFixture = `142 78 0:38 / / rw,relatime - aufs none rw,si=573b861da0b3a05b,dio
 const mountsFixture = `142 78 0:38 / / rw,relatime - aufs none rw,si=573b861da0b3a05b,dio
@@ -102,3 +109,51 @@ func TestNotCleanupMounts(t *testing.T) {
 		t.Fatal("Expected not to clean up /dev/shm")
 		t.Fatal("Expected not to clean up /dev/shm")
 	}
 	}
 }
 }
+
+// TestTmpfsDevShmSizeOverride checks that user-specified /dev/tmpfs mount
+// size is not overriden by the default shmsize (that should only be used
+// for default /dev/shm (as in "shareable" and "private" ipc modes).
+// https://github.com/moby/moby/issues/35271
+func TestTmpfsDevShmSizeOverride(t *testing.T) {
+	size := "777m"
+	mnt := "/dev/shm"
+
+	d := Daemon{
+		idMappings: &idtools.IDMappings{},
+	}
+	c := &container.Container{
+		HostConfig: &containertypes.HostConfig{
+			ShmSize: 48 * 1024, // size we should NOT end up with
+		},
+	}
+	ms := []container.Mount{
+		{
+			Source:      "tmpfs",
+			Destination: mnt,
+			Data:        "size=" + size,
+		},
+	}
+
+	// convert ms to spec
+	spec := oci.DefaultSpec()
+	err := setMounts(&d, &spec, c, ms)
+	assert.NoError(t, err)
+
+	// Check the resulting spec for the correct size
+	found := false
+	for _, m := range spec.Mounts {
+		if m.Destination == mnt {
+			for _, o := range m.Options {
+				if !strings.HasPrefix(o, "size=") {
+					continue
+				}
+				t.Logf("%+v\n", m.Options)
+				assert.Equal(t, "size="+size, o)
+				found = true
+			}
+		}
+	}
+	if !found {
+		t.Fatal("/dev/shm not found in spec, or size option missing")
+	}
+}

+ 21 - 17
daemon/oci_linux.go

@@ -538,23 +538,35 @@ func setMounts(daemon *Daemon, s *specs.Spec, c *container.Container, mounts []c
 		userMounts[m.Destination] = struct{}{}
 		userMounts[m.Destination] = struct{}{}
 	}
 	}
 
 
-	// Filter out mounts from spec
-	noIpc := c.HostConfig.IpcMode.IsNone()
-	// Filter out mounts that are overridden by user supplied mounts
+	// Copy all mounts from spec to defaultMounts, except for
+	//  - mounts overriden by a user supplied mount;
+	//  - all mounts under /dev if a user supplied /dev is present;
+	//  - /dev/shm, in case IpcMode is none.
+	// While at it, also
+	//  - set size for /dev/shm from shmsize.
 	var defaultMounts []specs.Mount
 	var defaultMounts []specs.Mount
 	_, mountDev := userMounts["/dev"]
 	_, mountDev := userMounts["/dev"]
 	for _, m := range s.Mounts {
 	for _, m := range s.Mounts {
-		// filter out /dev/shm mount if case IpcMode is none
-		if noIpc && m.Destination == "/dev/shm" {
+		if _, ok := userMounts[m.Destination]; ok {
+			// filter out mount overridden by a user supplied mount
 			continue
 			continue
 		}
 		}
-		// filter out mount overridden by a user supplied mount
-		if _, ok := userMounts[m.Destination]; !ok {
-			if mountDev && strings.HasPrefix(m.Destination, "/dev/") {
+		if mountDev && strings.HasPrefix(m.Destination, "/dev/") {
+			// filter out everything under /dev if /dev is user-mounted
+			continue
+		}
+
+		if m.Destination == "/dev/shm" {
+			if c.HostConfig.IpcMode.IsNone() {
+				// filter out /dev/shm for "none" IpcMode
 				continue
 				continue
 			}
 			}
-			defaultMounts = append(defaultMounts, m)
+			// set size for /dev/shm mount from spec
+			sizeOpt := "size=" + strconv.FormatInt(c.HostConfig.ShmSize, 10)
+			m.Options = append(m.Options, sizeOpt)
 		}
 		}
+
+		defaultMounts = append(defaultMounts, m)
 	}
 	}
 
 
 	s.Mounts = defaultMounts
 	s.Mounts = defaultMounts
@@ -662,14 +674,6 @@ func setMounts(daemon *Daemon, s *specs.Spec, c *container.Container, mounts []c
 		s.Linux.MaskedPaths = nil
 		s.Linux.MaskedPaths = nil
 	}
 	}
 
 
-	// Set size for /dev/shm mount that comes from spec (IpcMode: private only)
-	for i, m := range s.Mounts {
-		if m.Destination == "/dev/shm" {
-			sizeOpt := "size=" + strconv.FormatInt(c.HostConfig.ShmSize, 10)
-			s.Mounts[i].Options = append(s.Mounts[i].Options, sizeOpt)
-		}
-	}
-
 	// TODO: until a kernel/mount solution exists for handling remount in a user namespace,
 	// TODO: until a kernel/mount solution exists for handling remount in a user namespace,
 	// we must clear the readonly flag for the cgroups mount (@mrunalp concurs)
 	// we must clear the readonly flag for the cgroups mount (@mrunalp concurs)
 	if uidMap := daemon.idMappings.UIDs(); uidMap != nil || c.HostConfig.Privileged {
 	if uidMap := daemon.idMappings.UIDs(); uidMap != nil || c.HostConfig.Privileged {