Skip to content

Commit 23750fb

Browse files
author
Jess Frazelle
committed
Merge pull request moby#15862 from calavera/share_shm_and_mqueue
Share shm and mqueue between containers.
2 parents c8bc02e + b1d2f52 commit 23750fb

File tree

10 files changed

+278
-17
lines changed

10 files changed

+278
-17
lines changed

daemon/container.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,10 +288,17 @@ func (container *Container) Start() (err error) {
288288
return err
289289
}
290290

291+
if !container.hostConfig.IpcMode.IsContainer() && !container.hostConfig.IpcMode.IsHost() {
292+
if err := container.setupIpcDirs(); err != nil {
293+
return err
294+
}
295+
}
296+
291297
mounts, err := container.setupMounts()
292298
if err != nil {
293299
return err
294300
}
301+
mounts = append(mounts, container.ipcMounts()...)
295302

296303
container.command.Mounts = mounts
297304
return container.waitForStart()
@@ -330,8 +337,12 @@ func (container *Container) isNetworkAllocated() bool {
330337
func (container *Container) cleanup() {
331338
container.releaseNetwork()
332339

340+
if err := container.unmountIpcMounts(); err != nil {
341+
logrus.Errorf("%s: Failed to umount ipc filesystems: %v", container.ID, err)
342+
}
343+
333344
if err := container.Unmount(); err != nil {
334-
logrus.Errorf("%v: Failed to umount filesystem: %v", container.ID, err)
345+
logrus.Errorf("%s: Failed to umount filesystem: %v", container.ID, err)
335346
}
336347

337348
for _, eConfig := range container.execCommands.s {

daemon/container_unix.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ type Container struct {
5252
AppArmorProfile string
5353
HostnamePath string
5454
HostsPath string
55+
ShmPath string
56+
MqueuePath string
5557
MountPoints map[string]*mountPoint
5658
ResolvConfPath string
5759

@@ -192,15 +194,31 @@ func populateCommand(c *Container, env []string) error {
192194
}
193195

194196
ipc := &execdriver.Ipc{}
197+
var err error
198+
c.ShmPath, err = c.shmPath()
199+
if err != nil {
200+
return err
201+
}
202+
203+
c.MqueuePath, err = c.mqueuePath()
204+
if err != nil {
205+
return err
206+
}
195207

196208
if c.hostConfig.IpcMode.IsContainer() {
197209
ic, err := c.getIpcContainer()
198210
if err != nil {
199211
return err
200212
}
201213
ipc.ContainerID = ic.ID
214+
c.ShmPath = ic.ShmPath
215+
c.MqueuePath = ic.MqueuePath
202216
} else {
203217
ipc.HostIpc = c.hostConfig.IpcMode.IsHost()
218+
if ipc.HostIpc {
219+
c.ShmPath = "/dev/shm"
220+
c.MqueuePath = "/dev/mqueue"
221+
}
204222
}
205223

206224
pid := &execdriver.Pid{}
@@ -1236,3 +1254,99 @@ func (container *Container) removeMountPoints(rm bool) error {
12361254
}
12371255
return nil
12381256
}
1257+
1258+
func (container *Container) shmPath() (string, error) {
1259+
return container.getRootResourcePath("shm")
1260+
}
1261+
func (container *Container) mqueuePath() (string, error) {
1262+
return container.getRootResourcePath("mqueue")
1263+
}
1264+
1265+
func (container *Container) setupIpcDirs() error {
1266+
shmPath, err := container.shmPath()
1267+
if err != nil {
1268+
return err
1269+
}
1270+
1271+
if err := os.MkdirAll(shmPath, 0700); err != nil {
1272+
return err
1273+
}
1274+
1275+
if err := syscall.Mount("shm", shmPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel("mode=1777,size=65536k", container.getMountLabel())); err != nil {
1276+
return fmt.Errorf("mounting shm tmpfs: %s", err)
1277+
}
1278+
1279+
mqueuePath, err := container.mqueuePath()
1280+
if err != nil {
1281+
return err
1282+
}
1283+
1284+
if err := os.MkdirAll(mqueuePath, 0700); err != nil {
1285+
return err
1286+
}
1287+
1288+
if err := syscall.Mount("mqueue", mqueuePath, "mqueue", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), ""); err != nil {
1289+
return fmt.Errorf("mounting mqueue mqueue : %s", err)
1290+
}
1291+
1292+
return nil
1293+
}
1294+
1295+
func (container *Container) unmountIpcMounts() error {
1296+
if container.hostConfig.IpcMode.IsContainer() || container.hostConfig.IpcMode.IsHost() {
1297+
return nil
1298+
}
1299+
1300+
var errors []string
1301+
shmPath, err := container.shmPath()
1302+
if err != nil {
1303+
logrus.Error(err)
1304+
errors = append(errors, err.Error())
1305+
} else {
1306+
if err := detachMounted(shmPath); err != nil {
1307+
logrus.Errorf("failed to umount %s: %v", shmPath, err)
1308+
errors = append(errors, err.Error())
1309+
}
1310+
1311+
}
1312+
1313+
mqueuePath, err := container.mqueuePath()
1314+
if err != nil {
1315+
logrus.Error(err)
1316+
errors = append(errors, err.Error())
1317+
} else {
1318+
if err := detachMounted(mqueuePath); err != nil {
1319+
logrus.Errorf("failed to umount %s: %v", mqueuePath, err)
1320+
errors = append(errors, err.Error())
1321+
}
1322+
}
1323+
1324+
if len(errors) > 0 {
1325+
return fmt.Errorf("failed to cleanup ipc mounts:\n%v", strings.Join(errors, "\n"))
1326+
}
1327+
1328+
return nil
1329+
}
1330+
1331+
func (container *Container) ipcMounts() []execdriver.Mount {
1332+
var mounts []execdriver.Mount
1333+
label.SetFileLabel(container.ShmPath, container.MountLabel)
1334+
mounts = append(mounts, execdriver.Mount{
1335+
Source: container.ShmPath,
1336+
Destination: "/dev/shm",
1337+
Writable: true,
1338+
Private: true,
1339+
})
1340+
label.SetFileLabel(container.MqueuePath, container.MountLabel)
1341+
mounts = append(mounts, execdriver.Mount{
1342+
Source: container.MqueuePath,
1343+
Destination: "/dev/mqueue",
1344+
Writable: true,
1345+
Private: true,
1346+
})
1347+
return mounts
1348+
}
1349+
1350+
func detachMounted(path string) error {
1351+
return syscall.Unmount(path, syscall.MNT_DETACH)
1352+
}

daemon/container_windows.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,15 @@ func (container *Container) prepareMountPoints() error {
170170
func (container *Container) removeMountPoints(_ bool) error {
171171
return nil
172172
}
173+
174+
func (container *Container) setupIpcDirs() error {
175+
return nil
176+
}
177+
178+
func (container *Container) unmountIpcMounts() error {
179+
return nil
180+
}
181+
182+
func (container *Container) ipcMounts() []execdriver.Mount {
183+
return nil
184+
}

daemon/daemon.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,9 @@ func (daemon *Daemon) Register(container *Container) error {
217217
}
218218
daemon.execDriver.Terminate(cmd)
219219

220+
if err := container.unmountIpcMounts(); err != nil {
221+
logrus.Errorf("%s: Failed to umount ipc filesystems: %v", container.ID, err)
222+
}
220223
if err := container.Unmount(); err != nil {
221224
logrus.Debugf("unmount error %s", err)
222225
}
@@ -766,6 +769,11 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
766769
d.EventsService = eventsService
767770
d.volumes = volStore
768771
d.root = config.Root
772+
773+
if err := d.cleanupMounts(); err != nil {
774+
return nil, err
775+
}
776+
769777
go d.execCommandGC()
770778

771779
if err := d.restore(); err != nil {
@@ -848,6 +856,10 @@ func (daemon *Daemon) Shutdown() error {
848856
}
849857
}
850858

859+
if err := daemon.cleanupMounts(); err != nil {
860+
return err
861+
}
862+
851863
return nil
852864
}
853865

daemon/daemon_linux.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package daemon
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"io"
7+
"os"
8+
"path/filepath"
9+
"strings"
10+
11+
"github.com/Sirupsen/logrus"
12+
)
13+
14+
// cleanupMounts umounts shm/mqueue mounts for old containers
15+
func (daemon *Daemon) cleanupMounts() error {
16+
logrus.Debugf("Cleaning up old shm/mqueue mounts: start.")
17+
f, err := os.Open("/proc/self/mountinfo")
18+
if err != nil {
19+
return err
20+
}
21+
defer f.Close()
22+
23+
return daemon.cleanupMountsFromReader(f, detachMounted)
24+
}
25+
26+
func (daemon *Daemon) cleanupMountsFromReader(reader io.Reader, unmount func(target string) error) error {
27+
sc := bufio.NewScanner(reader)
28+
var errors []string
29+
for sc.Scan() {
30+
line := sc.Text()
31+
fields := strings.Fields(line)
32+
if strings.HasPrefix(fields[4], daemon.repository) {
33+
logrus.Debugf("Mount base: %v, repository %s", fields[4], daemon.repository)
34+
mnt := fields[4]
35+
mountBase := filepath.Base(mnt)
36+
if mountBase == "mqueue" || mountBase == "shm" {
37+
logrus.Debugf("Unmounting %v", mnt)
38+
if err := unmount(mnt); err != nil {
39+
logrus.Error(err)
40+
errors = append(errors, err.Error())
41+
}
42+
}
43+
}
44+
}
45+
46+
if err := sc.Err(); err != nil {
47+
return err
48+
}
49+
50+
if len(errors) > 0 {
51+
return fmt.Errorf("Error cleaningup mounts:\n%v", strings.Join(errors, "\n"))
52+
}
53+
54+
logrus.Debugf("Cleaning up old shm/mqueue mounts: done.")
55+
return nil
56+
}

daemon/daemon_linux_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// +build linux
2+
3+
package daemon
4+
5+
import (
6+
"strings"
7+
"testing"
8+
)
9+
10+
func TestCleanupMounts(t *testing.T) {
11+
fixture := `230 138 0:60 / / rw,relatime - overlay overlay rw,lowerdir=/var/lib/docker/overlay/0ef9f93d5d365c1385b09d54bbee6afff3d92002c16f22eccb6e1549b2ff97d8/root,upperdir=/var/lib/docker/overlay/dfac036ce135a8914e292cb2f6fea114f7339983c186366aa26d0051e93162cb/upper,workdir=/var/lib/docker/overlay/dfac036ce135a8914e292cb2f6fea114f7339983c186366aa26d0051e93162cb/work
12+
231 230 0:56 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw
13+
232 230 0:57 / /dev rw,nosuid - tmpfs tmpfs rw,mode=755
14+
233 232 0:58 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666
15+
234 232 0:59 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k
16+
235 232 0:55 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw
17+
236 230 0:61 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw
18+
237 236 0:62 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw
19+
238 237 0:21 /system.slice/docker.service /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd
20+
239 237 0:23 /docker/dfac036ce135a8914e292cb2f6fea114f7339983c186366aa26d0051e93162cb /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,perf_event
21+
240 237 0:24 /docker/dfac036ce135a8914e292cb2f6fea114f7339983c186366aa26d0051e93162cb /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpuset,clone_children
22+
241 237 0:25 /docker/dfac036ce135a8914e292cb2f6fea114f7339983c186366aa26d0051e93162cb /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,devices
23+
242 237 0:26 /docker/dfac036ce135a8914e292cb2f6fea114f7339983c186366aa26d0051e93162cb /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,freezer
24+
243 237 0:27 /docker/dfac036ce135a8914e292cb2f6fea114f7339983c186366aa26d0051e93162cb /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpu,cpuacct
25+
244 237 0:28 /docker/dfac036ce135a8914e292cb2f6fea114f7339983c186366aa26d0051e93162cb /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,blkio
26+
245 237 0:29 /docker/dfac036ce135a8914e292cb2f6fea114f7339983c186366aa26d0051e93162cb /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,net_cls,net_prio
27+
246 237 0:30 /docker/dfac036ce135a8914e292cb2f6fea114f7339983c186366aa26d0051e93162cb /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,hugetlb
28+
247 237 0:31 /docker/dfac036ce135a8914e292cb2f6fea114f7339983c186366aa26d0051e93162cb /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory
29+
248 230 253:1 /var/lib/docker/volumes/510cc41ac68c48bd4eac932e3e09711673876287abf1b185312cfbfe6261a111/_data /var/lib/docker rw,relatime - ext4 /dev/disk/by-uuid/ba70ea0c-1a8f-4ee4-9687-cb393730e2b5 rw,errors=remount-ro,data=ordered
30+
250 230 253:1 /var/lib/docker/containers/dfac036ce135a8914e292cb2f6fea114f7339983c186366aa26d0051e93162cb/hostname /etc/hostname rw,relatime - ext4 /dev/disk/by-uuid/ba70ea0c-1a8f-4ee4-9687-cb393730e2b5 rw,errors=remount-ro,data=ordered
31+
251 230 253:1 /var/lib/docker/containers/dfac036ce135a8914e292cb2f6fea114f7339983c186366aa26d0051e93162cb/hosts /etc/hosts rw,relatime - ext4 /dev/disk/by-uuid/ba70ea0c-1a8f-4ee4-9687-cb393730e2b5 rw,errors=remount-ro,data=ordered
32+
252 232 0:13 /1 /dev/console rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=000
33+
139 236 0:11 / /sys/kernel/security rw,relatime - securityfs none rw
34+
140 230 0:54 / /tmp rw,relatime - tmpfs none rw
35+
145 230 0:3 / /run/docker/netns/default rw - nsfs nsfs rw
36+
130 140 0:45 / /tmp/docker_recursive_mount_test312125472/tmpfs rw,relatime - tmpfs tmpfs rw
37+
131 230 0:3 / /run/docker/netns/47903e2e6701 rw - nsfs nsfs rw
38+
133 230 0:55 / /go/src/github.com/docker/docker/bundles/1.9.0-dev/test-integration-cli/d45526097/graph/containers/47903e2e67014246eba27607809d5f5c2437c3bf84c2986393448f84093cc40b/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw`
39+
40+
d := &Daemon{
41+
repository: "/go/src/github.com/docker/docker/bundles/1.9.0-dev/test-integration-cli/d45526097/graph/containers/",
42+
}
43+
44+
expected := "/go/src/github.com/docker/docker/bundles/1.9.0-dev/test-integration-cli/d45526097/graph/containers/47903e2e67014246eba27607809d5f5c2437c3bf84c2986393448f84093cc40b/mqueue"
45+
var unmounted bool
46+
unmount := func(target string) error {
47+
if target == expected {
48+
unmounted = true
49+
}
50+
return nil
51+
}
52+
53+
d.cleanupMountsFromReader(strings.NewReader(fixture), unmount)
54+
55+
if !unmounted {
56+
t.Fatalf("Expected to unmount the mqueue")
57+
}
58+
}

daemon/daemon_windows.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,7 @@ func (daemon *Daemon) newBaseContainer(id string) Container {
146146
},
147147
}
148148
}
149+
150+
func (daemon *Daemon) cleanupMounts() error {
151+
return nil
152+
}

daemon/execdriver/native/template/default_template.go

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,6 @@ func New() *configs.Config {
6161
Flags: syscall.MS_NOSUID | syscall.MS_NOEXEC,
6262
Data: "newinstance,ptmxmode=0666,mode=0620,gid=5",
6363
},
64-
{
65-
Device: "tmpfs",
66-
Source: "shm",
67-
Destination: "/dev/shm",
68-
Data: "mode=1777,size=65536k",
69-
Flags: defaultMountFlags,
70-
},
71-
{
72-
Source: "mqueue",
73-
Destination: "/dev/mqueue",
74-
Device: "mqueue",
75-
Flags: defaultMountFlags,
76-
},
7764
{
7865
Source: "sysfs",
7966
Destination: "/sys",

integration-cli/docker_cli_daemon_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,9 +1475,11 @@ func (s *DockerDaemonSuite) TestCleanupMountsAfterCrash(c *check.C) {
14751475
id := strings.TrimSpace(out)
14761476
c.Assert(s.d.cmd.Process.Signal(os.Kill), check.IsNil)
14771477
c.Assert(s.d.Start(), check.IsNil)
1478-
mountOut, err := exec.Command("mount").CombinedOutput()
1478+
mountOut, err := ioutil.ReadFile("/proc/self/mountinfo")
14791479
c.Assert(err, check.IsNil, check.Commentf("Output: %s", mountOut))
1480-
c.Assert(strings.Contains(string(mountOut), id), check.Equals, false, check.Commentf("Something mounted from older daemon start: %s", mountOut))
1480+
1481+
comment := check.Commentf("%s is still mounted from older daemon start:\nDaemon root repository %s\n%s", id, s.d.folder, mountOut)
1482+
c.Assert(strings.Contains(string(mountOut), id), check.Equals, false, comment)
14811483
}
14821484

14831485
func (s *DockerDaemonSuite) TestRunContainerWithBridgeNone(c *check.C) {

0 commit comments

Comments
 (0)