Separate out graphdriver mount and container root
| ... | ... |
@@ -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 |
} |