Browse code

Decouple daemon and container to mount and unmount filesystems.

Side effects:
- Decouple daemon and container to start containers.
- Decouple daemon and container to copy files.

Signed-off-by: David Calavera <david.calavera@gmail.com>

David Calavera authored on 2015/11/03 10:06:09
Showing 17 changed files
... ...
@@ -130,6 +130,12 @@ type Docker interface {
130 130
 	Release(sessionID string, activeImages []string)
131 131
 	// Kill stops the container execution abruptly.
132 132
 	Kill(c *daemon.Container) error
133
+	// Mount mounts the root filesystem for the container.
134
+	Mount(c *daemon.Container) error
135
+	// Unmount unmounts the root filesystem for the container.
136
+	Unmount(c *daemon.Container) error
137
+	// Start starts a new container
138
+	Start(c *daemon.Container) error
133 139
 }
134 140
 
135 141
 // ImageCache abstracts an image cache store.
... ...
@@ -399,8 +399,8 @@ func run(b *Builder, args []string, attributes map[string]bool, original string)
399 399
 
400 400
 	// Ensure that we keep the container mounted until the commit
401 401
 	// to avoid unmounting and then mounting directly again
402
-	c.Mount()
403
-	defer c.Unmount()
402
+	b.docker.Mount(c)
403
+	defer b.docker.Unmount(c)
404 404
 
405 405
 	err = b.run(c)
406 406
 	if err != nil {
... ...
@@ -67,10 +67,10 @@ func (b *Builder) commit(id string, autoCmd *stringutils.StrSlice, comment strin
67 67
 		}
68 68
 		id = container.ID
69 69
 
70
-		if err := container.Mount(); err != nil {
70
+		if err := b.docker.Mount(container); err != nil {
71 71
 			return err
72 72
 		}
73
-		defer container.Unmount()
73
+		defer b.docker.Unmount(container)
74 74
 	}
75 75
 
76 76
 	container, err := b.docker.Container(id)
... ...
@@ -201,7 +201,7 @@ func (b *Builder) runContextCommand(args []string, allowRemote bool, allowLocalD
201 201
 	if err != nil {
202 202
 		return err
203 203
 	}
204
-	defer container.Unmount()
204
+	defer b.docker.Unmount(container)
205 205
 	b.tmpContainers[container.ID] = struct{}{}
206 206
 
207 207
 	comment := fmt.Sprintf("%s %s in %s", cmdName, origPaths, dest)
... ...
@@ -524,7 +524,7 @@ func (b *Builder) create() (*daemon.Container, error) {
524 524
 	if err != nil {
525 525
 		return nil, err
526 526
 	}
527
-	defer c.Unmount()
527
+	defer b.docker.Unmount(c)
528 528
 	for _, warning := range warnings {
529 529
 		fmt.Fprintf(b.Stdout, " ---> [Warning] %s\n", warning)
530 530
 	}
... ...
@@ -549,7 +549,7 @@ func (b *Builder) run(c *daemon.Container) error {
549 549
 	}
550 550
 
551 551
 	//start the container
552
-	if err := c.Start(); err != nil {
552
+	if err := b.docker.Start(c); err != nil {
553 553
 		return err
554 554
 	}
555 555
 
... ...
@@ -30,7 +30,7 @@ func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, err
30 30
 		res = res[1:]
31 31
 	}
32 32
 
33
-	return container.copy(res)
33
+	return daemon.containerCopy(container, res)
34 34
 }
35 35
 
36 36
 // ContainerStatPath stats the filesystem resource at the specified path in the
... ...
@@ -41,7 +41,7 @@ func (daemon *Daemon) ContainerStatPath(name string, path string) (stat *types.C
41 41
 		return nil, err
42 42
 	}
43 43
 
44
-	return container.StatPath(path)
44
+	return daemon.containerStatPath(container, path)
45 45
 }
46 46
 
47 47
 // ContainerArchivePath creates an archive of the filesystem resource at the
... ...
@@ -53,7 +53,7 @@ func (daemon *Daemon) ContainerArchivePath(name string, path string) (content io
53 53
 		return nil, nil, err
54 54
 	}
55 55
 
56
-	return container.ArchivePath(path)
56
+	return daemon.containerArchivePath(container, path)
57 57
 }
58 58
 
59 59
 // ContainerExtractToDir extracts the given archive to the specified location
... ...
@@ -68,7 +68,7 @@ func (daemon *Daemon) ContainerExtractToDir(name, path string, noOverwriteDirNon
68 68
 		return err
69 69
 	}
70 70
 
71
-	return container.ExtractToDir(path, noOverwriteDirNonDir, content)
71
+	return daemon.containerExtractToDir(container, path, noOverwriteDirNonDir, content)
72 72
 }
73 73
 
74 74
 // resolvePath resolves the given path in the container to a resource on the
... ...
@@ -131,16 +131,16 @@ func (container *Container) statPath(resolvedPath, absPath string) (stat *types.
131 131
 	}, nil
132 132
 }
133 133
 
134
-// StatPath stats the filesystem resource at the specified path in this
134
+// containerStatPath stats the filesystem resource at the specified path in this
135 135
 // container. Returns stat info about the resource.
136
-func (container *Container) StatPath(path string) (stat *types.ContainerPathStat, err error) {
136
+func (daemon *Daemon) containerStatPath(container *Container, path string) (stat *types.ContainerPathStat, err error) {
137 137
 	container.Lock()
138 138
 	defer container.Unlock()
139 139
 
140
-	if err = container.Mount(); err != nil {
140
+	if err = daemon.Mount(container); err != nil {
141 141
 		return nil, err
142 142
 	}
143
-	defer container.Unmount()
143
+	defer daemon.Unmount(container)
144 144
 
145 145
 	err = container.mountVolumes()
146 146
 	defer container.unmountVolumes(true)
... ...
@@ -156,10 +156,10 @@ func (container *Container) StatPath(path string) (stat *types.ContainerPathStat
156 156
 	return container.statPath(resolvedPath, absPath)
157 157
 }
158 158
 
159
-// ArchivePath creates an archive of the filesystem resource at the specified
159
+// containerArchivePath creates an archive of the filesystem resource at the specified
160 160
 // path in this container. Returns a tar archive of the resource and stat info
161 161
 // about the resource.
162
-func (container *Container) ArchivePath(path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error) {
162
+func (daemon *Daemon) containerArchivePath(container *Container, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error) {
163 163
 	container.Lock()
164 164
 
165 165
 	defer func() {
... ...
@@ -171,7 +171,7 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta
171 171
 		}
172 172
 	}()
173 173
 
174
-	if err = container.Mount(); err != nil {
174
+	if err = daemon.Mount(container); err != nil {
175 175
 		return nil, nil, err
176 176
 	}
177 177
 
... ...
@@ -180,7 +180,7 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta
180 180
 			// unmount any volumes
181 181
 			container.unmountVolumes(true)
182 182
 			// unmount the container's rootfs
183
-			container.Unmount()
183
+			daemon.Unmount(container)
184 184
 		}
185 185
 	}()
186 186
 
... ...
@@ -214,7 +214,7 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta
214 214
 	content = ioutils.NewReadCloserWrapper(data, func() error {
215 215
 		err := data.Close()
216 216
 		container.unmountVolumes(true)
217
-		container.Unmount()
217
+		daemon.Unmount(container)
218 218
 		container.Unlock()
219 219
 		return err
220 220
 	})
... ...
@@ -224,20 +224,20 @@ func (container *Container) ArchivePath(path string) (content io.ReadCloser, sta
224 224
 	return content, stat, nil
225 225
 }
226 226
 
227
-// ExtractToDir extracts the given tar archive to the specified location in the
227
+// containerExtractToDir extracts the given tar archive to the specified location in the
228 228
 // filesystem of this container. The given path must be of a directory in the
229 229
 // container. If it is not, the error will be ErrExtractPointNotDirectory. If
230 230
 // noOverwriteDirNonDir is true then it will be an error if unpacking the
231 231
 // given content would cause an existing directory to be replaced with a non-
232 232
 // directory and vice versa.
233
-func (container *Container) ExtractToDir(path string, noOverwriteDirNonDir bool, content io.Reader) (err error) {
233
+func (daemon *Daemon) containerExtractToDir(container *Container, path string, noOverwriteDirNonDir bool, content io.Reader) (err error) {
234 234
 	container.Lock()
235 235
 	defer container.Unlock()
236 236
 
237
-	if err = container.Mount(); err != nil {
237
+	if err = daemon.Mount(container); err != nil {
238 238
 		return err
239 239
 	}
240
-	defer container.Unmount()
240
+	defer daemon.Unmount(container)
241 241
 
242 242
 	err = container.mountVolumes()
243 243
 	defer container.unmountVolumes(true)
... ...
@@ -225,76 +225,6 @@ func (container *Container) getRootResourcePath(path string) (string, error) {
225 225
 	return symlink.FollowSymlinkInScope(filepath.Join(container.root, cleanPath), container.root)
226 226
 }
227 227
 
228
-// Start prepares the container to run by setting up everything the
229
-// container needs, such as storage and networking, as well as links
230
-// between containers. The container is left waiting for a signal to
231
-// begin running.
232
-func (container *Container) Start() (err error) {
233
-	container.Lock()
234
-	defer container.Unlock()
235
-
236
-	if container.Running {
237
-		return nil
238
-	}
239
-
240
-	if container.removalInProgress || container.Dead {
241
-		return derr.ErrorCodeContainerBeingRemoved
242
-	}
243
-
244
-	// if we encounter an error during start we need to ensure that any other
245
-	// setup has been cleaned up properly
246
-	defer func() {
247
-		if err != nil {
248
-			container.setError(err)
249
-			// if no one else has set it, make sure we don't leave it at zero
250
-			if container.ExitCode == 0 {
251
-				container.ExitCode = 128
252
-			}
253
-			container.toDisk()
254
-			container.cleanup()
255
-			container.logEvent("die")
256
-		}
257
-	}()
258
-
259
-	if err := container.conditionalMountOnStart(); err != nil {
260
-		return err
261
-	}
262
-
263
-	// Make sure NetworkMode has an acceptable value. We do this to ensure
264
-	// backwards API compatibility.
265
-	container.hostConfig = runconfig.SetDefaultNetModeIfBlank(container.hostConfig)
266
-
267
-	if err := container.initializeNetworking(); err != nil {
268
-		return err
269
-	}
270
-	linkedEnv, err := container.setupLinkedContainers()
271
-	if err != nil {
272
-		return err
273
-	}
274
-	if err := container.setupWorkingDirectory(); err != nil {
275
-		return err
276
-	}
277
-	env := container.createDaemonEnvironment(linkedEnv)
278
-	if err := populateCommand(container, env); err != nil {
279
-		return err
280
-	}
281
-
282
-	if !container.hostConfig.IpcMode.IsContainer() && !container.hostConfig.IpcMode.IsHost() {
283
-		if err := container.setupIpcDirs(); err != nil {
284
-			return err
285
-		}
286
-	}
287
-
288
-	mounts, err := container.setupMounts()
289
-	if err != nil {
290
-		return err
291
-	}
292
-	mounts = append(mounts, container.ipcMounts()...)
293
-
294
-	container.command.Mounts = mounts
295
-	return container.waitForStart()
296
-}
297
-
298 228
 // streamConfig.StdinPipe returns a WriteCloser which can be used to feed data
299 229
 // to the standard input of the container's active process.
300 230
 // Container.StdoutPipe and Container.StderrPipe each return a ReadCloser
... ...
@@ -326,7 +256,7 @@ func (container *Container) cleanup() {
326 326
 
327 327
 	container.unmountIpcMounts(detachMounted)
328 328
 
329
-	container.conditionalUnmountOnCleanup()
329
+	container.daemon.conditionalUnmountOnCleanup(container)
330 330
 
331 331
 	for _, eConfig := range container.execCommands.s {
332 332
 		container.daemon.unregisterExecCommand(eConfig)
... ...
@@ -356,11 +286,6 @@ func (container *Container) Resize(h, w int) error {
356 356
 	return nil
357 357
 }
358 358
 
359
-// Mount sets container.basefs
360
-func (container *Container) Mount() error {
361
-	return container.daemon.Mount(container)
362
-}
363
-
364 359
 func (container *Container) changes() ([]archive.Change, error) {
365 360
 	container.Lock()
366 361
 	defer container.Unlock()
... ...
@@ -374,12 +299,6 @@ func (container *Container) getImage() (*image.Image, error) {
374 374
 	return container.daemon.graph.Get(container.ImageID)
375 375
 }
376 376
 
377
-// Unmount asks the daemon to release the layered filesystems that are
378
-// mounted by the container.
379
-func (container *Container) Unmount() error {
380
-	return container.daemon.unmount(container)
381
-}
382
-
383 377
 func (container *Container) hostConfigPath() (string, error) {
384 378
 	return container.getRootResourcePath("hostconfig.json")
385 379
 }
... ...
@@ -401,7 +320,7 @@ func validateID(id string) error {
401 401
 	return nil
402 402
 }
403 403
 
404
-func (container *Container) copy(resource string) (rc io.ReadCloser, err error) {
404
+func (daemon *Daemon) containerCopy(container *Container, resource string) (rc io.ReadCloser, err error) {
405 405
 	container.Lock()
406 406
 
407 407
 	defer func() {
... ...
@@ -413,7 +332,7 @@ func (container *Container) copy(resource string) (rc io.ReadCloser, err error)
413 413
 		}
414 414
 	}()
415 415
 
416
-	if err := container.Mount(); err != nil {
416
+	if err := daemon.Mount(container); err != nil {
417 417
 		return nil, err
418 418
 	}
419 419
 
... ...
@@ -422,7 +341,7 @@ func (container *Container) copy(resource string) (rc io.ReadCloser, err error)
422 422
 			// unmount any volumes
423 423
 			container.unmountVolumes(true)
424 424
 			// unmount the container's rootfs
425
-			container.Unmount()
425
+			daemon.Unmount(container)
426 426
 		}
427 427
 	}()
428 428
 
... ...
@@ -458,11 +377,11 @@ func (container *Container) copy(resource string) (rc io.ReadCloser, err error)
458 458
 	reader := ioutils.NewReadCloserWrapper(archive, func() error {
459 459
 		err := archive.Close()
460 460
 		container.unmountVolumes(true)
461
-		container.Unmount()
461
+		daemon.Unmount(container)
462 462
 		container.Unlock()
463 463
 		return err
464 464
 	})
465
-	container.logEvent("copy")
465
+	daemon.logContainerEvent(container, "copy")
466 466
 	return reader, nil
467 467
 }
468 468
 
... ...
@@ -379,24 +379,23 @@ func mergeDevices(defaultDevices, userDevices []*configs.Device) []*configs.Devi
379 379
 	return append(devs, userDevices...)
380 380
 }
381 381
 
382
-// GetSize returns the real size & virtual size of the container.
383
-func (container *Container) getSize() (int64, int64) {
382
+// getSize returns the real size & virtual size of the container.
383
+func (daemon *Daemon) getSize(container *Container) (int64, int64) {
384 384
 	var (
385 385
 		sizeRw, sizeRootfs int64
386 386
 		err                error
387
-		driver             = container.daemon.driver
388 387
 	)
389 388
 
390
-	if err := container.Mount(); err != nil {
389
+	if err := daemon.Mount(container); err != nil {
391 390
 		logrus.Errorf("Failed to compute size of container rootfs %s: %s", container.ID, err)
392 391
 		return sizeRw, sizeRootfs
393 392
 	}
394
-	defer container.Unmount()
393
+	defer daemon.Unmount(container)
395 394
 
396 395
 	initID := fmt.Sprintf("%s-init", container.ID)
397
-	sizeRw, err = driver.DiffSize(container.ID, initID)
396
+	sizeRw, err = daemon.driver.DiffSize(container.ID, initID)
398 397
 	if err != nil {
399
-		logrus.Errorf("Driver %s couldn't return diff size of container %s: %s", driver, container.ID, err)
398
+		logrus.Errorf("Driver %s couldn't return diff size of container %s: %s", daemon.driver, container.ID, err)
400 399
 		// FIXME: GetSize should return an error. Not changing it now in case
401 400
 		// there is a side-effect.
402 401
 		sizeRw = -1
... ...
@@ -1444,20 +1443,3 @@ func (container *Container) ipcMounts() []execdriver.Mount {
1444 1444
 func detachMounted(path string) error {
1445 1445
 	return syscall.Unmount(path, syscall.MNT_DETACH)
1446 1446
 }
1447
-
1448
-// conditionalMountOnStart is a platform specific helper function during the
1449
-// container start to call mount.
1450
-func (container *Container) conditionalMountOnStart() error {
1451
-	if err := container.Mount(); err != nil {
1452
-		return err
1453
-	}
1454
-	return nil
1455
-}
1456
-
1457
-// conditionalUnmountOnCleanup is a platform specific helper function called
1458
-// during the cleanup of a container to unmount.
1459
-func (container *Container) conditionalUnmountOnCleanup() {
1460
-	if err := container.Unmount(); err != nil {
1461
-		logrus.Errorf("%v: Failed to umount filesystem: %v", container.ID, err)
1462
-	}
1463
-}
... ...
@@ -5,7 +5,6 @@ package daemon
5 5
 import (
6 6
 	"strings"
7 7
 
8
-	"github.com/Sirupsen/logrus"
9 8
 	"github.com/docker/docker/daemon/execdriver"
10 9
 	derr "github.com/docker/docker/errors"
11 10
 	"github.com/docker/docker/volume"
... ...
@@ -143,8 +142,8 @@ func populateCommand(c *Container, env []string) error {
143 143
 	return nil
144 144
 }
145 145
 
146
-// GetSize returns real size & virtual size
147
-func (container *Container) getSize() (int64, int64) {
146
+// getSize returns real size & virtual size
147
+func (daemon *Daemon) getSize(container *Container) (int64, int64) {
148 148
 	// TODO Windows
149 149
 	return 0, 0
150 150
 }
... ...
@@ -191,26 +190,3 @@ func (container *Container) ipcMounts() []execdriver.Mount {
191 191
 func getDefaultRouteMtu() (int, error) {
192 192
 	return -1, errSystemNotSupported
193 193
 }
194
-
195
-// conditionalMountOnStart is a platform specific helper function during the
196
-// container start to call mount.
197
-func (container *Container) conditionalMountOnStart() error {
198
-	// We do not mount if a Hyper-V container
199
-	if !container.hostConfig.Isolation.IsHyperV() {
200
-		if err := container.Mount(); err != nil {
201
-			return err
202
-		}
203
-	}
204
-	return nil
205
-}
206
-
207
-// conditionalUnmountOnCleanup is a platform specific helper function called
208
-// during the cleanup of a container to unmount.
209
-func (container *Container) conditionalUnmountOnCleanup() {
210
-	// We do not unmount if a Hyper-V container
211
-	if !container.hostConfig.Isolation.IsHyperV() {
212
-		if err := container.Unmount(); err != nil {
213
-			logrus.Errorf("%v: Failed to umount filesystem: %v", container.ID, err)
214
-		}
215
-	}
216
-}
... ...
@@ -114,10 +114,10 @@ func (daemon *Daemon) create(params *ContainerCreateConfig) (retC *Container, re
114 114
 			}
115 115
 		}
116 116
 	}()
117
-	if err := container.Mount(); err != nil {
117
+	if err := daemon.Mount(container); err != nil {
118 118
 		return nil, err
119 119
 	}
120
-	defer container.Unmount()
120
+	defer daemon.Unmount(container)
121 121
 
122 122
 	if err := createContainerPlatformSpecificSettings(container, params.Config, params.HostConfig, img); err != nil {
123 123
 		return nil, err
... ...
@@ -127,7 +127,7 @@ func (daemon *Daemon) create(params *ContainerCreateConfig) (retC *Container, re
127 127
 		logrus.Errorf("Error saving new container to disk: %v", err)
128 128
 		return nil, err
129 129
 	}
130
-	container.logEvent("create")
130
+	daemon.logContainerEvent(container, "create")
131 131
 	return container, nil
132 132
 }
133 133
 
... ...
@@ -234,7 +234,7 @@ func (daemon *Daemon) Register(container *Container) error {
234 234
 
235 235
 		container.unmountIpcMounts(mount.Unmount)
236 236
 
237
-		if err := container.Unmount(); err != nil {
237
+		if err := daemon.Unmount(container); err != nil {
238 238
 			logrus.Debugf("unmount error %s", err)
239 239
 		}
240 240
 		if err := container.toDiskLocking(); err != nil {
... ...
@@ -349,7 +349,7 @@ func (daemon *Daemon) restore() error {
349 349
 			if daemon.configStore.AutoRestart && container.shouldRestart() {
350 350
 				logrus.Debugf("Starting container %s", container.ID)
351 351
 
352
-				if err := container.Start(); err != nil {
352
+				if err := daemon.containerStart(container); err != nil {
353 353
 					logrus.Errorf("Failed to start container %s: %s", container.ID, err)
354 354
 				}
355 355
 			}
... ...
@@ -947,7 +947,8 @@ func (daemon *Daemon) Mount(container *Container) error {
947 947
 	return nil
948 948
 }
949 949
 
950
-func (daemon *Daemon) unmount(container *Container) error {
950
+// Unmount unsets the container base filesystem
951
+func (daemon *Daemon) Unmount(container *Container) error {
951 952
 	return daemon.driver.Put(container.ID)
952 953
 }
953 954
 
... ...
@@ -610,6 +610,20 @@ func (daemon *Daemon) newBaseContainer(id string) *Container {
610 610
 	}
611 611
 }
612 612
 
613
+// conditionalMountOnStart is a platform specific helper function during the
614
+// container start to call mount.
615
+func (daemon *Daemon) conditionalMountOnStart(container *Container) error {
616
+	return daemon.Mount(container)
617
+}
618
+
619
+// conditionalUnmountOnCleanup is a platform specific helper function called
620
+// during the cleanup of a container to unmount.
621
+func (daemon *Daemon) conditionalUnmountOnCleanup(container *Container) {
622
+	if err := daemon.Unmount(container); err != nil {
623
+		logrus.Errorf("%v: Failed to umount filesystem: %v", container.ID, err)
624
+	}
625
+}
626
+
613 627
 // getDefaultRouteMtu returns the MTU for the default route's interface.
614 628
 func getDefaultRouteMtu() (int, error) {
615 629
 	routes, err := netlink.RouteList(nil, 0)
... ...
@@ -154,3 +154,26 @@ func (daemon *Daemon) newBaseContainer(id string) *Container {
154 154
 func (daemon *Daemon) cleanupMounts() error {
155 155
 	return nil
156 156
 }
157
+
158
+// conditionalMountOnStart is a platform specific helper function during the
159
+// container start to call mount.
160
+func (daemon *Daemon) conditionalMountOnStart(container *Container) error {
161
+	// We do not mount if a Hyper-V container
162
+	if !container.hostConfig.Isolation.IsHyperV() {
163
+		if err := daemon.Mount(container); err != nil {
164
+			return err
165
+		}
166
+	}
167
+	return nil
168
+}
169
+
170
+// conditionalUnmountOnCleanup is a platform specific helper function called
171
+// during the cleanup of a container to unmount.
172
+func (daemon *Daemon) conditionalUnmountOnCleanup(container *Container) {
173
+	// We do not unmount if a Hyper-V container
174
+	if !container.hostConfig.Isolation.IsHyperV() {
175
+		if err := daemon.Unmount(container); err != nil {
176
+			logrus.Errorf("%v: Failed to umount filesystem: %v", container.ID, err)
177
+		}
178
+	}
179
+}
... ...
@@ -96,7 +96,8 @@ func (d Docker) Create(cfg *runconfig.Config, hostCfg *runconfig.HostConfig) (*d
96 96
 	if err != nil {
97 97
 		return nil, ccr.Warnings, err
98 98
 	}
99
-	return container, ccr.Warnings, container.Mount()
99
+
100
+	return container, ccr.Warnings, d.Mount(container)
100 101
 }
101 102
 
102 103
 // Remove removes a container specified by `id`.
... ...
@@ -210,6 +211,21 @@ func (d Docker) Kill(container *daemon.Container) error {
210 210
 	return d.Daemon.Kill(container)
211 211
 }
212 212
 
213
+// Mount mounts the root filesystem for the container.
214
+func (d Docker) Mount(c *daemon.Container) error {
215
+	return d.Daemon.Mount(c)
216
+}
217
+
218
+// Unmount unmounts the root filesystem for the container.
219
+func (d Docker) Unmount(c *daemon.Container) error {
220
+	return d.Daemon.Unmount(c)
221
+}
222
+
223
+// Start starts a container
224
+func (d Docker) Start(c *daemon.Container) error {
225
+	return d.Daemon.Start(c)
226
+}
227
+
213 228
 // Following is specific to builder contexts
214 229
 
215 230
 // DetectContextFromRemoteURL returns a context and in certain cases the name of the dockerfile to be used
... ...
@@ -41,12 +41,12 @@ func (daemon *Daemon) containerExport(container *Container) (archive.Archive, er
41 41
 		GIDMaps:     gidMaps,
42 42
 	})
43 43
 	if err != nil {
44
-		daemon.unmount(container)
44
+		daemon.Unmount(container)
45 45
 		return nil, err
46 46
 	}
47 47
 	arch := ioutils.NewReadCloserWrapper(archive, func() error {
48 48
 		err := archive.Close()
49
-		container.Unmount()
49
+		daemon.Unmount(container)
50 50
 		return err
51 51
 	})
52 52
 	daemon.logContainerEvent(container, "export")
... ...
@@ -140,7 +140,7 @@ func (daemon *Daemon) getInspectData(container *Container, size bool) (*types.Co
140 140
 		sizeRootFs int64
141 141
 	)
142 142
 	if size {
143
-		sizeRw, sizeRootFs = container.getSize()
143
+		sizeRw, sizeRootFs = daemon.getSize(container)
144 144
 		contJSONBase.SizeRw = &sizeRw
145 145
 		contJSONBase.SizeRootFs = &sizeRootFs
146 146
 	}
... ...
@@ -369,7 +369,7 @@ func (daemon *Daemon) transformContainer(container *Container, ctx *listContext)
369 369
 	}
370 370
 
371 371
 	if ctx.Size {
372
-		sizeRw, sizeRootFs := container.getSize()
372
+		sizeRw, sizeRootFs := daemon.getSize(container)
373 373
 		newC.SizeRw = sizeRw
374 374
 		newC.SizeRootFs = sizeRootFs
375 375
 	}
... ...
@@ -29,15 +29,15 @@ func (daemon *Daemon) containerRestart(container *Container, seconds int) error
29 29
 	// Avoid unnecessarily unmounting and then directly mounting
30 30
 	// the container when the container stops and then starts
31 31
 	// again
32
-	if err := container.Mount(); err == nil {
33
-		defer container.Unmount()
32
+	if err := daemon.Mount(container); err == nil {
33
+		defer daemon.Unmount(container)
34 34
 	}
35 35
 
36 36
 	if err := daemon.containerStop(container, seconds); err != nil {
37 37
 		return err
38 38
 	}
39 39
 
40
-	if err := container.Start(); err != nil {
40
+	if err := daemon.containerStart(container); err != nil {
41 41
 		return err
42 42
 	}
43 43
 
... ...
@@ -44,9 +44,84 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConf
44 44
 		return err
45 45
 	}
46 46
 
47
-	if err := container.Start(); err != nil {
47
+	if err := daemon.containerStart(container); err != nil {
48 48
 		return derr.ErrorCodeCantStart.WithArgs(name, utils.GetErrorMessage(err))
49 49
 	}
50 50
 
51 51
 	return nil
52 52
 }
53
+
54
+// Start starts a container
55
+func (daemon *Daemon) Start(container *Container) error {
56
+	return daemon.containerStart(container)
57
+}
58
+
59
+// containerStart prepares the container to run by setting up everything the
60
+// container needs, such as storage and networking, as well as links
61
+// between containers. The container is left waiting for a signal to
62
+// begin running.
63
+func (daemon *Daemon) containerStart(container *Container) (err error) {
64
+	container.Lock()
65
+	defer container.Unlock()
66
+
67
+	if container.Running {
68
+		return nil
69
+	}
70
+
71
+	if container.removalInProgress || container.Dead {
72
+		return derr.ErrorCodeContainerBeingRemoved
73
+	}
74
+
75
+	// if we encounter an error during start we need to ensure that any other
76
+	// setup has been cleaned up properly
77
+	defer func() {
78
+		if err != nil {
79
+			container.setError(err)
80
+			// if no one else has set it, make sure we don't leave it at zero
81
+			if container.ExitCode == 0 {
82
+				container.ExitCode = 128
83
+			}
84
+			container.toDisk()
85
+			container.cleanup()
86
+			daemon.logContainerEvent(container, "die")
87
+		}
88
+	}()
89
+
90
+	if err := daemon.conditionalMountOnStart(container); err != nil {
91
+		return err
92
+	}
93
+
94
+	// Make sure NetworkMode has an acceptable value. We do this to ensure
95
+	// backwards API compatibility.
96
+	container.hostConfig = runconfig.SetDefaultNetModeIfBlank(container.hostConfig)
97
+
98
+	if err := container.initializeNetworking(); err != nil {
99
+		return err
100
+	}
101
+	linkedEnv, err := container.setupLinkedContainers()
102
+	if err != nil {
103
+		return err
104
+	}
105
+	if err := container.setupWorkingDirectory(); err != nil {
106
+		return err
107
+	}
108
+	env := container.createDaemonEnvironment(linkedEnv)
109
+	if err := populateCommand(container, env); err != nil {
110
+		return err
111
+	}
112
+
113
+	if !container.hostConfig.IpcMode.IsContainer() && !container.hostConfig.IpcMode.IsHost() {
114
+		if err := container.setupIpcDirs(); err != nil {
115
+			return err
116
+		}
117
+	}
118
+
119
+	mounts, err := container.setupMounts()
120
+	if err != nil {
121
+		return err
122
+	}
123
+	mounts = append(mounts, container.ipcMounts()...)
124
+
125
+	container.command.Mounts = mounts
126
+	return container.waitForStart()
127
+}