Browse code

Merge pull request #12159 from mrunalp/feature/ipc_share_dev

ipc: Share /dev/shm and /dev/mqueue when --ipc container:<id/name> is used

Jessie Frazelle authored on 2015/08/25 09:55:03
Showing 8 changed files
... ...
@@ -293,10 +293,17 @@ func (container *Container) Start() (err error) {
293 293
 		return err
294 294
 	}
295 295
 
296
+	if !(container.hostConfig.IpcMode.IsContainer() || container.hostConfig.IpcMode.IsHost()) {
297
+		if err := container.setupIpcDirs(); err != nil {
298
+			return err
299
+		}
300
+	}
301
+
296 302
 	mounts, err := container.setupMounts()
297 303
 	if err != nil {
298 304
 		return err
299 305
 	}
306
+	mounts = append(mounts, container.ipcMounts()...)
300 307
 
301 308
 	container.command.Mounts = mounts
302 309
 	return container.waitForStart()
... ...
@@ -355,6 +362,10 @@ func (container *Container) isNetworkAllocated() bool {
355 355
 func (container *Container) cleanup() {
356 356
 	container.ReleaseNetwork()
357 357
 
358
+	if err := container.unmountIpcMounts(); err != nil {
359
+		logrus.Errorf("%v: Failed to umount ipc filesystems: %v", container.ID, err)
360
+	}
361
+
358 362
 	if err := container.Unmount(); err != nil {
359 363
 		logrus.Errorf("%v: Failed to umount filesystem: %v", container.ID, err)
360 364
 	}
... ...
@@ -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{}
... ...
@@ -1199,3 +1217,85 @@ func (container *Container) removeMountPoints() error {
1199 1199
 	}
1200 1200
 	return nil
1201 1201
 }
1202
+
1203
+func (container *Container) shmPath() (string, error) {
1204
+	return container.GetRootResourcePath("shm")
1205
+}
1206
+func (container *Container) mqueuePath() (string, error) {
1207
+	return container.GetRootResourcePath("mqueue")
1208
+}
1209
+
1210
+func (container *Container) setupIpcDirs() error {
1211
+	shmPath, err := container.shmPath()
1212
+	if err != nil {
1213
+		return err
1214
+	}
1215
+
1216
+	if err := os.MkdirAll(shmPath, 0700); err != nil {
1217
+		return err
1218
+	}
1219
+
1220
+	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 {
1221
+		return fmt.Errorf("mounting shm tmpfs: %s", err)
1222
+	}
1223
+
1224
+	mqueuePath, err := container.mqueuePath()
1225
+	if err != nil {
1226
+		return err
1227
+	}
1228
+
1229
+	if err := os.MkdirAll(mqueuePath, 0700); err != nil {
1230
+		return err
1231
+	}
1232
+
1233
+	if err := syscall.Mount("mqueue", mqueuePath, "mqueue", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), ""); err != nil {
1234
+		return fmt.Errorf("mounting mqueue mqueue : %s", err)
1235
+	}
1236
+
1237
+	return nil
1238
+}
1239
+
1240
+func (container *Container) unmountIpcMounts() error {
1241
+	if container.hostConfig.IpcMode.IsContainer() || container.hostConfig.IpcMode.IsHost() {
1242
+		return nil
1243
+	}
1244
+
1245
+	shmPath, err := container.shmPath()
1246
+	if err != nil {
1247
+		return fmt.Errorf("shm path does not exist %v", err)
1248
+	}
1249
+
1250
+	if err := syscall.Unmount(shmPath, syscall.MNT_DETACH); err != nil {
1251
+		return fmt.Errorf("failed to umount %s filesystem %v", shmPath, err)
1252
+	}
1253
+
1254
+	mqueuePath, err := container.mqueuePath()
1255
+	if err != nil {
1256
+		return fmt.Errorf("mqueue path does not exist %v", err)
1257
+	}
1258
+
1259
+	if err := syscall.Unmount(mqueuePath, syscall.MNT_DETACH); err != nil {
1260
+		return fmt.Errorf("failed to umount %s filesystem %v", mqueuePath, err)
1261
+	}
1262
+
1263
+	return nil
1264
+}
1265
+
1266
+func (container *Container) ipcMounts() []execdriver.Mount {
1267
+	var mounts []execdriver.Mount
1268
+	label.SetFileLabel(container.ShmPath, container.MountLabel)
1269
+	mounts = append(mounts, execdriver.Mount{
1270
+		Source:      container.ShmPath,
1271
+		Destination: "/dev/shm",
1272
+		Writable:    true,
1273
+		Private:     true,
1274
+	})
1275
+	label.SetFileLabel(container.MqueuePath, container.MountLabel)
1276
+	mounts = append(mounts, execdriver.Mount{
1277
+		Source:      container.MqueuePath,
1278
+		Destination: "/dev/mqueue",
1279
+		Writable:    true,
1280
+		Private:     true,
1281
+	})
1282
+	return mounts
1283
+}
... ...
@@ -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
+}
... ...
@@ -746,6 +746,10 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
746 746
 		return nil, err
747 747
 	}
748 748
 
749
+	if err := d.cleanupMounts(); err != nil {
750
+		return nil, err
751
+	}
752
+
749 753
 	return d, nil
750 754
 }
751 755
 
... ...
@@ -791,6 +795,10 @@ func (daemon *Daemon) Shutdown() error {
791 791
 		}
792 792
 	}
793 793
 
794
+	if err := daemon.cleanupMounts(); err != nil {
795
+		return err
796
+	}
797
+
794 798
 	return nil
795 799
 }
796 800
 
797 801
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",
... ...
@@ -1889,7 +1889,7 @@ func (s *DockerSuite) TestRunModeIpcHost(c *check.C) {
1889 1889
 func (s *DockerSuite) TestRunModeIpcContainer(c *check.C) {
1890 1890
 	testRequires(c, SameHostDaemon)
1891 1891
 
1892
-	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
1892
+	out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "echo -n test > /dev/shm/test && top")
1893 1893
 
1894 1894
 	id := strings.TrimSpace(out)
1895 1895
 	state, err := inspectField(id, "State.Running")
... ...
@@ -1910,6 +1910,11 @@ func (s *DockerSuite) TestRunModeIpcContainer(c *check.C) {
1910 1910
 	if parentContainerIpc != out {
1911 1911
 		c.Fatalf("IPC different with --ipc=container:%s %s != %s\n", id, parentContainerIpc, out)
1912 1912
 	}
1913
+
1914
+	catOutput, _ := dockerCmd(c, "run", fmt.Sprintf("--ipc=container:%s", id), "busybox", "cat", "/dev/shm/test")
1915
+	if catOutput != "test" {
1916
+		c.Fatalf("Output of /dev/shm/test expected test but found: %s", catOutput)
1917
+	}
1913 1918
 }
1914 1919
 
1915 1920
 func (s *DockerSuite) TestRunModeIpcContainerNotExists(c *check.C) {