@@ -46,38 +46,13 @@ func TestSnapshotterSuite(t *testing.T) {
4646 logrus .SetLevel (logrus .DebugLevel )
4747
4848 snapshotterFn := func (ctx context.Context , root string ) (snapshots.Snapshotter , func () error , error ) {
49- // Create loopback devices for each test case
50- _ , loopDataDevice := createLoopbackDevice (t , root )
51- _ , loopMetaDevice := createLoopbackDevice (t , root )
52-
5349 poolName := fmt .Sprintf ("containerd-snapshotter-suite-pool-%d" , time .Now ().Nanosecond ())
54- err := dmsetup .CreatePool (poolName , loopDataDevice , loopMetaDevice , 64 * 1024 / dmsetup .SectorSize )
55- assert .NilError (t , err , "failed to create pool %q" , poolName )
56-
5750 config := & Config {
5851 RootPath : root ,
5952 PoolName : poolName ,
6053 BaseImageSize : "16Mb" ,
6154 }
62-
63- snap , err := NewSnapshotter (context .Background (), config )
64- if err != nil {
65- return nil , nil , err
66- }
67-
68- // Remove device mapper pool and detach loop devices after test completes
69- removePool := func () error {
70- result := multierror .Append (
71- snap .pool .RemovePool (ctx ),
72- mount .DetachLoopDevice (loopDataDevice , loopMetaDevice ))
73-
74- return result .ErrorOrNil ()
75- }
76-
77- // Pool cleanup should be called before closing metadata store (as we need to retrieve device names)
78- snap .cleanupFn = append ([]closeFunc {removePool }, snap .cleanupFn ... )
79-
80- return snap , snap .Close , nil
55+ return createSnapshotter (ctx , t , config )
8156 }
8257
8358 testsuite .SnapshotterSuite (t , "devmapper" , snapshotterFn )
@@ -165,3 +140,85 @@ func TestMkfsXfsNonDefault(t *testing.T) {
165140 err := mkfs (ctx , "xfs" , "noquota" , "" )
166141 assert .ErrorContains (t , err , `mkfs.xfs couldn't initialize ""` )
167142}
143+
144+ func TestMultipleXfsMounts (t * testing.T ) {
145+ testutil .RequiresRoot (t )
146+
147+ logrus .SetLevel (logrus .DebugLevel )
148+
149+ ctx := context .Background ()
150+ ctx = namespaces .WithNamespace (ctx , "testsuite" )
151+ tempDir , err := os .MkdirTemp ("" , "snapshot-suite-usage" )
152+ assert .NilError (t , err )
153+ defer os .RemoveAll (tempDir )
154+
155+ poolName := fmt .Sprintf ("containerd-snapshotter-suite-pool-%d" , time .Now ().Nanosecond ())
156+ config := & Config {
157+ RootPath : tempDir ,
158+ PoolName : poolName ,
159+ BaseImageSize : "16Mb" ,
160+ FileSystemType : "xfs" ,
161+ }
162+ snapshotter , closer , err := createSnapshotter (ctx , t , config )
163+ assert .NilError (t , err )
164+ defer closer ()
165+
166+ var (
167+ sizeBytes int64 = 1048576 // 1MB
168+ baseApplier = fstest .Apply (fstest .CreateRandomFile ("/a" , 12345679 , sizeBytes , 0777 ))
169+ )
170+
171+ // Create base layer
172+ mounts , err := snapshotter .Prepare (ctx , "prepare-1" , "" )
173+ assert .NilError (t , err )
174+
175+ root1 , _ := os .MkdirTemp (os .TempDir (), "containerd-mount" )
176+ defer func () {
177+ mount .UnmountAll (root1 , 0 )
178+ os .Remove (root1 )
179+ }()
180+ err = mount .All (mounts , root1 )
181+ assert .NilError (t , err )
182+ baseApplier .Apply (root1 )
183+ snapshotter .Commit (ctx , "layer-1" , "prepare-1" )
184+
185+ // Create one child layer
186+ mounts , err = snapshotter .Prepare (ctx , "prepare-2" , "layer-1" )
187+ assert .NilError (t , err )
188+
189+ root2 , _ := os .MkdirTemp (os .TempDir (), "containerd-mount" )
190+ defer func () {
191+ mount .UnmountAll (root2 , 0 )
192+ os .Remove (root2 )
193+ }()
194+ err = mount .All (mounts , root2 )
195+ assert .NilError (t , err )
196+ }
197+
198+ func createSnapshotter (ctx context.Context , t * testing.T , config * Config ) (snapshots.Snapshotter , func () error , error ) {
199+ // Create loopback devices for each test case
200+ _ , loopDataDevice := createLoopbackDevice (t , config .RootPath )
201+ _ , loopMetaDevice := createLoopbackDevice (t , config .RootPath )
202+
203+ err := dmsetup .CreatePool (config .PoolName , loopDataDevice , loopMetaDevice , 64 * 1024 / dmsetup .SectorSize )
204+ assert .NilError (t , err , "failed to create pool %q" , config .PoolName )
205+
206+ snap , err := NewSnapshotter (ctx , config )
207+ if err != nil {
208+ return nil , nil , err
209+ }
210+
211+ // Remove device mapper pool and detach loop devices after test completes
212+ removePool := func () error {
213+ result := multierror .Append (
214+ snap .pool .RemovePool (ctx ),
215+ mount .DetachLoopDevice (loopDataDevice , loopMetaDevice ))
216+
217+ return result .ErrorOrNil ()
218+ }
219+
220+ // Pool cleanup should be called before closing metadata store (as we need to retrieve device names)
221+ snap .cleanupFn = append ([]closeFunc {removePool }, snap .cleanupFn ... )
222+
223+ return snap , snap .Close , nil
224+ }
0 commit comments