Skip to content

Commit 3382fb7

Browse files
committed
Tweak mount info for overlayfs in case of parallel unpack
Signed-off-by: Henry Wang <[email protected]>
1 parent 68e128c commit 3382fb7

2 files changed

Lines changed: 115 additions & 0 deletions

File tree

core/unpack/unpacker.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,15 @@ func (u *Unpacker) unpack(
530530
case <-fetchC[i-fetchOffset]:
531531
}
532532

533+
// In case of parallel unpack, the parent snapshot isn't provided to the snapshotter.
534+
// The overlayfs will return bind mounts for all layers, we need to convert them
535+
// to overlay mounts for the applier to perform whiteout conversion correctly.
536+
// TODO: this is a temporary workaround until #13053 lands.
537+
// See: https://github.com/containerd/containerd/issues/13030
538+
if i > 0 && parallel && unpack.SnapshotterKey == "overlayfs" {
539+
mounts = bindToOverlay(mounts)
540+
}
541+
533542
diff, err := a.Apply(ctx, desc, mounts, unpack.ApplyOpts...)
534543
if err != nil {
535544
cleanup.Do(ctx, abort)
@@ -753,3 +762,23 @@ func uniquePart() string {
753762
rand.Read(b[:])
754763
return fmt.Sprintf("%d-%s", t.Nanosecond(), base64.URLEncoding.EncodeToString(b[:]))
755764
}
765+
766+
// TODO: this is a temporary workaround until #13053 lands.
767+
func bindToOverlay(mounts []mount.Mount) []mount.Mount {
768+
if len(mounts) != 1 || mounts[0].Type != "bind" {
769+
return mounts
770+
}
771+
772+
m := mount.Mount{
773+
Type: "overlay",
774+
Source: "overlay",
775+
}
776+
for _, o := range mounts[0].Options {
777+
if o != "rbind" {
778+
m.Options = append(m.Options, o)
779+
}
780+
}
781+
m.Options = append(m.Options, "upperdir="+mounts[0].Source)
782+
783+
return []mount.Mount{m}
784+
}

core/unpack/unpacker_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ package unpack
1919
import (
2020
"crypto/rand"
2121
"fmt"
22+
"reflect"
2223
"testing"
2324

25+
"github.com/containerd/containerd/v2/core/mount"
2426
"github.com/opencontainers/go-digest"
2527
"github.com/opencontainers/image-spec/identity"
2628
)
@@ -91,3 +93,87 @@ func BenchmarkUnpackWithChainIDs(b *testing.B) {
9193
})
9294
}
9395
}
96+
97+
func TestBindToOverlay(t *testing.T) {
98+
testCases := []struct {
99+
name string
100+
mounts []mount.Mount
101+
expect []mount.Mount
102+
}{
103+
{
104+
name: "single bind mount",
105+
mounts: []mount.Mount{
106+
{
107+
Type: "bind",
108+
Source: "/path/to/source",
109+
Options: []string{"ro", "rbind"},
110+
},
111+
},
112+
expect: []mount.Mount{
113+
{
114+
Type: "overlay",
115+
Source: "overlay",
116+
Options: []string{
117+
"ro",
118+
"upperdir=/path/to/source",
119+
},
120+
},
121+
},
122+
},
123+
{
124+
name: "overlay mount",
125+
mounts: []mount.Mount{
126+
{
127+
Type: "overlay",
128+
Source: "overlay",
129+
Options: []string{
130+
"lowerdir=/path/to/lower",
131+
"upperdir=/path/to/upper",
132+
},
133+
},
134+
},
135+
expect: []mount.Mount{
136+
{
137+
Type: "overlay",
138+
Source: "overlay",
139+
Options: []string{
140+
"lowerdir=/path/to/lower",
141+
"upperdir=/path/to/upper",
142+
},
143+
},
144+
},
145+
},
146+
{
147+
name: "multiple mounts",
148+
mounts: []mount.Mount{
149+
{
150+
Type: "bind",
151+
Source: "/path/to/source1",
152+
},
153+
{
154+
Type: "bind",
155+
Source: "/path/to/source2",
156+
},
157+
},
158+
expect: []mount.Mount{
159+
{
160+
Type: "bind",
161+
Source: "/path/to/source1",
162+
},
163+
{
164+
Type: "bind",
165+
Source: "/path/to/source2",
166+
},
167+
},
168+
},
169+
}
170+
171+
for _, tc := range testCases {
172+
t.Run(tc.name, func(t *testing.T) {
173+
result := bindToOverlay(tc.mounts)
174+
if !reflect.DeepEqual(result, tc.expect) {
175+
t.Errorf("unexpected result: got %v, want %v", result, tc.expect)
176+
}
177+
})
178+
}
179+
}

0 commit comments

Comments
 (0)