From 52a92e83f0cc9ff262e4fe2f64e7454ed3959682 Mon Sep 17 00:00:00 2001 From: Aadhar Agarwal Date: Mon, 12 Jan 2026 23:09:34 +0000 Subject: [PATCH 1/2] erofs-differ: use same UUID append style in tar index mode as tar conversion mode Use the same approach for appending UUID arguments in GenerateTarIndexAndAppendTar as done in ConvertTarErofs for consistency between the two modes. Signed-off-by: Aadhar Agarwal --- internal/erofsutils/mount.go | 5 ++++- plugins/diff/erofs/differ.go | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/internal/erofsutils/mount.go b/internal/erofsutils/mount.go index d99e979e2931..35c469904bf1 100644 --- a/internal/erofsutils/mount.go +++ b/internal/erofsutils/mount.go @@ -54,7 +54,7 @@ func ConvertTarErofs(ctx context.Context, r io.Reader, layerPath, uuid string, m // The `--tar=i` option instructs mkfs.erofs to only generate the tar index // for the tar content. The resulting file structure is: // [Tar index][Original tar content] -func GenerateTarIndexAndAppendTar(ctx context.Context, r io.Reader, layerPath string, mkfsExtraOpts []string) error { +func GenerateTarIndexAndAppendTar(ctx context.Context, r io.Reader, layerPath, uuid string, mkfsExtraOpts []string) error { // Create a temporary file for storing the tar content tarFile, err := os.CreateTemp("", "erofs-tar-*") if err != nil { @@ -68,6 +68,9 @@ func GenerateTarIndexAndAppendTar(ctx context.Context, r io.Reader, layerPath st // Generate tar index directly to layerPath using --tar=i option args := append([]string{"--tar=i", "--aufs", "--quiet"}, mkfsExtraOpts...) + if uuid != "" { + args = append(args, []string{"-U", uuid}...) + } args = append(args, layerPath) cmd := exec.CommandContext(ctx, "mkfs.erofs", args...) cmd.Stdin = teeReader diff --git a/plugins/diff/erofs/differ.go b/plugins/diff/erofs/differ.go index b4bccbee5ff7..6ad99b555725 100644 --- a/plugins/diff/erofs/differ.go +++ b/plugins/diff/erofs/differ.go @@ -174,16 +174,17 @@ func (s erofsDiff) Apply(ctx context.Context, desc ocispec.Descriptor, mounts [] } // Choose between tar index or tar conversion mode + // Generate deterministic UUID from layer digest + u := uuid.NewSHA1(uuid.NameSpaceURL, []byte("erofs:blobs/"+desc.Digest)) if s.enableTarIndex { // Use the tar index method: generate tar index and append tar - err = erofsutils.GenerateTarIndexAndAppendTar(ctx, rc, layerBlobPath, s.mkfsExtraOpts) + err = erofsutils.GenerateTarIndexAndAppendTar(ctx, rc, layerBlobPath, u.String(), s.mkfsExtraOpts) if err != nil { return emptyDesc, fmt.Errorf("failed to generate tar index: %w", err) } log.G(ctx).WithField("path", layerBlobPath).Debug("Applied layer using tar index mode") } else { // Use the tar method: fully convert tar to EROFS - u := uuid.NewSHA1(uuid.NameSpaceURL, []byte("erofs:blobs/"+desc.Digest)) err = erofsutils.ConvertTarErofs(ctx, rc, layerBlobPath, u.String(), s.mkfsExtraOpts) if err != nil { return emptyDesc, fmt.Errorf("failed to convert tar to erofs: %w", err) From cf7cb3c35e72531ceae9929b8ad8ea008a01bb8f Mon Sep 17 00:00:00 2001 From: "jinda.ljd" Date: Wed, 21 Jan 2026 19:25:01 +0800 Subject: [PATCH 2/2] erofs: Move immutable file handling before storage.Remove The layer blob immutable flag clearing logic was moved before storage.Remove() call to ensure that immutable files can be properly removed even if subsequent operations fail after storage.Remove(). The previous order had storage.Remove() called first, which meant if any subsequent operations failed, there would be no opportunity to remove the immutable flag on the layer blob files. Signed-off-by: jinda.ljd --- plugins/snapshots/erofs/erofs.go | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/plugins/snapshots/erofs/erofs.go b/plugins/snapshots/erofs/erofs.go index 2ef5553ad165..dfc32a8b1f31 100644 --- a/plugins/snapshots/erofs/erofs.go +++ b/plugins/snapshots/erofs/erofs.go @@ -728,25 +728,31 @@ func (s *snapshotter) Remove(ctx context.Context, key string) (err error) { } }() return s.ms.WithTransaction(ctx, true, func(ctx context.Context) error { - var k snapshots.Kind - - id, k, err = storage.Remove(ctx, key) + id, info, _, err := storage.GetInfo(ctx, key) if err != nil { - return fmt.Errorf("failed to remove snapshot %s: %w", key, err) + if errdefs.IsNotFound(err) { + return nil + } + return fmt.Errorf("failed to get snapshot info: %w", err) } - removals, err = s.getCleanupDirectories(ctx) - if err != nil { - return fmt.Errorf("unable to get directories for removal: %w", err) - } // The layer blob is only persisted for committed snapshots. - if k == snapshots.KindCommitted { + if info.Kind == snapshots.KindCommitted { // Clear IMMUTABLE_FL before removal, since this flag avoids it. err = setImmutable(s.layerBlobPath(id), false) if err != nil && !errdefs.IsNotImplemented(err) { return fmt.Errorf("failed to clear IMMUTABLE_FL: %w", err) } } + _, _, err = storage.Remove(ctx, key) + if err != nil { + return fmt.Errorf("failed to remove snapshot %s: %w", key, err) + } + + removals, err = s.getCleanupDirectories(ctx) + if err != nil { + return fmt.Errorf("unable to get directories for removal: %w", err) + } return nil }) }