From fdbc2695fe00d522c5c1a962f9be2f802bf53943 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 12 Sep 2013 20:30:55 +0200 Subject: [PATCH] devmapper: Move init layer to top rather than bottom The init layer needs to be topmost to make sure certain files are always there (for instance, the ubuntu:12.10 image wrongly has /dev/shm being a symlink to /run/shm, and we need to override that). However, previously the devmapper code implemented the init layer by putting it in the base devmapper device, which meant layers above it could override these files (so that ubuntu:12.10 broke). So, instead we put the base layer in *each* images devmapper device. This is "safe" because we still have the pristine layer data in the layer directory. Also, it means we diff the container against the image with the init layer applied, so it won't show up in diffs/commits. --- devmapper/deviceset_devmapper.go | 62 -------------------------------- image.go | 17 +++++++++ 2 files changed, 17 insertions(+), 62 deletions(-) diff --git a/devmapper/deviceset_devmapper.go b/devmapper/deviceset_devmapper.go index 4fcfac4464..670d7621c4 100644 --- a/devmapper/deviceset_devmapper.go +++ b/devmapper/deviceset_devmapper.go @@ -542,45 +542,6 @@ func (devices *DeviceSetDM) loadMetaData() error { return nil } -func (devices *DeviceSetDM) createBaseLayer(dir string) error { - for pth, typ := range map[string]string{ - "/dev/pts": "dir", - "/dev/shm": "dir", - "/proc": "dir", - "/sys": "dir", - "/.dockerinit": "file", - "/etc/resolv.conf": "file", - "/etc/hosts": "file", - "/etc/hostname": "file", - // "var/run": "dir", - // "var/lock": "dir", - } { - if _, err := os.Stat(path.Join(dir, pth)); err != nil { - if os.IsNotExist(err) { - switch typ { - case "dir": - if err := os.MkdirAll(path.Join(dir, pth), 0755); err != nil { - return err - } - case "file": - if err := os.MkdirAll(path.Join(dir, path.Dir(pth)), 0755); err != nil { - return err - } - - if f, err := os.OpenFile(path.Join(dir, pth), os.O_CREATE, 0755); err != nil { - return err - } else { - f.Close() - } - } - } else { - return err - } - } - } - return nil -} - func (devices *DeviceSetDM) setupBaseImage() error { oldInfo := devices.Devices[""] if oldInfo != nil && oldInfo.Initialized { @@ -622,29 +583,6 @@ func (devices *DeviceSetDM) setupBaseImage() error { return err } - tmpDir := path.Join(devices.loopbackDir(), "basefs") - if err = os.MkdirAll(tmpDir, 0700); err != nil && !os.IsExist(err) { - return err - } - - err = devices.MountDevice("", tmpDir) - if err != nil { - return err - } - - err = devices.createBaseLayer(tmpDir) - if err != nil { - _ = syscall.Unmount(tmpDir, 0) - return err - } - - err = devices.UnmountDevice("", tmpDir) - if err != nil { - return err - } - - _ = os.Remove(tmpDir) - info.Initialized = true err = devices.saveMetadata() diff --git a/image.go b/image.go index da03fb8ff1..1a279654d5 100644 --- a/image.go +++ b/image.go @@ -379,6 +379,23 @@ func (image *Image) ensureImageDevice(devices DeviceSet) error { return err } + // The docker init layer is conceptually above all other layers, so we apply + // it for every image. This is safe because the layer directory is the + // definition of the image, and the device-mapper device is just a cache + // of it instantiated. Diffs/commit compare the container device with the + // image device, which will then *not* pick up the init layer changes as + // part of the container changes + dockerinitLayer, err := image.getDockerInitLayer() + if err != nil { + _ = devices.RemoveDevice(image.ID) + return err + } + err = image.applyLayer(dockerinitLayer, mountDir) + if err != nil { + _ = devices.RemoveDevice(image.ID) + return err + } + err = devices.UnmountDevice(image.ID, mountDir) if err != nil { _ = devices.RemoveDevice(image.ID)