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