Browse code

Add support for sharing /dev/shm/ and /dev/mqueue between containers

This changeset creates /dev/shm and /dev/mqueue mounts for each container under
/var/lib/containers/<id>/ and bind mounts them into the container. When --ipc:container<id/name>
is used, then the /dev/shm and /dev/mqueue of the ipc container are used instead of creating
new ones for the container.

Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
Docker-DCO-1.1-Signed-off-by: Dan Walsh <dwalsh@redhat.com> (github: rhatdan)

Mrunal Patel authored on 2015/08/04 07:05:34
Showing 7 changed files
... ...
@@ -292,10 +292,17 @@ func (container *Container) Start() (err error) {
292 292
 		return err
293 293
 	}
294 294
 
295
+	if !(container.hostConfig.IpcMode.IsContainer() || container.hostConfig.IpcMode.IsHost()) {
296
+		if err := container.setupIpcDirs(); err != nil {
297
+			return err
298
+		}
299
+	}
300
+
295 301
 	mounts, err := container.setupMounts()
296 302
 	if err != nil {
297 303
 		return err
298 304
 	}
305
+	mounts = append(mounts, container.ipcMounts()...)
299 306
 
300 307
 	container.command.Mounts = mounts
301 308
 	return container.waitForStart()
... ...
@@ -354,6 +361,10 @@ func (container *Container) isNetworkAllocated() bool {
354 354
 func (container *Container) cleanup() {
355 355
 	container.ReleaseNetwork()
356 356
 
357
+	if err := container.unmountIpcMounts(); err != nil {
358
+		logrus.Errorf("%v: Failed to umount ipc filesystems: %v", container.ID, err)
359
+	}
360
+
357 361
 	if err := container.Unmount(); err != nil {
358 362
 		logrus.Errorf("%v: Failed to umount filesystem: %v", container.ID, err)
359 363
 	}
... ...
@@ -45,6 +45,8 @@ type Container struct {
45 45
 	AppArmorProfile string
46 46
 	HostnamePath    string
47 47
 	HostsPath       string
48
+	ShmPath         string
49
+	MqueuePath      string
48 50
 	MountPoints     map[string]*mountPoint
49 51
 	ResolvConfPath  string
50 52
 	UpdateDns       bool
... ...
@@ -184,6 +186,16 @@ func populateCommand(c *Container, env []string) error {
184 184
 	}
185 185
 
186 186
 	ipc := &execdriver.Ipc{}
187
+	var err error
188
+	c.ShmPath, err = c.shmPath()
189
+	if err != nil {
190
+		return err
191
+	}
192
+
193
+	c.MqueuePath, err = c.mqueuePath()
194
+	if err != nil {
195
+		return err
196
+	}
187 197
 
188 198
 	if c.hostConfig.IpcMode.IsContainer() {
189 199
 		ic, err := c.getIpcContainer()
... ...
@@ -191,8 +203,14 @@ func populateCommand(c *Container, env []string) error {
191 191
 			return err
192 192
 		}
193 193
 		ipc.ContainerID = ic.ID
194
+		c.ShmPath = ic.ShmPath
195
+		c.MqueuePath = ic.MqueuePath
194 196
 	} else {
195 197
 		ipc.HostIpc = c.hostConfig.IpcMode.IsHost()
198
+		if ipc.HostIpc {
199
+			c.ShmPath = "/dev/shm"
200
+			c.MqueuePath = "/dev/mqueue"
201
+		}
196 202
 	}
197 203
 
198 204
 	pid := &execdriver.Pid{}
... ...
@@ -1193,3 +1211,85 @@ func (container *Container) removeMountPoints() error {
1193 1193
 	}
1194 1194
 	return nil
1195 1195
 }
1196
+
1197
+func (container *Container) shmPath() (string, error) {
1198
+	return container.GetRootResourcePath("shm")
1199
+}
1200
+func (container *Container) mqueuePath() (string, error) {
1201
+	return container.GetRootResourcePath("mqueue")
1202
+}
1203
+
1204
+func (container *Container) setupIpcDirs() error {
1205
+	shmPath, err := container.shmPath()
1206
+	if err != nil {
1207
+		return err
1208
+	}
1209
+
1210
+	if err := os.MkdirAll(shmPath, 0700); err != nil {
1211
+		return err
1212
+	}
1213
+
1214
+	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 {
1215
+		return fmt.Errorf("mounting shm tmpfs: %s", err)
1216
+	}
1217
+
1218
+	mqueuePath, err := container.mqueuePath()
1219
+	if err != nil {
1220
+		return err
1221
+	}
1222
+
1223
+	if err := os.MkdirAll(mqueuePath, 0700); err != nil {
1224
+		return err
1225
+	}
1226
+
1227
+	if err := syscall.Mount("mqueue", mqueuePath, "mqueue", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), ""); err != nil {
1228
+		return fmt.Errorf("mounting mqueue mqueue : %s", err)
1229
+	}
1230
+
1231
+	return nil
1232
+}
1233
+
1234
+func (container *Container) unmountIpcMounts() error {
1235
+	if container.hostConfig.IpcMode.IsContainer() || container.hostConfig.IpcMode.IsHost() {
1236
+		return nil
1237
+	}
1238
+
1239
+	shmPath, err := container.shmPath()
1240
+	if err != nil {
1241
+		return fmt.Errorf("shm path does not exist %v", err)
1242
+	}
1243
+
1244
+	if err := syscall.Unmount(shmPath, syscall.MNT_DETACH); err != nil {
1245
+		return fmt.Errorf("failed to umount %s filesystem %v", shmPath, err)
1246
+	}
1247
+
1248
+	mqueuePath, err := container.mqueuePath()
1249
+	if err != nil {
1250
+		return fmt.Errorf("mqueue path does not exist %v", err)
1251
+	}
1252
+
1253
+	if err := syscall.Unmount(mqueuePath, syscall.MNT_DETACH); err != nil {
1254
+		return fmt.Errorf("failed to umount %s filesystem %v", mqueuePath, err)
1255
+	}
1256
+
1257
+	return nil
1258
+}
1259
+
1260
+func (container *Container) ipcMounts() []execdriver.Mount {
1261
+	var mounts []execdriver.Mount
1262
+	label.SetFileLabel(container.ShmPath, container.MountLabel)
1263
+	mounts = append(mounts, execdriver.Mount{
1264
+		Source:      container.ShmPath,
1265
+		Destination: "/dev/shm",
1266
+		Writable:    true,
1267
+		Private:     true,
1268
+	})
1269
+	label.SetFileLabel(container.MqueuePath, container.MountLabel)
1270
+	mounts = append(mounts, execdriver.Mount{
1271
+		Source:      container.MqueuePath,
1272
+		Destination: "/dev/mqueue",
1273
+		Writable:    true,
1274
+		Private:     true,
1275
+	})
1276
+	return mounts
1277
+}
... ...
@@ -172,3 +172,15 @@ func (container *Container) prepareMountPoints() error {
172 172
 func (container *Container) removeMountPoints() error {
173 173
 	return nil
174 174
 }
175
+
176
+func (container *Container) setupIpcDirs() error {
177
+	return nil
178
+}
179
+
180
+func (container *Container) unmountIpcMounts() error {
181
+	return nil
182
+}
183
+
184
+func (container *Container) ipcMounts() []execdriver.Mount {
185
+	return nil
186
+}
... ...
@@ -745,6 +745,10 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
745 745
 		return nil, err
746 746
 	}
747 747
 
748
+	if err := d.cleanupMounts(); err != nil {
749
+		return nil, err
750
+	}
751
+
748 752
 	return d, nil
749 753
 }
750 754
 
... ...
@@ -789,6 +793,10 @@ func (daemon *Daemon) Shutdown() error {
789 789
 		}
790 790
 	}
791 791
 
792
+	if err := daemon.cleanupMounts(); err != nil {
793
+		return err
794
+	}
795
+
792 796
 	return nil
793 797
 }
794 798
 
795 799
new file mode 100644
... ...
@@ -0,0 +1,44 @@
0
+package daemon
1
+
2
+import (
3
+	"bufio"
4
+	"os"
5
+	"path/filepath"
6
+	"strings"
7
+
8
+	"github.com/Sirupsen/logrus"
9
+	"github.com/docker/docker/pkg/mount"
10
+)
11
+
12
+// cleanupMounts umounts shm/mqueue mounts for old containers
13
+func (daemon *Daemon) cleanupMounts() error {
14
+	logrus.Debugf("Cleaning up old shm/mqueue mounts: start.")
15
+	f, err := os.Open("/proc/self/mountinfo")
16
+	if err != nil {
17
+		return err
18
+	}
19
+	defer f.Close()
20
+
21
+	sc := bufio.NewScanner(f)
22
+	for sc.Scan() {
23
+		line := sc.Text()
24
+		fields := strings.Split(line, " ")
25
+		if strings.HasPrefix(fields[4], daemon.repository) {
26
+			mnt := fields[4]
27
+			mountBase := filepath.Base(mnt)
28
+			if mountBase == "mqueue" || mountBase == "shm" {
29
+				logrus.Debugf("Unmounting %+v", mnt)
30
+				if err := mount.Unmount(mnt); err != nil {
31
+					return err
32
+				}
33
+			}
34
+		}
35
+	}
36
+
37
+	if err := sc.Err(); err != nil {
38
+		return err
39
+	}
40
+
41
+	logrus.Debugf("Cleaning up old shm/mqueue mounts: done.")
42
+	return nil
43
+}
... ...
@@ -138,3 +138,7 @@ func (daemon *Daemon) newBaseContainer(id string) Container {
138 138
 		},
139 139
 	}
140 140
 }
141
+
142
+func (daemon *Daemon) cleanupMounts() error {
143
+	return nil
144
+}
... ...
@@ -62,19 +62,6 @@ func New() *configs.Config {
62 62
 				Data:        "newinstance,ptmxmode=0666,mode=0620,gid=5",
63 63
 			},
64 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
-			},
77
-			{
78 65
 				Source:      "sysfs",
79 66
 				Destination: "/sys",
80 67
 				Device:      "sysfs",