Implement WCOW parentless active snapshots and view snapshots

The WCOW layer support does not support creating sandboxes with no
parent.  Instead, parentless scratch layers must be layed out as a
directory containing only a directory named 'Files', and all data stored
inside 'Files'. At commit-time, this will be converted in-place into a
read-only layer suitable for use as a parent layer.

The WCOW layer support also does not deal with making read-only layers,
i.e. layers that are prepared to be parent layers, visible in a
read-only manner. A bind-mount or junction point cannot be made
read-only, so a view must instead be a small sandbox layer that we can
mount via WCOW, and discard later, to protect the layer against
accidental or deliberate modification.

Signed-off-by: Paul "TBBle" Hampson <Paul.Hampson@Pobox.com>
This commit is contained in:
Paul "TBBle" Hampson
2020-07-23 22:13:08 +10:00
committed by Gabriel Adrian Samfira
parent 988ee8ffef
commit 34b07d3e2d
2 changed files with 94 additions and 43 deletions

View File

@@ -320,10 +320,13 @@ func mountsToLayerAndParents(mounts []mount.Mount) (string, []string, error) {
return "", nil, fmt.Errorf("number of mounts should always be 1 for Windows layers: %w", errdefs.ErrInvalidArgument)
}
mnt := mounts[0]
if mnt.Type != "windows-layer" {
if mnt.Type != "windows-layer" && mnt.Type != "bind" {
// This is a special case error. When this is received the diff service
// will attempt the next differ in the chain which for Windows is the
// lcow differ that we want.
// TODO: Is there any situation where we actually wanted a "bind" mount to
// fall through to the lcow differ?
return "", nil, fmt.Errorf("windowsDiff does not support layer type %s: %w", mnt.Type, errdefs.ErrNotImplemented)
}
@@ -332,6 +335,30 @@ func mountsToLayerAndParents(mounts []mount.Mount) (string, []string, error) {
return "", nil, err
}
isView := false
for _, o := range mnt.Options {
if o == "ro" {
isView = true
break
}
}
if isView {
if mnt.Type == "bind" && len(parentLayerPaths) != 0 {
return "", nil, fmt.Errorf("unexpected bind-mount View with parents: %w", errdefs.ErrInvalidArgument)
} else if mnt.Type == "bind" {
// rootfs.CreateDiff creates a new, empty View to diff against,
// when diffing something with no parent.
// This makes perfect sense for a walking Diff, but for WCOW,
// we have to recognise this as "diff against nothing"
return "", nil, nil
} else if len(parentLayerPaths) == 0 {
return "", nil, fmt.Errorf("unexpected windows-layer View with no parent: %w", errdefs.ErrInvalidArgument)
}
// Ignore the dummy sandbox.
return parentLayerPaths[0], parentLayerPaths[1:], nil
}
return mnt.Source, parentLayerPaths, nil
}
@@ -346,8 +373,16 @@ func mountPairToLayerStack(lower, upper []mount.Mount) ([]string, error) {
return nil, fmt.Errorf("Upper mount invalid: %w", err)
}
lowerLayer, lowerParentLayerPaths, err := mountsToLayerAndParents(lower)
if errdefs.IsNotImplemented(err) {
// Upper was a windows-layer or bind, lower is not. We can't handle that.
return nil, fmt.Errorf("windowsDiff cannot diff a windows-layer against a non-windows-layer: %w", errdefs.ErrInvalidArgument)
} else if err != nil {
return nil, fmt.Errorf("Lower mount invalid: %w", err)
}
// Trivial case, diff-against-nothing
if len(lower) == 0 {
if lowerLayer == "" {
if len(upperParentLayerPaths) != 0 {
return nil, fmt.Errorf("windowsDiff cannot diff a layer with parents against a null layer: %w", errdefs.ErrInvalidArgument)
}
@@ -358,14 +393,6 @@ func mountPairToLayerStack(lower, upper []mount.Mount) ([]string, error) {
return nil, fmt.Errorf("windowsDiff cannot diff a layer with no parents against another layer: %w", errdefs.ErrInvalidArgument)
}
lowerLayer, lowerParentLayerPaths, err := mountsToLayerAndParents(lower)
if errdefs.IsNotImplemented(err) {
// Upper was a windows-layer, lower is not. We can't handle that.
return nil, fmt.Errorf("windowsDiff cannot diff a windows-layer against a non-windows-layer: %w", errdefs.ErrInvalidArgument)
} else if err != nil {
return nil, fmt.Errorf("Lower mount invalid: %w", err)
}
if upperParentLayerPaths[0] != lowerLayer {
return nil, fmt.Errorf("windowsDiff cannot diff a layer against a layer other than its own parent: %w", errdefs.ErrInvalidArgument)
}