Browse code

Merge pull request #3841 from alexlarsson/separate-base-fs

Separate out graphdriver mount and container root

Michael Crosby authored on 2014/02/01 04:49:14
Showing 5 changed files
... ...
@@ -328,7 +328,7 @@ func (b *buildFile) checkPathForAddition(orig string) error {
328 328
 func (b *buildFile) addContext(container *Container, orig, dest string) error {
329 329
 	var (
330 330
 		origPath = path.Join(b.contextPath, orig)
331
-		destPath = path.Join(container.RootfsPath(), dest)
331
+		destPath = path.Join(container.BasefsPath(), dest)
332 332
 	)
333 333
 	// Preserve the trailing '/'
334 334
 	if strings.HasSuffix(dest, "/") {
... ...
@@ -34,7 +34,7 @@ var (
34 34
 type Container struct {
35 35
 	sync.Mutex
36 36
 	root   string // Path to the "home" of the container, including metadata.
37
-	rootfs string // Path to the root filesystem of the container.
37
+	basefs string // Path to the graphdriver mountpoint
38 38
 
39 39
 	ID string
40 40
 
... ...
@@ -266,7 +266,7 @@ func (container *Container) Inject(file io.Reader, pth string) error {
266 266
 	defer container.Unmount()
267 267
 
268 268
 	// Return error if path exists
269
-	destPath := path.Join(container.RootfsPath(), pth)
269
+	destPath := path.Join(container.basefs, pth)
270 270
 	if _, err := os.Stat(destPath); err == nil {
271 271
 		// Since err is nil, the path could be stat'd and it exists
272 272
 		return fmt.Errorf("%s exists", pth)
... ...
@@ -278,7 +278,7 @@ func (container *Container) Inject(file io.Reader, pth string) error {
278 278
 	}
279 279
 
280 280
 	// Make sure the directory exists
281
-	if err := os.MkdirAll(path.Join(container.RootfsPath(), path.Dir(pth)), 0755); err != nil {
281
+	if err := os.MkdirAll(path.Join(container.basefs, path.Dir(pth)), 0755); err != nil {
282 282
 		return err
283 283
 	}
284 284
 
... ...
@@ -707,11 +707,9 @@ func (container *Container) Start() (err error) {
707 707
 		return err
708 708
 	}
709 709
 
710
-	root := container.RootfsPath()
711
-
712 710
 	if container.Config.WorkingDir != "" {
713 711
 		container.Config.WorkingDir = path.Clean(container.Config.WorkingDir)
714
-		if err := os.MkdirAll(path.Join(root, container.Config.WorkingDir), 0755); err != nil {
712
+		if err := os.MkdirAll(path.Join(container.basefs, container.Config.WorkingDir), 0755); err != nil {
715 713
 			return nil
716 714
 		}
717 715
 	}
... ...
@@ -721,6 +719,23 @@ func (container *Container) Start() (err error) {
721 721
 		return err
722 722
 	}
723 723
 
724
+	// Setup the root fs as a bind mount of the base fs
725
+	root := container.RootfsPath()
726
+	if err := os.MkdirAll(root, 0755); err != nil && !os.IsExist(err) {
727
+		return nil
728
+	}
729
+
730
+	// Create a bind mount of the base fs as a place where we can add mounts
731
+	// without affecting the ability to access the base fs
732
+	if err := mount.Mount(container.basefs, root, "none", "bind,rw"); err != nil {
733
+		return err
734
+	}
735
+
736
+	// Make sure the root fs is private so the mounts here don't propagate to basefs
737
+	if err := mount.ForceMount(root, root, "none", "private"); err != nil {
738
+		return err
739
+	}
740
+
724 741
 	// Mount docker specific files into the containers root fs
725 742
 	if err := mount.Mount(runtime.sysInitPath, path.Join(root, "/.dockerinit"), "none", "bind,ro"); err != nil {
726 743
 		return err
... ...
@@ -907,8 +922,8 @@ func (container *Container) createVolumes() error {
907 907
 		container.VolumesRW[volPath] = srcRW
908 908
 
909 909
 		// Create the mountpoint
910
-		volPath = path.Join(container.RootfsPath(), volPath)
911
-		rootVolPath, err := utils.FollowSymlinkInScope(volPath, container.RootfsPath())
910
+		volPath = path.Join(container.basefs, volPath)
911
+		rootVolPath, err := utils.FollowSymlinkInScope(volPath, container.basefs)
912 912
 		if err != nil {
913 913
 			return err
914 914
 		}
... ...
@@ -997,7 +1012,7 @@ func (container *Container) applyExternalVolumes() error {
997 997
 				if _, exists := container.Volumes[volPath]; exists {
998 998
 					continue
999 999
 				}
1000
-				if err := os.MkdirAll(path.Join(container.RootfsPath(), volPath), 0755); err != nil {
1000
+				if err := os.MkdirAll(path.Join(container.basefs, volPath), 0755); err != nil {
1001 1001
 					return err
1002 1002
 				}
1003 1003
 				container.Volumes[volPath] = id
... ...
@@ -1264,6 +1279,30 @@ func (container *Container) cleanup() {
1264 1264
 		}
1265 1265
 	}
1266 1266
 
1267
+	var (
1268
+		root   = container.RootfsPath()
1269
+		mounts = []string{
1270
+			root,
1271
+			path.Join(root, "/.dockerinit"),
1272
+			path.Join(root, "/.dockerenv"),
1273
+			path.Join(root, "/etc/resolv.conf"),
1274
+		}
1275
+	)
1276
+
1277
+	if container.HostnamePath != "" && container.HostsPath != "" {
1278
+		mounts = append(mounts, path.Join(root, "/etc/hostname"), path.Join(root, "/etc/hosts"))
1279
+	}
1280
+
1281
+	for r := range container.Volumes {
1282
+		mounts = append(mounts, path.Join(root, r))
1283
+	}
1284
+
1285
+	for i := len(mounts) - 1; i >= 0; i-- {
1286
+		if lastError := mount.Unmount(mounts[i]); lastError != nil {
1287
+			log.Printf("Failed to umount %v: %v", mounts[i], lastError)
1288
+		}
1289
+	}
1290
+
1267 1291
 	if err := container.Unmount(); err != nil {
1268 1292
 		log.Printf("%v: Failed to umount filesystem: %v", container.ID, err)
1269 1293
 	}
... ...
@@ -1367,7 +1406,7 @@ func (container *Container) Export() (archive.Archive, error) {
1367 1367
 		return nil, err
1368 1368
 	}
1369 1369
 
1370
-	archive, err := archive.Tar(container.RootfsPath(), archive.Uncompressed)
1370
+	archive, err := archive.Tar(container.basefs, archive.Uncompressed)
1371 1371
 	if err != nil {
1372 1372
 		return nil, err
1373 1373
 	}
... ...
@@ -1405,32 +1444,6 @@ func (container *Container) GetImage() (*Image, error) {
1405 1405
 }
1406 1406
 
1407 1407
 func (container *Container) Unmount() error {
1408
-	var (
1409
-		err    error
1410
-		root   = container.RootfsPath()
1411
-		mounts = []string{
1412
-			path.Join(root, "/.dockerinit"),
1413
-			path.Join(root, "/.dockerenv"),
1414
-			path.Join(root, "/etc/resolv.conf"),
1415
-		}
1416
-	)
1417
-
1418
-	if container.HostnamePath != "" && container.HostsPath != "" {
1419
-		mounts = append(mounts, path.Join(root, "/etc/hostname"), path.Join(root, "/etc/hosts"))
1420
-	}
1421
-
1422
-	for r := range container.Volumes {
1423
-		mounts = append(mounts, path.Join(root, r))
1424
-	}
1425
-
1426
-	for i := len(mounts) - 1; i >= 0; i-- {
1427
-		if lastError := mount.Unmount(mounts[i]); lastError != nil {
1428
-			err = fmt.Errorf("Failed to umount %v: %v", mounts[i], lastError)
1429
-		}
1430
-	}
1431
-	if err != nil {
1432
-		return err
1433
-	}
1434 1408
 	return container.runtime.Unmount(container)
1435 1409
 }
1436 1410
 
... ...
@@ -1467,8 +1480,15 @@ func (container *Container) EnvConfigPath() (string, error) {
1467 1467
 }
1468 1468
 
1469 1469
 // This method must be exported to be used from the lxc template
1470
+// This directory is only usable when the container is running
1470 1471
 func (container *Container) RootfsPath() string {
1471
-	return container.rootfs
1472
+	return path.Join(container.root, "root")
1473
+}
1474
+
1475
+// This is the stand-alone version of the root fs, without any additional mounts.
1476
+// This directory is usable whenever the container is mounted (and not unmounted)
1477
+func (container *Container) BasefsPath() string {
1478
+	return container.basefs
1472 1479
 }
1473 1480
 
1474 1481
 func validateID(id string) error {
... ...
@@ -1503,14 +1523,14 @@ func (container *Container) GetSize() (int64, int64) {
1503 1503
 	} else {
1504 1504
 		changes, _ := container.Changes()
1505 1505
 		if changes != nil {
1506
-			sizeRw = archive.ChangesSize(container.RootfsPath(), changes)
1506
+			sizeRw = archive.ChangesSize(container.basefs, changes)
1507 1507
 		} else {
1508 1508
 			sizeRw = -1
1509 1509
 		}
1510 1510
 	}
1511 1511
 
1512
-	if _, err = os.Stat(container.RootfsPath()); err != nil {
1513
-		if sizeRootfs, err = utils.TreeSize(container.RootfsPath()); err != nil {
1512
+	if _, err = os.Stat(container.basefs); err != nil {
1513
+		if sizeRootfs, err = utils.TreeSize(container.basefs); err != nil {
1514 1514
 			sizeRootfs = -1
1515 1515
 		}
1516 1516
 	}
... ...
@@ -1522,7 +1542,7 @@ func (container *Container) Copy(resource string) (archive.Archive, error) {
1522 1522
 		return nil, err
1523 1523
 	}
1524 1524
 	var filter []string
1525
-	basePath := path.Join(container.RootfsPath(), resource)
1525
+	basePath := path.Join(container.basefs, resource)
1526 1526
 	stat, err := os.Stat(basePath)
1527 1527
 	if err != nil {
1528 1528
 		container.Unmount()
... ...
@@ -75,7 +75,7 @@ func containerFileExists(eng *engine.Engine, id, dir string, t utils.Fataler) bo
75 75
 		t.Fatal(err)
76 76
 	}
77 77
 	defer c.Unmount()
78
-	if _, err := os.Stat(path.Join(c.RootfsPath(), dir)); err != nil {
78
+	if _, err := os.Stat(path.Join(c.BasefsPath(), dir)); err != nil {
79 79
 		if os.IsNotExist(err) {
80 80
 			return false
81 81
 		}
... ...
@@ -40,6 +40,7 @@ func parseOptions(options string) (int, string) {
40 40
 		"nodiratime":    {false, syscall.MS_NODIRATIME},
41 41
 		"bind":          {false, syscall.MS_BIND},
42 42
 		"rbind":         {false, syscall.MS_BIND | syscall.MS_REC},
43
+		"private":       {false, syscall.MS_PRIVATE},
43 44
 		"relatime":      {false, syscall.MS_RELATIME},
44 45
 		"norelatime":    {true, syscall.MS_RELATIME},
45 46
 		"strictatime":   {false, syscall.MS_STRICTATIME},
... ...
@@ -132,12 +132,12 @@ func (runtime *Runtime) Register(container *Container) error {
132 132
 	}
133 133
 
134 134
 	// Get the root filesystem from the driver
135
-	rootfs, err := runtime.driver.Get(container.ID)
135
+	basefs, err := runtime.driver.Get(container.ID)
136 136
 	if err != nil {
137 137
 		return fmt.Errorf("Error getting container filesystem %s from driver %s: %s", container.ID, runtime.driver, err)
138 138
 	}
139 139
 	defer runtime.driver.Put(container.ID)
140
-	container.rootfs = rootfs
140
+	container.basefs = basefs
141 141
 
142 142
 	container.runtime = runtime
143 143
 
... ...
@@ -765,11 +765,11 @@ func (runtime *Runtime) Mount(container *Container) error {
765 765
 	if err != nil {
766 766
 		return fmt.Errorf("Error getting container %s from driver %s: %s", container.ID, runtime.driver, err)
767 767
 	}
768
-	if container.rootfs == "" {
769
-		container.rootfs = dir
770
-	} else if container.rootfs != dir {
768
+	if container.basefs == "" {
769
+		container.basefs = dir
770
+	} else if container.basefs != dir {
771 771
 		return fmt.Errorf("Error: driver %s is returning inconsistent paths for container %s ('%s' then '%s')",
772
-			runtime.driver, container.ID, container.rootfs, dir)
772
+			runtime.driver, container.ID, container.basefs, dir)
773 773
 	}
774 774
 	return nil
775 775
 }