Skip to content

Commit a1d7186

Browse files
committed
erofs-differ: support EROFS native image layers
If the layer media type is expected as an EROFS native layer: - `application/vnd.erofs.image.layer`, or - have the suffix `.image.layer.erofs` Copy the content as the layer blob. Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
1 parent 060ceed commit a1d7186

File tree

1 file changed

+41
-2
lines changed

1 file changed

+41
-2
lines changed

plugins/diff/erofs/differ_linux.go

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ import (
2222
"encoding/base64"
2323
"fmt"
2424
"io"
25+
"os"
2526
"path"
2627
"path/filepath"
28+
"strings"
2729
"time"
2830

2931
"github.com/containerd/containerd/v2/core/content"
@@ -62,6 +64,27 @@ func NewErofsDiffer(store content.Store, mkfsExtraOpts []string) differ {
6264
}
6365
}
6466

67+
// A valid EROFS native layer media type should be either:
68+
// - `application/vnd.erofs.image.layer`, or
69+
// - have the suffix `.image.layer.erofs`
70+
//
71+
// Please avoid using any +suffix to list the algorithms used inside EROFS
72+
// blobs, since:
73+
// - Each EROFS layer can use multiple compression algorithms;
74+
// - The suffixes should only indicate the corresponding preprocessor for
75+
// `images.DiffCompression`.
76+
//
77+
// Since `images.DiffCompression` doesn't support arbitrary media types,
78+
// disallow non-empty suffixes for now.
79+
func isErofsMediaType(mt string) bool {
80+
mediaType, ext, ok := strings.Cut(mt, "+")
81+
if !ok || ext != "" {
82+
return false
83+
}
84+
return mediaType == "application/vnd.erofs.image.layer" ||
85+
strings.HasSuffix(mediaType, ".image.layer.erofs")
86+
}
87+
6588
func writeDiff(ctx context.Context, w io.Writer, lower []mount.Mount, upperRoot string) error {
6689
var opts []archive.ChangeWriterOpt
6790

@@ -223,7 +246,10 @@ func (s erofsDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []
223246
}
224247
}()
225248

226-
if _, err := images.DiffCompression(ctx, desc.MediaType); err != nil {
249+
native := false
250+
if isErofsMediaType(desc.MediaType) {
251+
native = true
252+
} else if _, err := images.DiffCompression(ctx, desc.MediaType); err != nil {
227253
return emptyDesc, fmt.Errorf("currently unsupported media type: %s", desc.MediaType)
228254
}
229255

@@ -245,6 +271,20 @@ func (s erofsDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []
245271
}
246272
defer ra.Close()
247273

274+
layerBlobPath := path.Join(layer, "layer.erofs")
275+
if native {
276+
// TODO: prefer to use hardlink as an optimization here
277+
f, err := os.Create(layerBlobPath)
278+
if err != nil {
279+
return emptyDesc, err
280+
}
281+
_, err = io.Copy(f, content.NewReader(ra))
282+
if err != nil {
283+
return emptyDesc, err
284+
}
285+
return desc, nil
286+
}
287+
248288
processor := diff.NewProcessorChain(desc.MediaType, content.NewReader(ra))
249289
for {
250290
if processor, err = diff.GetProcessor(ctx, processor, config.ProcessorPayloads); err != nil {
@@ -261,7 +301,6 @@ func (s erofsDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts []
261301
r: io.TeeReader(processor, digester.Hash()),
262302
}
263303

264-
layerBlobPath := path.Join(layer, "layer.erofs")
265304
err = erofsutils.ConvertTarErofs(ctx, rc, layerBlobPath, s.mkfsExtraOpts)
266305
if err != nil {
267306
return emptyDesc, fmt.Errorf("failed to convert erofs: %w", err)

0 commit comments

Comments
 (0)