mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
511a70583f
Fix unmount issues in the daemon crash and restart lifecycle, w.r.t graph drivers. This change sets a live container RWLayer's activity count to 1, so that the RWLayer is aware of the mount. Note that containerd has experimental support for restore live containers. Added/updated corresponding tests. Signed-off-by: Anusha Ragunathan <anusha@docker.com>
188 lines
3.5 KiB
Go
188 lines
3.5 KiB
Go
package layer
|
|
|
|
import (
|
|
"io"
|
|
"sync"
|
|
|
|
"github.com/docker/docker/pkg/archive"
|
|
)
|
|
|
|
type mountedLayer struct {
|
|
name string
|
|
mountID string
|
|
initID string
|
|
parent *roLayer
|
|
path string
|
|
layerStore *layerStore
|
|
|
|
references map[RWLayer]*referencedRWLayer
|
|
}
|
|
|
|
func (ml *mountedLayer) cacheParent() string {
|
|
if ml.initID != "" {
|
|
return ml.initID
|
|
}
|
|
if ml.parent != nil {
|
|
return ml.parent.cacheID
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (ml *mountedLayer) TarStream() (io.ReadCloser, error) {
|
|
archiver, err := ml.layerStore.driver.Diff(ml.mountID, ml.cacheParent())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return archiver, nil
|
|
}
|
|
|
|
func (ml *mountedLayer) Name() string {
|
|
return ml.name
|
|
}
|
|
|
|
func (ml *mountedLayer) Parent() Layer {
|
|
if ml.parent != nil {
|
|
return ml.parent
|
|
}
|
|
|
|
// Return a nil interface instead of an interface wrapping a nil
|
|
// pointer.
|
|
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) {
|
|
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) incActivityCount(ref RWLayer) error {
|
|
rl, ok := ml.references[ref]
|
|
if !ok {
|
|
return ErrLayerNotRetained
|
|
}
|
|
|
|
if err := rl.acquire(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
func (ml *mountedLayer) retakeReference(r RWLayer) {
|
|
if ref, ok := r.(*referencedRWLayer); ok {
|
|
ref.activityCount = 0
|
|
ml.references[ref] = ref
|
|
}
|
|
}
|
|
|
|
type referencedRWLayer struct {
|
|
*mountedLayer
|
|
|
|
activityL sync.Mutex
|
|
activityCount int
|
|
}
|
|
|
|
func (rl *referencedRWLayer) acquire() error {
|
|
rl.activityL.Lock()
|
|
defer rl.activityL.Unlock()
|
|
|
|
rl.activityCount++
|
|
|
|
return nil
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
if rl.activityCount > 0 {
|
|
rl.activityCount++
|
|
return rl.path, nil
|
|
}
|
|
|
|
m, err := rl.mountedLayer.Mount(mountLabel)
|
|
if err == nil {
|
|
rl.activityCount++
|
|
rl.path = m
|
|
}
|
|
return m, err
|
|
}
|
|
|
|
// Unmount decrements the activity count and unmounts the underlying layer
|
|
// Callers should only call `Unmount` once per call to `Mount`, even on error.
|
|
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--
|
|
if rl.activityCount > 0 {
|
|
return nil
|
|
}
|
|
|
|
return rl.mountedLayer.Unmount()
|
|
}
|