Преглед изворни кода

Refactor RWLayer to use referenced object instead of string

RWLayer will now have more operations and be protected through a referenced type rather than always looked up by string in the layer store.
Separates creation of RWLayer (write capture layer) from mounting of the layer.
This allows mount labels to be applied after creation and allowing RWLayer objects to have the same lifespan as a container without performance regressions from requiring mount.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
Derek McGowan пре 9 година
родитељ
комит
d04fa49a0d

+ 1 - 1
daemon/commit.go

@@ -145,7 +145,7 @@ func (daemon *Daemon) exportContainerRw(container *container.Container) (archive
 	}
 	}
 	return ioutils.NewReadCloserWrapper(archive, func() error {
 	return ioutils.NewReadCloserWrapper(archive, func() error {
 			archive.Close()
 			archive.Close()
-			return daemon.layerStore.Unmount(container.ID)
+			return container.RWLayer.Unmount()
 		}),
 		}),
 		nil
 		nil
 }
 }

+ 1 - 1
daemon/container_operations_windows.go

@@ -98,7 +98,7 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
 		}
 		}
 	}
 	}
 
 
-	m, err := daemon.layerStore.Metadata(c.ID)
+	m, err := c.RWLayer.Metadata()
 	if err != nil {
 	if err != nil {
 		return derr.ErrorCodeGetLayerMetadata.WithArgs(err)
 		return derr.ErrorCodeGetLayerMetadata.WithArgs(err)
 	}
 	}

+ 24 - 0
daemon/create.go

@@ -7,6 +7,7 @@ import (
 	"github.com/docker/docker/container"
 	"github.com/docker/docker/container"
 	derr "github.com/docker/docker/errors"
 	derr "github.com/docker/docker/errors"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/image"
+	"github.com/docker/docker/layer"
 	"github.com/docker/docker/pkg/idtools"
 	"github.com/docker/docker/pkg/idtools"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/volume"
 	"github.com/docker/docker/volume"
@@ -95,6 +96,11 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig) (*container.Con
 		}
 		}
 	}()
 	}()
 
 
+	// Set RWLayer for container after mount labels have been set
+	if err := daemon.setRWLayer(container); err != nil {
+		return nil, err
+	}
+
 	if err := daemon.createContainerPlatformSpecificSettings(container, params.Config, params.HostConfig, img); err != nil {
 	if err := daemon.createContainerPlatformSpecificSettings(container, params.Config, params.HostConfig, img); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -126,6 +132,24 @@ func (daemon *Daemon) generateSecurityOpt(ipcMode containertypes.IpcMode, pidMod
 	return nil, nil
 	return nil, nil
 }
 }
 
 
+func (daemon *Daemon) setRWLayer(container *container.Container) error {
+	var layerID layer.ChainID
+	if container.ImageID != "" {
+		img, err := daemon.imageStore.Get(container.ImageID)
+		if err != nil {
+			return err
+		}
+		layerID = img.RootFS.ChainID()
+	}
+	rwLayer, err := daemon.layerStore.CreateRWLayer(container.ID, layerID, container.MountLabel, daemon.setupInitLayer)
+	if err != nil {
+		return err
+	}
+	container.RWLayer = rwLayer
+
+	return nil
+}
+
 // VolumeCreate creates a volume with the specified name, driver, and opts
 // VolumeCreate creates a volume with the specified name, driver, and opts
 // This is called directly from the remote API
 // This is called directly from the remote API
 func (daemon *Daemon) VolumeCreate(name, driverName string, opts map[string]string) (*types.Volume, error) {
 func (daemon *Daemon) VolumeCreate(name, driverName string, opts map[string]string) (*types.Volume, error) {

+ 10 - 16
daemon/daemon.go

@@ -323,6 +323,13 @@ func (daemon *Daemon) restore() error {
 			continue
 			continue
 		}
 		}
 
 
+		rwlayer, err := daemon.layerStore.GetRWLayer(container.ID)
+		if err != nil {
+			logrus.Errorf("Failed to load container mount %v: %v", id, err)
+			continue
+		}
+		container.RWLayer = rwlayer
+
 		// Ignore the container if it does not support the current driver being used by the graph
 		// Ignore the container if it does not support the current driver being used by the graph
 		if (container.Driver == "" && currentDriver == "aufs") || container.Driver == currentDriver {
 		if (container.Driver == "" && currentDriver == "aufs") || container.Driver == currentDriver {
 			logrus.Debugf("Loaded container %v", container.ID)
 			logrus.Debugf("Loaded container %v", container.ID)
@@ -961,19 +968,7 @@ func (daemon *Daemon) Shutdown() error {
 // Mount sets container.BaseFS
 // Mount sets container.BaseFS
 // (is it not set coming in? why is it unset?)
 // (is it not set coming in? why is it unset?)
 func (daemon *Daemon) Mount(container *container.Container) error {
 func (daemon *Daemon) Mount(container *container.Container) error {
-	var layerID layer.ChainID
-	if container.ImageID != "" {
-		img, err := daemon.imageStore.Get(container.ImageID)
-		if err != nil {
-			return err
-		}
-		layerID = img.RootFS.ChainID()
-	}
-	rwlayer, err := daemon.layerStore.Mount(container.ID, layerID, container.GetMountLabel(), daemon.setupInitLayer)
-	if err != nil {
-		return err
-	}
-	dir, err := rwlayer.Path()
+	dir, err := container.RWLayer.Mount(container.GetMountLabel())
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -990,13 +985,12 @@ func (daemon *Daemon) Mount(container *container.Container) error {
 		}
 		}
 	}
 	}
 	container.BaseFS = dir // TODO: combine these fields
 	container.BaseFS = dir // TODO: combine these fields
-	container.RWLayer = rwlayer
 	return nil
 	return nil
 }
 }
 
 
 // Unmount unsets the container base filesystem
 // Unmount unsets the container base filesystem
 func (daemon *Daemon) Unmount(container *container.Container) {
 func (daemon *Daemon) Unmount(container *container.Container) {
-	if err := daemon.layerStore.Unmount(container.ID); err != nil {
+	if err := container.RWLayer.Unmount(); err != nil {
 		logrus.Errorf("Error unmounting container %s: %s", container.ID, err)
 		logrus.Errorf("Error unmounting container %s: %s", container.ID, err)
 	}
 	}
 }
 }
@@ -1029,7 +1023,7 @@ func (daemon *Daemon) unsubscribeToContainerStats(c *container.Container, ch cha
 }
 }
 
 
 func (daemon *Daemon) changes(container *container.Container) ([]archive.Change, error) {
 func (daemon *Daemon) changes(container *container.Container) ([]archive.Change, error) {
-	return daemon.layerStore.Changes(container.ID)
+	return container.RWLayer.Changes()
 }
 }
 
 
 // TagImage creates a tag in the repository reponame, pointing to the image named
 // TagImage creates a tag in the repository reponame, pointing to the image named

+ 1 - 1
daemon/delete.go

@@ -130,7 +130,7 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo
 		return derr.ErrorCodeRmFS.WithArgs(container.ID, err)
 		return derr.ErrorCodeRmFS.WithArgs(container.ID, err)
 	}
 	}
 
 
-	metadata, err := daemon.layerStore.DeleteMount(container.ID)
+	metadata, err := daemon.layerStore.ReleaseRWLayer(container.RWLayer)
 	layer.LogReleaseMetadata(metadata)
 	layer.LogReleaseMetadata(metadata)
 	if err != nil && err != layer.ErrMountDoesNotExist {
 	if err != nil && err != layer.ErrMountDoesNotExist {
 		return derr.ErrorCodeRmDriverFS.WithArgs(daemon.driver, container.ID, err)
 		return derr.ErrorCodeRmDriverFS.WithArgs(daemon.driver, container.ID, err)

+ 1 - 1
daemon/inspect.go

@@ -163,7 +163,7 @@ func (daemon *Daemon) getInspectData(container *container.Container, size bool)
 
 
 	contJSONBase.GraphDriver.Name = container.Driver
 	contJSONBase.GraphDriver.Name = container.Driver
 
 
-	graphDriverData, err := daemon.layerStore.Metadata(container.ID)
+	graphDriverData, err := container.RWLayer.Metadata()
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}

+ 4 - 12
distribution/xfer/download_test.go

@@ -12,7 +12,6 @@ import (
 	"github.com/docker/distribution/digest"
 	"github.com/docker/distribution/digest"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/layer"
 	"github.com/docker/docker/layer"
-	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/progress"
 	"github.com/docker/docker/pkg/progress"
 	"golang.org/x/net/context"
 	"golang.org/x/net/context"
 )
 )
@@ -115,25 +114,18 @@ func (ls *mockLayerStore) Get(chainID layer.ChainID) (layer.Layer, error) {
 func (ls *mockLayerStore) Release(l layer.Layer) ([]layer.Metadata, error) {
 func (ls *mockLayerStore) Release(l layer.Layer) ([]layer.Metadata, error) {
 	return []layer.Metadata{}, nil
 	return []layer.Metadata{}, nil
 }
 }
-
-func (ls *mockLayerStore) Mount(id string, parent layer.ChainID, label string, init layer.MountInit) (layer.RWLayer, error) {
+func (ls *mockLayerStore) CreateRWLayer(string, layer.ChainID, string, layer.MountInit) (layer.RWLayer, error) {
 	return nil, errors.New("not implemented")
 	return nil, errors.New("not implemented")
 }
 }
 
 
-func (ls *mockLayerStore) Unmount(id string) error {
-	return errors.New("not implemented")
-}
-
-func (ls *mockLayerStore) DeleteMount(id string) ([]layer.Metadata, error) {
+func (ls *mockLayerStore) GetRWLayer(string) (layer.RWLayer, error) {
 	return nil, errors.New("not implemented")
 	return nil, errors.New("not implemented")
-}
 
 
-func (ls *mockLayerStore) Changes(id string) ([]archive.Change, error) {
-	return nil, errors.New("not implemented")
 }
 }
 
 
-func (ls *mockLayerStore) Metadata(id string) (map[string]string, error) {
+func (ls *mockLayerStore) ReleaseRWLayer(layer.RWLayer) ([]layer.Metadata, error) {
 	return nil, errors.New("not implemented")
 	return nil, errors.New("not implemented")
+
 }
 }
 
 
 type mockDownloadDescriptor struct {
 type mockDownloadDescriptor struct {

+ 26 - 8
layer/layer.go

@@ -31,6 +31,11 @@ var (
 	// attempted on a mount layer which does not exist.
 	// attempted on a mount layer which does not exist.
 	ErrMountDoesNotExist = errors.New("mount does not exist")
 	ErrMountDoesNotExist = errors.New("mount does not exist")
 
 
+	// ErrMountNameConflict is used when a mount is attempted
+	// to be created but there is already a mount with the name
+	// used for creation.
+	ErrMountNameConflict = errors.New("mount already exists with name")
+
 	// ErrActiveMount is used when an operation on a
 	// ErrActiveMount is used when an operation on a
 	// mount is attempted but the layer is still
 	// mount is attempted but the layer is still
 	// mounted and the operation cannot be performed.
 	// mounted and the operation cannot be performed.
@@ -103,18 +108,33 @@ type Layer interface {
 type RWLayer interface {
 type RWLayer interface {
 	TarStreamer
 	TarStreamer
 
 
-	// Path returns the filesystem path to the writable
-	// layer.
-	Path() (string, error)
+	// Name of mounted layer
+	Name() string
 
 
 	// Parent returns the layer which the writable
 	// Parent returns the layer which the writable
 	// layer was created from.
 	// layer was created from.
 	Parent() Layer
 	Parent() Layer
 
 
+	// Mount mounts the RWLayer and returns the filesystem path
+	// the to the writable layer.
+	Mount(mountLabel string) (string, error)
+
+	// Unmount unmounts the RWLayer. This should be called
+	// for every mount. If there are multiple mount calls
+	// this operation will only decrement the internal mount counter.
+	Unmount() error
+
 	// Size represents the size of the writable layer
 	// Size represents the size of the writable layer
 	// as calculated by the total size of the files
 	// as calculated by the total size of the files
 	// changed in the mutable layer.
 	// changed in the mutable layer.
 	Size() (int64, error)
 	Size() (int64, error)
+
+	// Changes returns the set of changes for the mutable layer
+	// from the base layer.
+	Changes() ([]archive.Change, error)
+
+	// Metadata returns the low level metadata for the mutable layer
+	Metadata() (map[string]string, error)
 }
 }
 
 
 // Metadata holds information about a
 // Metadata holds information about a
@@ -147,11 +167,9 @@ type Store interface {
 	Get(ChainID) (Layer, error)
 	Get(ChainID) (Layer, error)
 	Release(Layer) ([]Metadata, error)
 	Release(Layer) ([]Metadata, error)
 
 
-	Mount(id string, parent ChainID, label string, init MountInit) (RWLayer, error)
-	Unmount(id string) error
-	DeleteMount(id string) ([]Metadata, error)
-	Changes(id string) ([]archive.Change, error)
-	Metadata(id string) (map[string]string, error)
+	CreateRWLayer(id string, parent ChainID, mountLabel string, initFunc MountInit) (RWLayer, error)
+	GetRWLayer(id string) (RWLayer, error)
+	ReleaseRWLayer(RWLayer) ([]Metadata, error)
 }
 }
 
 
 // MetadataTransaction represents functions for setting layer metadata
 // MetadataTransaction represents functions for setting layer metadata

+ 69 - 120
layer/layer_store.go

@@ -5,7 +5,6 @@ import (
 	"fmt"
 	"fmt"
 	"io"
 	"io"
 	"io/ioutil"
 	"io/ioutil"
-	"runtime"
 	"sync"
 	"sync"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
@@ -144,6 +143,7 @@ func (ls *layerStore) loadMount(mount string) error {
 		mountID:    mountID,
 		mountID:    mountID,
 		initID:     initID,
 		initID:     initID,
 		layerStore: ls,
 		layerStore: ls,
+		references: map[RWLayer]*referencedRWLayer{},
 	}
 	}
 
 
 	if parent != "" {
 	if parent != "" {
@@ -382,78 +382,15 @@ func (ls *layerStore) Release(l Layer) ([]Metadata, error) {
 	return ls.releaseLayer(layer)
 	return ls.releaseLayer(layer)
 }
 }
 
 
-func (ls *layerStore) mount(m *mountedLayer, mountLabel string) error {
-	dir, err := ls.driver.Get(m.mountID, mountLabel)
-	if err != nil {
-		return err
-	}
-	m.path = dir
-	m.activityCount++
-
-	return nil
-}
-
-func (ls *layerStore) saveMount(mount *mountedLayer) error {
-	if err := ls.store.SetMountID(mount.name, mount.mountID); err != nil {
-		return err
-	}
-
-	if mount.initID != "" {
-		if err := ls.store.SetInitID(mount.name, mount.initID); err != nil {
-			return err
-		}
-	}
-
-	if mount.parent != nil {
-		if err := ls.store.SetMountParent(mount.name, mount.parent.chainID); err != nil {
-			return err
-		}
-	}
-
-	ls.mounts[mount.name] = mount
-
-	return nil
-}
-
-func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc MountInit) (string, error) {
-	// Use "<graph-id>-init" to maintain compatibility with graph drivers
-	// which are expecting this layer with this special name. If all
-	// graph drivers can be updated to not rely on knowing about this layer
-	// then the initID should be randomly generated.
-	initID := fmt.Sprintf("%s-init", graphID)
-
-	if err := ls.driver.Create(initID, parent, mountLabel); err != nil {
-		return "", err
-	}
-	p, err := ls.driver.Get(initID, "")
-	if err != nil {
-		return "", err
-	}
-
-	if err := initFunc(p); err != nil {
-		ls.driver.Put(initID)
-		return "", err
-	}
-
-	if err := ls.driver.Put(initID); err != nil {
-		return "", err
-	}
-
-	return initID, nil
-}
-
-func (ls *layerStore) Mount(name string, parent ChainID, mountLabel string, initFunc MountInit) (l RWLayer, err error) {
+func (ls *layerStore) CreateRWLayer(name string, parent ChainID, mountLabel string, initFunc MountInit) (RWLayer, error) {
 	ls.mountL.Lock()
 	ls.mountL.Lock()
 	defer ls.mountL.Unlock()
 	defer ls.mountL.Unlock()
 	m, ok := ls.mounts[name]
 	m, ok := ls.mounts[name]
 	if ok {
 	if ok {
-		// Check if has path
-		if err := ls.mount(m, mountLabel); err != nil {
-			return nil, err
-		}
-		return m, nil
+		return nil, ErrMountNameConflict
 	}
 	}
 
 
+	var err error
 	var pid string
 	var pid string
 	var p *roLayer
 	var p *roLayer
 	if string(parent) != "" {
 	if string(parent) != "" {
@@ -473,17 +410,12 @@ func (ls *layerStore) Mount(name string, parent ChainID, mountLabel string, init
 		}()
 		}()
 	}
 	}
 
 
-	mountID := name
-	if runtime.GOOS != "windows" {
-		// windows has issues if container ID doesn't match mount ID
-		mountID = stringid.GenerateRandomID()
-	}
-
 	m = &mountedLayer{
 	m = &mountedLayer{
 		name:       name,
 		name:       name,
 		parent:     p,
 		parent:     p,
-		mountID:    mountID,
+		mountID:    ls.mountID(name),
 		layerStore: ls,
 		layerStore: ls,
+		references: map[RWLayer]*referencedRWLayer{},
 	}
 	}
 
 
 	if initFunc != nil {
 	if initFunc != nil {
@@ -502,44 +434,35 @@ func (ls *layerStore) Mount(name string, parent ChainID, mountLabel string, init
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	if err = ls.mount(m, mountLabel); err != nil {
-		return nil, err
-	}
-
-	return m, nil
+	return m.getReference(), nil
 }
 }
 
 
-func (ls *layerStore) Unmount(name string) error {
+func (ls *layerStore) GetRWLayer(id string) (RWLayer, error) {
 	ls.mountL.Lock()
 	ls.mountL.Lock()
 	defer ls.mountL.Unlock()
 	defer ls.mountL.Unlock()
-
-	m := ls.mounts[name]
-	if m == nil {
-		return ErrMountDoesNotExist
-	}
-
-	m.activityCount--
-
-	if err := ls.driver.Put(m.mountID); err != nil {
-		return err
+	mount, ok := ls.mounts[id]
+	if !ok {
+		return nil, ErrMountDoesNotExist
 	}
 	}
 
 
-	return nil
+	return mount.getReference(), nil
 }
 }
 
 
-func (ls *layerStore) DeleteMount(name string) ([]Metadata, error) {
+func (ls *layerStore) ReleaseRWLayer(l RWLayer) ([]Metadata, error) {
 	ls.mountL.Lock()
 	ls.mountL.Lock()
 	defer ls.mountL.Unlock()
 	defer ls.mountL.Unlock()
-
-	m := ls.mounts[name]
-	if m == nil {
-		return nil, ErrMountDoesNotExist
+	m, ok := ls.mounts[l.Name()]
+	if !ok {
+		return []Metadata{}, nil
 	}
 	}
-	if m.activityCount > 0 {
-		return nil, ErrActiveMount
+
+	if err := m.deleteReference(l); err != nil {
+		return nil, err
 	}
 	}
 
 
-	delete(ls.mounts, name)
+	if m.hasReferences() {
+		return []Metadata{}, nil
+	}
 
 
 	if err := ls.driver.Remove(m.mountID); err != nil {
 	if err := ls.driver.Remove(m.mountID); err != nil {
 		logrus.Errorf("Error removing mounted layer %s: %s", m.name, err)
 		logrus.Errorf("Error removing mounted layer %s: %s", m.name, err)
@@ -558,6 +481,8 @@ func (ls *layerStore) DeleteMount(name string) ([]Metadata, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
+	delete(ls.mounts, m.Name())
+
 	ls.layerL.Lock()
 	ls.layerL.Lock()
 	defer ls.layerL.Unlock()
 	defer ls.layerL.Unlock()
 	if m.parent != nil {
 	if m.parent != nil {
@@ -567,18 +492,53 @@ func (ls *layerStore) DeleteMount(name string) ([]Metadata, error) {
 	return []Metadata{}, nil
 	return []Metadata{}, nil
 }
 }
 
 
-func (ls *layerStore) Changes(name string) ([]archive.Change, error) {
-	ls.mountL.Lock()
-	m := ls.mounts[name]
-	ls.mountL.Unlock()
-	if m == nil {
-		return nil, ErrMountDoesNotExist
+func (ls *layerStore) saveMount(mount *mountedLayer) error {
+	if err := ls.store.SetMountID(mount.name, mount.mountID); err != nil {
+		return err
 	}
 	}
-	pid := m.initID
-	if pid == "" && m.parent != nil {
-		pid = m.parent.cacheID
+
+	if mount.initID != "" {
+		if err := ls.store.SetInitID(mount.name, mount.initID); err != nil {
+			return err
+		}
 	}
 	}
-	return ls.driver.Changes(m.mountID, pid)
+
+	if mount.parent != nil {
+		if err := ls.store.SetMountParent(mount.name, mount.parent.chainID); err != nil {
+			return err
+		}
+	}
+
+	ls.mounts[mount.name] = mount
+
+	return nil
+}
+
+func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc MountInit) (string, error) {
+	// Use "<graph-id>-init" to maintain compatibility with graph drivers
+	// which are expecting this layer with this special name. If all
+	// graph drivers can be updated to not rely on knowing about this layer
+	// then the initID should be randomly generated.
+	initID := fmt.Sprintf("%s-init", graphID)
+
+	if err := ls.driver.Create(initID, parent, mountLabel); err != nil {
+		return "", err
+	}
+	p, err := ls.driver.Get(initID, "")
+	if err != nil {
+		return "", err
+	}
+
+	if err := initFunc(p); err != nil {
+		ls.driver.Put(initID)
+		return "", err
+	}
+
+	if err := ls.driver.Put(initID); err != nil {
+		return "", err
+	}
+
+	return initID, nil
 }
 }
 
 
 func (ls *layerStore) assembleTar(graphID string, metadata io.ReadCloser, size *int64) (io.ReadCloser, error) {
 func (ls *layerStore) assembleTar(graphID string, metadata io.ReadCloser, size *int64) (io.ReadCloser, error) {
@@ -621,17 +581,6 @@ func (ls *layerStore) assembleTar(graphID string, metadata io.ReadCloser, size *
 	return pR, nil
 	return pR, nil
 }
 }
 
 
-// Metadata returns the low level metadata from the mount with the given name
-func (ls *layerStore) Metadata(name string) (map[string]string, error) {
-	ls.mountL.Lock()
-	m := ls.mounts[name]
-	ls.mountL.Unlock()
-	if m == nil {
-		return nil, ErrMountDoesNotExist
-	}
-	return ls.driver.GetMetadata(m.mountID)
-}
-
 type naiveDiffPathDriver struct {
 type naiveDiffPathDriver struct {
 	graphdriver.Driver
 	graphdriver.Driver
 }
 }

+ 64 - 18
layer/layer_test.go

@@ -82,12 +82,12 @@ type layerInit func(root string) error
 
 
 func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
 func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
 	containerID := stringid.GenerateRandomID()
 	containerID := stringid.GenerateRandomID()
-	mount, err := ls.Mount(containerID, parent, "", nil)
+	mount, err := ls.CreateRWLayer(containerID, parent, "", nil)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	path, err := mount.Path()
+	path, err := mount.Mount("")
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -107,11 +107,11 @@ func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	if err := ls.Unmount(containerID); err != nil {
+	if err := mount.Unmount(); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	if _, err := ls.DeleteMount(containerID); err != nil {
+	if _, err := ls.ReleaseRWLayer(mount); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
@@ -171,6 +171,13 @@ func getCachedLayer(l Layer) *roLayer {
 	return l.(*roLayer)
 	return l.(*roLayer)
 }
 }
 
 
+func getMountLayer(l RWLayer) *mountedLayer {
+	if rl, ok := l.(*referencedRWLayer); ok {
+		return rl.mountedLayer
+	}
+	return l.(*mountedLayer)
+}
+
 func createMetadata(layers ...Layer) []Metadata {
 func createMetadata(layers ...Layer) []Metadata {
 	metadata := make([]Metadata, len(layers))
 	metadata := make([]Metadata, len(layers))
 	for i := range layers {
 	for i := range layers {
@@ -270,12 +277,12 @@ func TestMountAndRegister(t *testing.T) {
 	size, _ := layer.Size()
 	size, _ := layer.Size()
 	t.Logf("Layer size: %d", size)
 	t.Logf("Layer size: %d", size)
 
 
-	mount2, err := ls.Mount("new-test-mount", layer.ChainID(), "", nil)
+	mount2, err := ls.CreateRWLayer("new-test-mount", layer.ChainID(), "", nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	path2, err := mount2.Path()
+	path2, err := mount2.Mount("")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -289,11 +296,11 @@ func TestMountAndRegister(t *testing.T) {
 		t.Fatalf("Wrong file data, expected %q, got %q", expected, string(b))
 		t.Fatalf("Wrong file data, expected %q, got %q", expected, string(b))
 	}
 	}
 
 
-	if err := ls.Unmount("new-test-mount"); err != nil {
+	if err := mount2.Unmount(); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	if _, err := ls.DeleteMount("new-test-mount"); err != nil {
+	if _, err := ls.ReleaseRWLayer(mount2); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 }
 }
@@ -370,12 +377,12 @@ func TestStoreRestore(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	m, err := ls.Mount("some-mount_name", layer3.ChainID(), "", nil)
+	m, err := ls.CreateRWLayer("some-mount_name", layer3.ChainID(), "", nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	path, err := m.Path()
+	path, err := m.Mount("")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -383,11 +390,14 @@ func TestStoreRestore(t *testing.T) {
 	if err := ioutil.WriteFile(filepath.Join(path, "testfile.txt"), []byte("nothing here"), 0644); err != nil {
 	if err := ioutil.WriteFile(filepath.Join(path, "testfile.txt"), []byte("nothing here"), 0644); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
+	assertActivityCount(t, m, 1)
 
 
-	if err := ls.Unmount("some-mount_name"); err != nil {
+	if err := m.Unmount(); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
+	assertActivityCount(t, m, 0)
+
 	ls2, err := NewStore(ls.(*layerStore).store, ls.(*layerStore).driver)
 	ls2, err := NewStore(ls.(*layerStore).store, ls.(*layerStore).driver)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -400,18 +410,39 @@ func TestStoreRestore(t *testing.T) {
 
 
 	assertLayerEqual(t, layer3b, layer3)
 	assertLayerEqual(t, layer3b, layer3)
 
 
-	// Mount again with same name, should already be loaded
-	m2, err := ls2.Mount("some-mount_name", layer3b.ChainID(), "", nil)
-	if err != nil {
+	// Create again with same name, should return error
+	if _, err := ls2.CreateRWLayer("some-mount_name", layer3b.ChainID(), "", nil); err == nil {
+		t.Fatal("Expected error creating mount with same name")
+	} else if err != ErrMountNameConflict {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	path2, err := m2.Path()
+	m2, err := ls2.GetRWLayer("some-mount_name")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	b, err := ioutil.ReadFile(filepath.Join(path2, "testfile.txt"))
+	if mountPath, err := m2.Mount(""); err != nil {
+		t.Fatal(err)
+	} else if path != mountPath {
+		t.Fatalf("Unexpected path %s, expected %s", mountPath, path)
+	}
+
+	assertActivityCount(t, m2, 1)
+
+	if mountPath, err := m2.Mount(""); err != nil {
+		t.Fatal(err)
+	} else if path != mountPath {
+		t.Fatalf("Unexpected path %s, expected %s", mountPath, path)
+	}
+	assertActivityCount(t, m2, 2)
+	if err := m2.Unmount(); err != nil {
+		t.Fatal(err)
+	}
+
+	assertActivityCount(t, m2, 1)
+
+	b, err := ioutil.ReadFile(filepath.Join(path, "testfile.txt"))
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -419,11 +450,19 @@ func TestStoreRestore(t *testing.T) {
 		t.Fatalf("Unexpected content %q, expected %q", string(b), expected)
 		t.Fatalf("Unexpected content %q, expected %q", string(b), expected)
 	}
 	}
 
 
-	if err := ls2.Unmount("some-mount_name"); err != nil {
+	if err := m2.Unmount(); err != nil {
+		t.Fatal(err)
+	}
+
+	assertActivityCount(t, m2, 0)
+
+	if metadata, err := ls2.ReleaseRWLayer(m2); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
+	} else if len(metadata) != 0 {
+		t.Fatalf("Unexpectedly deleted layers: %#v", metadata)
 	}
 	}
 
 
-	if metadata, err := ls2.DeleteMount("some-mount_name"); err != nil {
+	if metadata, err := ls2.ReleaseRWLayer(m2); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	} else if len(metadata) != 0 {
 	} else if len(metadata) != 0 {
 		t.Fatalf("Unexpectedly deleted layers: %#v", metadata)
 		t.Fatalf("Unexpectedly deleted layers: %#v", metadata)
@@ -627,6 +666,13 @@ func assertReferences(t *testing.T, references ...Layer) {
 	}
 	}
 }
 }
 
 
+func assertActivityCount(t *testing.T, l RWLayer, expected int) {
+	rl := l.(*referencedRWLayer)
+	if rl.activityCount != expected {
+		t.Fatalf("Unexpected activity count %d, expected %d", rl.activityCount, expected)
+	}
+}
+
 func TestRegisterExistingLayer(t *testing.T) {
 func TestRegisterExistingLayer(t *testing.T) {
 	ls, cleanup := newTestStore(t)
 	ls, cleanup := newTestStore(t)
 	defer cleanup()
 	defer cleanup()

+ 9 - 0
layer/layer_unix.go

@@ -0,0 +1,9 @@
+// +build linux freebsd darwin
+
+package layer
+
+import "github.com/docker/docker/pkg/stringid"
+
+func (ls *layerStore) mountID(name string) string {
+	return stringid.GenerateRandomID()
+}

+ 5 - 0
layer/layer_windows.go

@@ -89,3 +89,8 @@ func (ls *layerStore) RegisterDiffID(graphID string, size int64) (Layer, error)
 
 
 	return layer.getReference(), nil
 	return layer.getReference(), nil
 }
 }
+
+func (ls *layerStore) mountID(name string) string {
+	// windows has issues if container ID doesn't match mount ID
+	return name
+}

+ 12 - 13
layer/migration.go

@@ -14,30 +14,33 @@ import (
 	"github.com/vbatts/tar-split/tar/storage"
 	"github.com/vbatts/tar-split/tar/storage"
 )
 )
 
 
-func (ls *layerStore) MountByGraphID(name string, graphID string, parent ChainID) (l RWLayer, err error) {
+// CreateRWLayerByGraphID creates a RWLayer in the layer store using
+// the provided name with the given graphID. To get the RWLayer
+// after migration the layer may be retrieved by the given name.
+func (ls *layerStore) CreateRWLayerByGraphID(name string, graphID string, parent ChainID) (err error) {
 	ls.mountL.Lock()
 	ls.mountL.Lock()
 	defer ls.mountL.Unlock()
 	defer ls.mountL.Unlock()
 	m, ok := ls.mounts[name]
 	m, ok := ls.mounts[name]
 	if ok {
 	if ok {
 		if m.parent.chainID != parent {
 		if m.parent.chainID != parent {
-			return nil, errors.New("name conflict, mismatched parent")
+			return errors.New("name conflict, mismatched parent")
 		}
 		}
 		if m.mountID != graphID {
 		if m.mountID != graphID {
-			return nil, errors.New("mount already exists")
+			return errors.New("mount already exists")
 		}
 		}
 
 
-		return m, nil
+		return nil
 	}
 	}
 
 
 	if !ls.driver.Exists(graphID) {
 	if !ls.driver.Exists(graphID) {
-		return nil, errors.New("graph ID does not exist")
+		return errors.New("graph ID does not exist")
 	}
 	}
 
 
 	var p *roLayer
 	var p *roLayer
 	if string(parent) != "" {
 	if string(parent) != "" {
 		p = ls.get(parent)
 		p = ls.get(parent)
 		if p == nil {
 		if p == nil {
-			return nil, ErrLayerDoesNotExist
+			return ErrLayerDoesNotExist
 		}
 		}
 
 
 		// Release parent chain if error
 		// Release parent chain if error
@@ -57,6 +60,7 @@ func (ls *layerStore) MountByGraphID(name string, graphID string, parent ChainID
 		parent:     p,
 		parent:     p,
 		mountID:    graphID,
 		mountID:    graphID,
 		layerStore: ls,
 		layerStore: ls,
+		references: map[RWLayer]*referencedRWLayer{},
 	}
 	}
 
 
 	// Check for existing init layer
 	// Check for existing init layer
@@ -66,15 +70,10 @@ func (ls *layerStore) MountByGraphID(name string, graphID string, parent ChainID
 	}
 	}
 
 
 	if err = ls.saveMount(m); err != nil {
 	if err = ls.saveMount(m); err != nil {
-		return nil, err
-	}
-
-	// TODO: provide a mount label
-	if err = ls.mount(m, ""); err != nil {
-		return nil, err
+		return err
 	}
 	}
 
 
-	return m, nil
+	return nil
 }
 }
 
 
 func (ls *layerStore) migrateLayer(tx MetadataTransaction, tarDataFile string, layer *roLayer) error {
 func (ls *layerStore) migrateLayer(tx MetadataTransaction, tarDataFile string, layer *roLayer) error {

+ 45 - 13
layer/migration_test.go

@@ -303,12 +303,20 @@ func TestMountMigration(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	rwLayer1, err := ls.(*layerStore).MountByGraphID("migration-mount", containerID, layer1.ChainID())
+	if err := ls.(*layerStore).CreateRWLayerByGraphID("migration-mount", containerID, layer1.ChainID()); err != nil {
+		t.Fatal(err)
+	}
+
+	rwLayer1, err := ls.GetRWLayer("migration-mount")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	changes, err := ls.Changes("migration-mount")
+	if _, err := rwLayer1.Mount(""); err != nil {
+		t.Fatal(err)
+	}
+
+	changes, err := rwLayer1.Changes()
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -341,39 +349,63 @@ func TestMountMigration(t *testing.T) {
 		Kind: archive.ChangeAdd,
 		Kind: archive.ChangeAdd,
 	})
 	})
 
 
-	if expectedCount := 1; rwLayer1.(*mountedLayer).activityCount != expectedCount {
-		t.Fatalf("Wrong activity count %d, expected %d", rwLayer1.(*mountedLayer).activityCount, expectedCount)
+	assertActivityCount(t, rwLayer1, 1)
+
+	if _, err := ls.CreateRWLayer("migration-mount", layer1.ChainID(), "", nil); err == nil {
+		t.Fatal("Expected error creating mount with same name")
+	} else if err != ErrMountNameConflict {
+		t.Fatal(err)
 	}
 	}
 
 
-	rwLayer2, err := ls.Mount("migration-mount", layer1.ChainID(), "", nil)
+	rwLayer2, err := ls.GetRWLayer("migration-mount")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	if rwLayer1 != rwLayer2 {
-		t.Fatalf("Wrong rwlayer %v, expected %v", rwLayer2, rwLayer1)
+	if getMountLayer(rwLayer1) != getMountLayer(rwLayer2) {
+		t.Fatal("Expected same layer from get with same name as from migrate")
+	}
+
+	if _, err := rwLayer2.Mount(""); err != nil {
+		t.Fatal(err)
 	}
 	}
 
 
-	if expectedCount := 2; rwLayer2.(*mountedLayer).activityCount != expectedCount {
-		t.Fatalf("Wrong activity count %d, expected %d", rwLayer2.(*mountedLayer).activityCount, expectedCount)
+	assertActivityCount(t, rwLayer2, 1)
+	assertActivityCount(t, rwLayer1, 1)
+
+	if _, err := rwLayer2.Mount(""); err != nil {
+		t.Fatal(err)
 	}
 	}
 
 
+	assertActivityCount(t, rwLayer2, 2)
+	assertActivityCount(t, rwLayer1, 1)
+
 	if metadata, err := ls.Release(layer1); err != nil {
 	if metadata, err := ls.Release(layer1); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	} else if len(metadata) > 0 {
 	} else if len(metadata) > 0 {
 		t.Fatalf("Expected no layers to be deleted, deleted %#v", metadata)
 		t.Fatalf("Expected no layers to be deleted, deleted %#v", metadata)
 	}
 	}
 
 
-	if err := ls.Unmount("migration-mount"); err != nil {
+	if err := rwLayer1.Unmount(); err != nil {
+		t.Fatal(err)
+	}
+	assertActivityCount(t, rwLayer2, 2)
+	assertActivityCount(t, rwLayer1, 0)
+
+	if _, err := ls.ReleaseRWLayer(rwLayer1); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := rwLayer2.Unmount(); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	if _, err := ls.DeleteMount("migration-mount"); err == nil {
+	if _, err := ls.ReleaseRWLayer(rwLayer2); err == nil {
 		t.Fatal("Expected error deleting active mount")
 		t.Fatal("Expected error deleting active mount")
 	}
 	}
-	if err := ls.Unmount("migration-mount"); err != nil {
+	if err := rwLayer2.Unmount(); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	metadata, err := ls.DeleteMount("migration-mount")
+	metadata, err := ls.ReleaseRWLayer(rwLayer2)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}

+ 7 - 7
layer/mount_test.go

@@ -27,12 +27,12 @@ func TestMountInit(t *testing.T) {
 		return initfile.ApplyFile(root)
 		return initfile.ApplyFile(root)
 	}
 	}
 
 
-	m, err := ls.Mount("fun-mount", layer.ChainID(), "", mountInit)
+	m, err := ls.CreateRWLayer("fun-mount", layer.ChainID(), "", mountInit)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	path, err := m.Path()
+	path, err := m.Mount("")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -80,12 +80,12 @@ func TestMountSize(t *testing.T) {
 		return newTestFile("file-init", contentInit, 0777).ApplyFile(root)
 		return newTestFile("file-init", contentInit, 0777).ApplyFile(root)
 	}
 	}
 
 
-	m, err := ls.Mount("mount-size", layer.ChainID(), "", mountInit)
+	m, err := ls.CreateRWLayer("mount-size", layer.ChainID(), "", mountInit)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	path, err := m.Path()
+	path, err := m.Mount("")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -125,12 +125,12 @@ func TestMountChanges(t *testing.T) {
 		return initfile.ApplyFile(root)
 		return initfile.ApplyFile(root)
 	}
 	}
 
 
-	m, err := ls.Mount("mount-changes", layer.ChainID(), "", mountInit)
+	m, err := ls.CreateRWLayer("mount-changes", layer.ChainID(), "", mountInit)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	path, err := m.Path()
+	path, err := m.Mount("")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -155,7 +155,7 @@ func TestMountChanges(t *testing.T) {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
 
 
-	changes, err := ls.Changes("mount-changes")
+	changes, err := m.Changes()
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}

+ 105 - 13
layer/mounted_layer.go

@@ -1,15 +1,20 @@
 package layer
 package layer
 
 
-import "io"
+import (
+	"io"
+	"sync"
+
+	"github.com/docker/docker/pkg/archive"
+)
 
 
 type mountedLayer struct {
 type mountedLayer struct {
-	name          string
-	mountID       string
-	initID        string
-	parent        *roLayer
-	path          string
-	layerStore    *layerStore
-	activityCount int
+	name       string
+	mountID    string
+	initID     string
+	parent     *roLayer
+	layerStore *layerStore
+
+	references map[RWLayer]*referencedRWLayer
 }
 }
 
 
 func (ml *mountedLayer) cacheParent() string {
 func (ml *mountedLayer) cacheParent() string {
@@ -30,11 +35,8 @@ func (ml *mountedLayer) TarStream() (io.ReadCloser, error) {
 	return archiver, nil
 	return archiver, nil
 }
 }
 
 
-func (ml *mountedLayer) Path() (string, error) {
-	if ml.path == "" {
-		return "", ErrNotMounted
-	}
-	return ml.path, nil
+func (ml *mountedLayer) Name() string {
+	return ml.name
 }
 }
 
 
 func (ml *mountedLayer) Parent() Layer {
 func (ml *mountedLayer) Parent() Layer {
@@ -47,6 +49,96 @@ func (ml *mountedLayer) Parent() Layer {
 	return nil
 	return nil
 }
 }
 
 
+func (ml *mountedLayer) Mount(mountLabel string) (string, error) {
+	return ml.layerStore.driver.Get(ml.mountID, mountLabel)
+}
+
+func (ml *mountedLayer) Unmount() error {
+	return ml.layerStore.driver.Put(ml.mountID)
+}
+
 func (ml *mountedLayer) Size() (int64, error) {
 func (ml *mountedLayer) Size() (int64, error) {
 	return ml.layerStore.driver.DiffSize(ml.mountID, ml.cacheParent())
 	return ml.layerStore.driver.DiffSize(ml.mountID, ml.cacheParent())
 }
 }
+
+func (ml *mountedLayer) Changes() ([]archive.Change, error) {
+	return ml.layerStore.driver.Changes(ml.mountID, ml.cacheParent())
+}
+
+func (ml *mountedLayer) Metadata() (map[string]string, error) {
+	return ml.layerStore.driver.GetMetadata(ml.mountID)
+}
+
+func (ml *mountedLayer) getReference() RWLayer {
+	ref := &referencedRWLayer{
+		mountedLayer: ml,
+	}
+	ml.references[ref] = ref
+
+	return ref
+}
+
+func (ml *mountedLayer) hasReferences() bool {
+	return len(ml.references) > 0
+}
+
+func (ml *mountedLayer) deleteReference(ref RWLayer) error {
+	rl, ok := ml.references[ref]
+	if !ok {
+		return ErrLayerNotRetained
+	}
+
+	if err := rl.release(); err != nil {
+		return err
+	}
+	delete(ml.references, ref)
+
+	return nil
+}
+
+type referencedRWLayer struct {
+	*mountedLayer
+
+	activityL     sync.Mutex
+	activityCount int
+}
+
+func (rl *referencedRWLayer) release() error {
+	rl.activityL.Lock()
+	defer rl.activityL.Unlock()
+
+	if rl.activityCount > 0 {
+		return ErrActiveMount
+	}
+
+	rl.activityCount = -1
+
+	return nil
+}
+
+func (rl *referencedRWLayer) Mount(mountLabel string) (string, error) {
+	rl.activityL.Lock()
+	defer rl.activityL.Unlock()
+
+	if rl.activityCount == -1 {
+		return "", ErrLayerNotRetained
+	}
+
+	rl.activityCount++
+	return rl.mountedLayer.Mount(mountLabel)
+}
+
+func (rl *referencedRWLayer) Unmount() error {
+	rl.activityL.Lock()
+	defer rl.activityL.Unlock()
+
+	if rl.activityCount == 0 {
+		return ErrNotMounted
+	}
+	if rl.activityCount == -1 {
+		return ErrLayerNotRetained
+	}
+	rl.activityCount--
+
+	return rl.mountedLayer.Unmount()
+}

+ 2 - 9
migrate/v1/migratev1.go

@@ -24,8 +24,7 @@ type graphIDRegistrar interface {
 }
 }
 
 
 type graphIDMounter interface {
 type graphIDMounter interface {
-	MountByGraphID(string, string, layer.ChainID) (layer.RWLayer, error)
-	Unmount(string) error
+	CreateRWLayerByGraphID(string, string, layer.ChainID) error
 }
 }
 
 
 const (
 const (
@@ -172,13 +171,7 @@ func migrateContainers(root string, ls graphIDMounter, is image.Store, imageMapp
 			return err
 			return err
 		}
 		}
 
 
-		_, err = ls.MountByGraphID(id, id, img.RootFS.ChainID())
-		if err != nil {
-			return err
-		}
-
-		err = ls.Unmount(id)
-		if err != nil {
+		if err := ls.CreateRWLayerByGraphID(id, id, img.RootFS.ChainID()); err != nil {
 			return err
 			return err
 		}
 		}
 
 

+ 2 - 3
migrate/v1/migratev1_test.go

@@ -338,10 +338,9 @@ type mockMounter struct {
 	count  int
 	count  int
 }
 }
 
 
-func (r *mockMounter) MountByGraphID(name string, graphID string, parent layer.ChainID) (layer.RWLayer, error) {
+func (r *mockMounter) CreateRWLayerByGraphID(name string, graphID string, parent layer.ChainID) error {
 	r.mounts = append(r.mounts, mountInfo{name, graphID, string(parent)})
 	r.mounts = append(r.mounts, mountInfo{name, graphID, string(parent)})
-	r.count++
-	return nil, nil
+	return nil
 }
 }
 func (r *mockMounter) Unmount(string) error {
 func (r *mockMounter) Unmount(string) error {
 	r.count--
 	r.count--