Skip to content

Commit bb21824

Browse files
committed
overlay coreos/user-patches: Add a patch for app-containers/containerd
Signed-off-by: Krzesimir Nowak <knowak@microsoft.com>
1 parent 8f61fc2 commit bb21824

File tree

2 files changed

+231
-0
lines changed

2 files changed

+231
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
From 3d509bcd335b15cece69ebfa117681d2715df930 Mon Sep 17 00:00:00 2001
2+
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Poulin?= <jeromepoulin@gmail.com>
3+
Date: Wed, 26 Nov 2025 18:28:26 -0500
4+
Subject: [PATCH 1/2] core/mount/manager: add tests for WithTemporary option
5+
MIME-Version: 1.0
6+
Content-Type: text/plain; charset=UTF-8
7+
Content-Transfer-Encoding: 8bit
8+
9+
Add tests for the WithTemporary mount activation used by `ctr images mount`.
10+
Covers bind mount and overlay scenarios to catch regressions like #12549.
11+
12+
Signed-off-by: Jérôme Poulin <jeromepoulin@gmail.com>
13+
---
14+
core/mount/manager/manager_linux_test.go | 157 ++++++++++++++++++++++-
15+
1 file changed, 156 insertions(+), 1 deletion(-)
16+
17+
diff --git a/core/mount/manager/manager_linux_test.go b/core/mount/manager/manager_linux_test.go
18+
index 06ab38c2b7b0..b62f3fdc8cf4 100644
19+
--- a/core/mount/manager/manager_linux_test.go
20+
+++ b/core/mount/manager/manager_linux_test.go
21+
@@ -314,6 +314,161 @@ func TestLoopbackOverlay(t *testing.T) {
22+
}
23+
}
24+
25+
+// TestTemporaryMountActivation tests the WithTemporary option used by
26+
+// `ctr images mount`. This verifies the bind mount returned in info.System
27+
+// points to a valid, mounted directory.
28+
+func TestTemporaryMountActivation(t *testing.T) {
29+
+ testutil.RequiresRoot(t)
30+
+ ctx := logtest.WithT(context.Background(), t)
31+
+ ctx = namespaces.WithNamespace(ctx, "test")
32+
+ td := t.TempDir()
33+
+ metadb := filepath.Join(td, "mounts.db")
34+
+ targetdir := filepath.Join(td, "m")
35+
+ db, err := bolt.Open(metadb, 0600, nil)
36+
+ require.NoError(t, err)
37+
+ defer db.Close()
38+
+
39+
+ sourcedir := filepath.Join(td, "source")
40+
+ require.NoError(t, os.MkdirAll(sourcedir, 0755))
41+
+
42+
+ a := fstest.Apply(
43+
+ fstest.CreateFile("/testfile.txt", []byte("test content\n"), 0644),
44+
+ fstest.CreateDir("/testdir", 0755),
45+
+ )
46+
+ require.NoError(t, a.Apply(sourcedir))
47+
+
48+
+ mounts := []mount.Mount{
49+
+ {
50+
+ Type: "bind",
51+
+ Source: sourcedir,
52+
+ Options: []string{"rbind", "ro"},
53+
+ },
54+
+ }
55+
+
56+
+ m, err := NewManager(db, targetdir)
57+
+ require.NoError(t, err)
58+
+
59+
+ ainfo, err := m.Activate(ctx, "temp-mount-test", mounts, mount.WithTemporary)
60+
+ require.NoError(t, err)
61+
+ defer func() {
62+
+ assert.NoError(t, m.Deactivate(ctx, "temp-mount-test"))
63+
+ }()
64+
+
65+
+ require.NotEmpty(t, ainfo.System, "Expected system mounts to be returned")
66+
+
67+
+ require.Len(t, ainfo.System, 1, "Expected exactly one system mount")
68+
+ systemMount := ainfo.System[0]
69+
+ assert.Equal(t, "bind", systemMount.Type, "Expected bind mount type")
70+
+
71+
+ sourceInfo, err := os.Stat(systemMount.Source)
72+
+ require.NoError(t, err, "Bind mount source %q should exist", systemMount.Source)
73+
+ assert.True(t, sourceInfo.IsDir(), "Bind mount source should be a directory")
74+
+
75+
+ testFile := filepath.Join(systemMount.Source, "testfile.txt")
76+
+ content, err := os.ReadFile(testFile)
77+
+ require.NoError(t, err, "Should be able to read test file from bind mount source")
78+
+ assert.Equal(t, "test content\n", string(content), "Test file content should match")
79+
+
80+
+ targetMount := filepath.Join(td, "target")
81+
+ require.NoError(t, os.MkdirAll(targetMount, 0755))
82+
+
83+
+ err = mount.All(ainfo.System, targetMount)
84+
+ require.NoError(t, err, "Should be able to mount system mounts to target")
85+
+ defer testutil.Unmount(t, targetMount)
86+
+
87+
+ targetTestFile := filepath.Join(targetMount, "testfile.txt")
88+
+ targetContent, err := os.ReadFile(targetTestFile)
89+
+ require.NoError(t, err, "Should be able to read test file from target mount")
90+
+ assert.Equal(t, "test content\n", string(targetContent), "Target test file content should match")
91+
+}
92+
+
93+
+// TestTemporaryOverlayMountActivation tests WithTemporary with overlay mounts,
94+
+// which is the more common case for `ctr images mount` with overlay snapshotter.
95+
+func TestTemporaryOverlayMountActivation(t *testing.T) {
96+
+ testutil.RequiresRoot(t)
97+
+ ctx := logtest.WithT(context.Background(), t)
98+
+ ctx = namespaces.WithNamespace(ctx, "test")
99+
+ td := t.TempDir()
100+
+ metadb := filepath.Join(td, "mounts.db")
101+
+ targetdir := filepath.Join(td, "m")
102+
+ db, err := bolt.Open(metadb, 0600, nil)
103+
+ require.NoError(t, err)
104+
+ defer db.Close()
105+
+
106+
+ lower1 := filepath.Join(td, "lower1")
107+
+ lower2 := filepath.Join(td, "lower2")
108+
+ upper := filepath.Join(td, "upper")
109+
+ work := filepath.Join(td, "work")
110+
+
111+
+ require.NoError(t, os.MkdirAll(lower1, 0755))
112+
+ require.NoError(t, os.MkdirAll(lower2, 0755))
113+
+ require.NoError(t, os.MkdirAll(upper, 0755))
114+
+ require.NoError(t, os.MkdirAll(work, 0755))
115+
+
116+
+ require.NoError(t, os.WriteFile(filepath.Join(lower1, "file1.txt"), []byte("layer1\n"), 0644))
117+
+ require.NoError(t, os.WriteFile(filepath.Join(lower2, "file2.txt"), []byte("layer2\n"), 0644))
118+
+
119+
+ mounts := []mount.Mount{
120+
+ {
121+
+ Type: "overlay",
122+
+ Source: "overlay",
123+
+ Options: []string{
124+
+ fmt.Sprintf("lowerdir=%s:%s", lower2, lower1),
125+
+ fmt.Sprintf("upperdir=%s", upper),
126+
+ fmt.Sprintf("workdir=%s", work),
127+
+ },
128+
+ },
129+
+ }
130+
+
131+
+ m, err := NewManager(db, targetdir)
132+
+ require.NoError(t, err)
133+
+
134+
+ ainfo, err := m.Activate(ctx, "temp-overlay-test", mounts, mount.WithTemporary)
135+
+ require.NoError(t, err)
136+
+ defer func() {
137+
+ assert.NoError(t, m.Deactivate(ctx, "temp-overlay-test"))
138+
+ }()
139+
+
140+
+ require.NotEmpty(t, ainfo.System, "Expected system mounts to be returned")
141+
+
142+
+ require.Len(t, ainfo.System, 1, "Expected exactly one system mount")
143+
+ systemMount := ainfo.System[0]
144+
+ assert.Equal(t, "bind", systemMount.Type, "Expected bind mount type")
145+
+
146+
+ sourceInfo, err := os.Stat(systemMount.Source)
147+
+ require.NoError(t, err, "Bind mount source %q should exist", systemMount.Source)
148+
+ assert.True(t, sourceInfo.IsDir(), "Bind mount source should be a directory")
149+
+
150+
+ file1 := filepath.Join(systemMount.Source, "file1.txt")
151+
+ file2 := filepath.Join(systemMount.Source, "file2.txt")
152+
+
153+
+ content1, err := os.ReadFile(file1)
154+
+ require.NoError(t, err, "Should be able to read file1 from overlay via bind source")
155+
+ assert.Equal(t, "layer1\n", string(content1))
156+
+
157+
+ content2, err := os.ReadFile(file2)
158+
+ require.NoError(t, err, "Should be able to read file2 from overlay via bind source")
159+
+ assert.Equal(t, "layer2\n", string(content2))
160+
+
161+
+ targetMount := filepath.Join(td, "target")
162+
+ require.NoError(t, os.MkdirAll(targetMount, 0755))
163+
+
164+
+ err = mount.All(ainfo.System, targetMount)
165+
+ require.NoError(t, err, "Should be able to mount system mounts to target")
166+
+ defer testutil.Unmount(t, targetMount)
167+
+
168+
+ targetFile1 := filepath.Join(targetMount, "file1.txt")
169+
+ targetFile2 := filepath.Join(targetMount, "file2.txt")
170+
+
171+
+ targetContent1, err := os.ReadFile(targetFile1)
172+
+ require.NoError(t, err)
173+
+ assert.Equal(t, "layer1\n", string(targetContent1))
174+
+
175+
+ targetContent2, err := os.ReadFile(targetFile2)
176+
+ require.NoError(t, err)
177+
+ assert.Equal(t, "layer2\n", string(targetContent2))
178+
+}
179+
+
180+
func initalizeBlockDevice(td string, a fstest.Applier) (string, error) {
181+
file, err := os.CreateTemp(td, "fs-")
182+
if err != nil {
183+
@@ -342,7 +497,7 @@ func initalizeBlockDevice(td string, a fstest.Applier) (string, error) {
184+
185+
m := mount.Mount{
186+
Type: "ext4",
187+
- Source: dpath, // previous mount
188+
+ Source: dpath,
189+
Options: []string{"loop"},
190+
}
191+
target, err := os.MkdirTemp(td, "mount-")
192+
193+
From 1d79082735d46fe24ded00a55ea6e3a33954593e Mon Sep 17 00:00:00 2001
194+
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Poulin?= <jeromepoulin@gmail.com>
195+
Date: Wed, 26 Nov 2025 18:29:31 -0500
196+
Subject: [PATCH 2/2] core/mount/manager: fix bind mount missing rbind option
197+
MIME-Version: 1.0
198+
Content-Type: text/plain; charset=UTF-8
199+
Content-Transfer-Encoding: 8bit
200+
201+
The bind mount created for temporary activations was missing the
202+
Options field, causing mount to fail with "no such device" because
203+
the MS_BIND flag wasn't being set.
204+
205+
Fixes #12549
206+
207+
Signed-off-by: Jérôme Poulin <jeromepoulin@gmail.com>
208+
---
209+
core/mount/manager/manager.go | 6 +++---
210+
1 file changed, 3 insertions(+), 3 deletions(-)
211+
212+
diff --git a/core/mount/manager/manager.go b/core/mount/manager/manager.go
213+
index d43c1beb8e7c..5163c17dbcac 100644
214+
--- a/core/mount/manager/manager.go
215+
+++ b/core/mount/manager/manager.go
216+
@@ -430,9 +430,9 @@ func (mm *mountManager) Activate(ctx context.Context, name string, mounts []moun
217+
// TODO: Add config for whether to add the bind mount?
218+
if config.Temporary && firstSystemMount > 0 {
219+
mounts = append(mounts, mount.Mount{
220+
- Type: "bind",
221+
- Source: mounted[firstSystemMount-1].MountPoint,
222+
- // TODO : Configurable bind mount options?
223+
+ Type: "bind",
224+
+ Source: mounted[firstSystemMount-1].MountPoint,
225+
+ Options: []string{"rbind"},
226+
})
227+
}
228+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The `0001-ctr-no-such-device-fix.patch` fixes a regression detected by
2+
our `cl.toolbox.dnf-install` test. It is merged into the 2.2 release
3+
branch in upstream, but no release with the fix happened yet.

0 commit comments

Comments
 (0)