@@ -813,6 +813,19 @@ func (c *containerMounter) prepareMounts() ([]mountInfo, error) {
813
813
return mounts , nil
814
814
}
815
815
816
+ func (c * containerMounter ) getPathMode (ctx context.Context , creds * auth.Credentials , path * vfs.PathOperation ) (linux.FileMode , error ) {
817
+ stat , err := c .k .VFS ().StatAt (ctx , creds , path , & vfs.StatOptions {
818
+ Mask : linux .STATX_TYPE ,
819
+ })
820
+ if err != nil {
821
+ return 0 , err
822
+ }
823
+ if stat .Mask & linux .STATX_TYPE == 0 {
824
+ return 0 , fmt .Errorf ("failed to get file type" )
825
+ }
826
+ return linux .FileMode (stat .Mode ), nil
827
+ }
828
+
816
829
func (c * containerMounter ) mountSubmount (ctx context.Context , spec * specs.Spec , conf * config.Config , mns * vfs.MountNamespace , creds * auth.Credentials , submount * mountInfo ) (* vfs.Mount , error ) {
817
830
fsName , opts , err := getMountNameAndOptions (spec , conf , submount , c .productName , c .containerName )
818
831
if err != nil {
@@ -823,10 +836,6 @@ func (c *containerMounter) mountSubmount(ctx context.Context, spec *specs.Spec,
823
836
return nil , nil
824
837
}
825
838
826
- if err := c .makeMountPoint (ctx , creds , mns , submount .mount .Destination ); err != nil {
827
- return nil , fmt .Errorf ("creating mount point %q: %w" , submount .mount .Destination , err )
828
- }
829
-
830
839
if submount .goferMountConf .ShouldUseOverlayfs () {
831
840
log .Infof ("Adding overlay on top of mount %q" , submount .mount .Destination )
832
841
var cleanup func ()
@@ -838,18 +847,41 @@ func (c *containerMounter) mountSubmount(ctx context.Context, spec *specs.Spec,
838
847
fsName = overlay .Name
839
848
}
840
849
850
+ mount := submount .mount
841
851
root := mns .Root (ctx )
842
852
defer root .DecRef (ctx )
843
853
target := & vfs.PathOperation {
844
854
Root : root ,
845
855
Start : root ,
846
- Path : fspath .Parse (submount .mount .Destination ),
856
+ Path : fspath .Parse (mount .Destination ),
857
+ }
858
+ mnt , err := c .k .VFS ().MountDisconnected (ctx , creds , "" , fsName , opts )
859
+ if err != nil {
860
+ return nil , err
861
+ }
862
+ defer mnt .DecRef (ctx )
863
+
864
+ vd := vfs .MakeVirtualDentry (mnt , mnt .Root ())
865
+ rootPath := & vfs.PathOperation {
866
+ Root : vd ,
867
+ Start : vd ,
847
868
}
848
- mnt , err := c .k .VFS ().MountAt (ctx , creds , "" , target , fsName , opts )
869
+
870
+ rootMode , err := c .getPathMode (ctx , creds , rootPath )
849
871
if err != nil {
850
- return nil , fmt .Errorf ("failed to mount %q (type: %s): %w, opts: %v" , submount .mount .Destination , submount .mount .Type , err , opts )
872
+ return nil , fmt .Errorf ("failed to stat %q: %w" , mount .Source , err )
873
+ }
874
+ if err := c .makeMountPoint (ctx , creds , mns , mount .Destination , rootMode ); err != nil {
875
+ return nil , fmt .Errorf ("creating mount point %q: %w" , mount .Destination , err )
851
876
}
852
- log .Infof ("Mounted %q to %q type: %s, internal-options: %q" , submount .mount .Source , submount .mount .Destination , submount .mount .Type , opts .GetFilesystemOptions .Data )
877
+
878
+ if err := c .k .VFS ().ConnectMountAt (ctx , creds , mnt , target ); err != nil {
879
+ return nil , fmt .Errorf ("failed to mount %q (type: %s): %w, opts: %v" ,
880
+ mount .Destination , mount .Type , err , opts )
881
+ }
882
+
883
+ log .Infof ("Mounted %q to %q type: %s, internal-options: %q" ,
884
+ mount .Source , mount .Destination , mount .Type , opts .GetFilesystemOptions .Data )
853
885
return mnt , nil
854
886
}
855
887
@@ -1225,7 +1257,17 @@ func (c *containerMounter) mountSharedSubmount(ctx context.Context, conf *config
1225
1257
Path : fspath .Parse (mntInfo .mount .Destination ),
1226
1258
}
1227
1259
1228
- if err := c .makeMountPoint (ctx , creds , mns , mntInfo .mount .Destination ); err != nil {
1260
+ vd := vfs .MakeVirtualDentry (newMnt , newMnt .Root ())
1261
+ rootPath := & vfs.PathOperation {
1262
+ Root : vd ,
1263
+ Start : vd ,
1264
+ }
1265
+ rootMode , err := c .getPathMode (ctx , creds , rootPath )
1266
+ if err != nil {
1267
+ return nil , err
1268
+ }
1269
+
1270
+ if err := c .makeMountPoint (ctx , creds , mns , mntInfo .mount .Destination , rootMode ); err != nil {
1229
1271
return nil , fmt .Errorf ("creating mount point %q: %w" , mntInfo .mount .Destination , err )
1230
1272
}
1231
1273
@@ -1236,24 +1278,63 @@ func (c *containerMounter) mountSharedSubmount(ctx context.Context, conf *config
1236
1278
return newMnt , nil
1237
1279
}
1238
1280
1239
- func (c * containerMounter ) makeMountPoint (ctx context.Context , creds * auth.Credentials , mns * vfs.MountNamespace , dest string ) error {
1281
+ func (c * containerMounter ) makeMountPoint (
1282
+ ctx context.Context ,
1283
+ creds * auth.Credentials ,
1284
+ mns * vfs.MountNamespace ,
1285
+ dest string ,
1286
+ rootMode linux.FileMode ,
1287
+ ) error {
1240
1288
root := mns .Root (ctx )
1241
1289
defer root .DecRef (ctx )
1290
+
1242
1291
target := & vfs.PathOperation {
1243
1292
Root : root ,
1244
1293
Start : root ,
1245
1294
Path : fspath .Parse (dest ),
1246
1295
}
1247
- // First check if mount point exists. When overlay is enabled, gofer doesn't
1248
- // allow changes to the FS, making MakeSytheticMountpoint() ineffective
1249
- // because MkdirAt fails with EROFS even if file exists.
1250
- vd , err := c .k .VFS ().GetDentryAt (ctx , creds , target , & vfs.GetDentryOptions {})
1251
- if err == nil {
1252
- // File exists, we're done.
1253
- vd .DecRef (ctx )
1296
+
1297
+ fs := c .k .VFS ()
1298
+
1299
+ mode , err := c .getPathMode (ctx , creds , target )
1300
+ // First check if mount point exists.
1301
+ switch {
1302
+ case err == nil :
1303
+ if mode .IsDir () != rootMode .IsDir () {
1304
+ if rootMode .IsDir () {
1305
+ return fmt .Errorf ("mountpoint %q isn't a directory" , dest )
1306
+ } else {
1307
+ return fmt .Errorf ("mountpoint %q isn't not a file" , dest )
1308
+ }
1309
+ }
1310
+ // Target already exists.
1254
1311
return nil
1312
+ case linuxerr .Equals (linuxerr .ENOENT , err ):
1313
+ // Expected, we will create the mount point.
1314
+ default :
1315
+ return fmt .Errorf ("stat failed for %q during mountpoint creation: %w" , dest , err )
1316
+ }
1317
+
1318
+ mkdirOpts := & vfs.MkdirOptions {Mode : 0755 , ForSyntheticMountpoint : true }
1319
+
1320
+ // Make sure the parent directory of target exists.
1321
+ if err := fs .MkdirAllAt (ctx , path .Dir (dest ), root , creds , mkdirOpts , true /* mustBeDir */ ); err != nil {
1322
+ return fmt .Errorf ("failed to create parent directory of mountpoint %q: %w" , dest , err )
1255
1323
}
1256
- return c .k .VFS ().MakeSyntheticMountpoint (ctx , dest , root , creds )
1324
+
1325
+ if rootMode .IsDir () {
1326
+ if err := fs .MkdirAt (ctx , creds , target , mkdirOpts ); err != nil {
1327
+ return fmt .Errorf ("failed to create directory mountpoint %q: %w" , dest , err )
1328
+ }
1329
+ } else {
1330
+ mknodOpts := & vfs.MknodOptions {
1331
+ Mode : linux .FileMode (linux .S_IFREG | 0644 ),
1332
+ }
1333
+ if err := fs .MknodAt (ctx , creds , target , mknodOpts ); err != nil {
1334
+ return fmt .Errorf ("failed to create file mountpoint %q: %w" , dest , err )
1335
+ }
1336
+ }
1337
+ return nil
1257
1338
}
1258
1339
1259
1340
// configureRestore returns an updated context.Context including filesystem
0 commit comments