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)

(cherry picked from commit d88fe447df0e87b3a57f9d08b108b141dd72678c)

Mrunal Patel authored on 2015/08/04 07:05:34
Showing 7 changed files
... ...
@@ -296,10 +296,17 @@ func (container *Container) Start() (err error) {
296 296
 		return err
297 297
 	}
298 298
 
299
+	if !(container.hostConfig.IpcMode.IsContainer() || container.hostConfig.IpcMode.IsHost()) {
300
+		if err := container.setupIpcDirs(); err != nil {
301
+			return err
302
+		}
303
+	}
304
+
299 305
 	mounts, err := container.setupMounts()
300 306
 	if err != nil {
301 307
 		return err
302 308
 	}
309
+	mounts = append(mounts, container.ipcMounts()...)
303 310
 
304 311
 	container.command.Mounts = mounts
305 312
 	return container.waitForStart()
... ...
@@ -358,6 +365,10 @@ func (container *Container) isNetworkAllocated() bool {
358 358
 func (container *Container) cleanup() {
359 359
 	container.releaseNetwork()
360 360
 
361
+	if err := container.unmountIpcMounts(); err != nil {
362
+		logrus.Errorf("%v: Failed to umount ipc filesystems: %v", container.ID, err)
363
+	}
364
+
361 365
 	if err := container.Unmount(); err != nil {
362 366
 		logrus.Errorf("%v: Failed to umount filesystem: %v", container.ID, err)
363 367
 	}
... ...
@@ -50,6 +50,8 @@ type Container struct {
50 50
 	AppArmorProfile string
51 51
 	HostnamePath    string
52 52
 	HostsPath       string
53
+	ShmPath         string
54
+	MqueuePath      string
53 55
 	MountPoints     map[string]*mountPoint
54 56
 	ResolvConfPath  string
55 57
 
... ...
@@ -189,6 +191,16 @@ func populateCommand(c *Container, env []string) error {
189 189
 	}
190 190
 
191 191
 	ipc := &execdriver.Ipc{}
192
+	var err error
193
+	c.ShmPath, err = c.shmPath()
194
+	if err != nil {
195
+		return err
196
+	}
197
+
198
+	c.MqueuePath, err = c.mqueuePath()
199
+	if err != nil {
200
+		return err
201
+	}
192 202
 
193 203
 	if c.hostConfig.IpcMode.IsContainer() {
194 204
 		ic, err := c.getIpcContainer()
... ...
@@ -196,8 +208,14 @@ func populateCommand(c *Container, env []string) error {
196 196
 			return err
197 197
 		}
198 198
 		ipc.ContainerID = ic.ID
199
+		c.ShmPath = ic.ShmPath
200
+		c.MqueuePath = ic.MqueuePath
199 201
 	} else {
200 202
 		ipc.HostIpc = c.hostConfig.IpcMode.IsHost()
203
+		if ipc.HostIpc {
204
+			c.ShmPath = "/dev/shm"
205
+			c.MqueuePath = "/dev/mqueue"
206
+		}
201 207
 	}
202 208
 
203 209
 	pid := &execdriver.Pid{}
... ...
@@ -1222,3 +1240,85 @@ func (container *Container) removeMountPoints(rm bool) error {
1222 1222
 	}
1223 1223
 	return nil
1224 1224
 }
1225
+
1226
+func (container *Container) shmPath() (string, error) {
1227
+	return container.GetRootResourcePath("shm")
1228
+}
1229
+func (container *Container) mqueuePath() (string, error) {
1230
+	return container.GetRootResourcePath("mqueue")
1231
+}
1232
+
1233
+func (container *Container) setupIpcDirs() error {
1234
+	shmPath, err := container.shmPath()
1235
+	if err != nil {
1236
+		return err
1237
+	}
1238
+
1239
+	if err := os.MkdirAll(shmPath, 0700); err != nil {
1240
+		return err
1241
+	}
1242
+
1243
+	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 {
1244
+		return fmt.Errorf("mounting shm tmpfs: %s", err)
1245
+	}
1246
+
1247
+	mqueuePath, err := container.mqueuePath()
1248
+	if err != nil {
1249
+		return err
1250
+	}
1251
+
1252
+	if err := os.MkdirAll(mqueuePath, 0700); err != nil {
1253
+		return err
1254
+	}
1255
+
1256
+	if err := syscall.Mount("mqueue", mqueuePath, "mqueue", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), ""); err != nil {
1257
+		return fmt.Errorf("mounting mqueue mqueue : %s", err)
1258
+	}
1259
+
1260
+	return nil
1261
+}
1262
+
1263
+func (container *Container) unmountIpcMounts() error {
1264
+	if container.hostConfig.IpcMode.IsContainer() || container.hostConfig.IpcMode.IsHost() {
1265
+		return nil
1266
+	}
1267
+
1268
+	shmPath, err := container.shmPath()
1269
+	if err != nil {
1270
+		return fmt.Errorf("shm path does not exist %v", err)
1271
+	}
1272
+
1273
+	if err := syscall.Unmount(shmPath, syscall.MNT_DETACH); err != nil {
1274
+		return fmt.Errorf("failed to umount %s filesystem %v", shmPath, err)
1275
+	}
1276
+
1277
+	mqueuePath, err := container.mqueuePath()
1278
+	if err != nil {
1279
+		return fmt.Errorf("mqueue path does not exist %v", err)
1280
+	}
1281
+
1282
+	if err := syscall.Unmount(mqueuePath, syscall.MNT_DETACH); err != nil {
1283
+		return fmt.Errorf("failed to umount %s filesystem %v", mqueuePath, err)
1284
+	}
1285
+
1286
+	return nil
1287
+}
1288
+
1289
+func (container *Container) ipcMounts() []execdriver.Mount {
1290
+	var mounts []execdriver.Mount
1291
+	label.SetFileLabel(container.ShmPath, container.MountLabel)
1292
+	mounts = append(mounts, execdriver.Mount{
1293
+		Source:      container.ShmPath,
1294
+		Destination: "/dev/shm",
1295
+		Writable:    true,
1296
+		Private:     true,
1297
+	})
1298
+	label.SetFileLabel(container.MqueuePath, container.MountLabel)
1299
+	mounts = append(mounts, execdriver.Mount{
1300
+		Source:      container.MqueuePath,
1301
+		Destination: "/dev/mqueue",
1302
+		Writable:    true,
1303
+		Private:     true,
1304
+	})
1305
+	return mounts
1306
+}
... ...
@@ -163,3 +163,15 @@ func (container *Container) prepareMountPoints() error {
163 163
 func (container *Container) removeMountPoints(_ bool) error {
164 164
 	return nil
165 165
 }
166
+
167
+func (container *Container) setupIpcDirs() error {
168
+	return nil
169
+}
170
+
171
+func (container *Container) unmountIpcMounts() error {
172
+	return nil
173
+}
174
+
175
+func (container *Container) ipcMounts() []execdriver.Mount {
176
+	return nil
177
+}
... ...
@@ -762,6 +762,10 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
762 762
 		return nil, err
763 763
 	}
764 764
 
765
+	if err := d.cleanupMounts(); err != nil {
766
+		return nil, err
767
+	}
768
+
765 769
 	return d, nil
766 770
 }
767 771
 
... ...
@@ -838,6 +842,10 @@ func (daemon *Daemon) Shutdown() error {
838 838
 		}
839 839
 	}
840 840
 
841
+	if err := daemon.cleanupMounts(); err != nil {
842
+		return err
843
+	}
844
+
841 845
 	return nil
842 846
 }
843 847
 
844 848
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
+}
... ...
@@ -141,3 +141,7 @@ func (daemon *Daemon) newBaseContainer(id string) Container {
141 141
 		},
142 142
 	}
143 143
 }
144
+
145
+func (daemon *Daemon) cleanupMounts() error {
146
+	return nil
147
+}
... ...
@@ -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",