@@ -187,7 +187,7 @@ func (s *snapshotter) Mounts(ctx context.Context, key string) (_ []mount.Mount,
187187 return nil , err
188188 }
189189
190- return s .mounts (snapshot ), nil
190+ return s .mounts (snapshot , key ), nil
191191}
192192
193193func (s * snapshotter ) Commit (ctx context.Context , name , key string , opts ... snapshots.Opt ) (retErr error ) {
@@ -208,7 +208,11 @@ func (s *snapshotter) Commit(ctx context.Context, name, key string, opts ...snap
208208 // If (windowsDiff).Apply was used to populate this layer, then it's already in the 'committed' state.
209209 // See createSnapshot below for more details
210210 if ! strings .Contains (key , snapshots .UnpackKeyPrefix ) {
211- if err := s .convertScratchToReadOnlyLayer (ctx , snapshot , path ); err != nil {
211+ if len (snapshot .ParentIDs ) == 0 {
212+ if err = hcsshim .ConvertToBaseLayer (path ); err != nil {
213+ return err
214+ }
215+ } else if err := s .convertScratchToReadOnlyLayer (ctx , snapshot , path ); err != nil {
212216 return err
213217 }
214218 }
@@ -299,11 +303,9 @@ func (s *snapshotter) Close() error {
299303 return s .ms .Close ()
300304}
301305
302- func (s * snapshotter ) mounts (sn storage.Snapshot ) []mount.Mount {
306+ func (s * snapshotter ) mounts (sn storage.Snapshot , key string ) []mount.Mount {
303307 var (
304- roFlag string
305- source string
306- parentLayerPaths []string
308+ roFlag string
307309 )
308310
309311 if sn .Kind == snapshots .KindView {
@@ -312,12 +314,19 @@ func (s *snapshotter) mounts(sn storage.Snapshot) []mount.Mount {
312314 roFlag = "rw"
313315 }
314316
315- if len (sn .ParentIDs ) == 0 || sn .Kind == snapshots .KindActive {
316- source = s .getSnapshotDir (sn .ID )
317- parentLayerPaths = s .parentIDsToParentPaths (sn .ParentIDs )
318- } else {
319- source = s .getSnapshotDir (sn .ParentIDs [0 ])
320- parentLayerPaths = s .parentIDsToParentPaths (sn .ParentIDs [1 :])
317+ source := s .getSnapshotDir (sn .ID )
318+ parentLayerPaths := s .parentIDsToParentPaths (sn .ParentIDs )
319+
320+ mountType := "windows-layer"
321+
322+ if len (sn .ParentIDs ) == 0 {
323+ // A mount of a parentless snapshot is a bind-mount.
324+ mountType = "bind"
325+ // If not being extracted into, then the bind-target is the
326+ // "Files" subdirectory.
327+ if ! strings .Contains (key , snapshots .UnpackKeyPrefix ) {
328+ source = filepath .Join (source , "Files" )
329+ }
321330 }
322331
323332 // error is not checked here, as a string array will never fail to Marshal
@@ -327,7 +336,7 @@ func (s *snapshotter) mounts(sn storage.Snapshot) []mount.Mount {
327336 var mounts []mount.Mount
328337 mounts = append (mounts , mount.Mount {
329338 Source : source ,
330- Type : "windows-layer" ,
339+ Type : mountType ,
331340 Options : []string {
332341 roFlag ,
333342 parentLayersOption ,
@@ -360,13 +369,22 @@ func (s *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, k
360369 return err
361370 }
362371
363- // IO/disk space optimization
364- //
365- // We only need one sandbox.vhdx for the container. Skip making one for this
366- // snapshot if this isn't the snapshot that just houses the final sandbox.vhd
367- // that will be mounted as the containers scratch. Currently the key for a snapshot
368- // where a layer will be extracted to will have the string `extract-` in it.
369- if ! strings .Contains (key , snapshots .UnpackKeyPrefix ) {
372+ if strings .Contains (key , snapshots .UnpackKeyPrefix ) {
373+ // IO/disk space optimization: Do nothing
374+ //
375+ // We only need one sandbox.vhdx for the container. Skip making one for this
376+ // snapshot if this isn't the snapshot that just houses the final sandbox.vhd
377+ // that will be mounted as the containers scratch. Currently the key for a snapshot
378+ // where a layer will be extracted to will have the string `extract-` in it.
379+ } else if len (newSnapshot .ParentIDs ) == 0 {
380+ // A parentless snapshot is just a bind-mount to a directory named
381+ // "Files". When committed, there'll be some post-processing to fill in the rest
382+ // of the metadata.
383+ filesDir := filepath .Join (snDir , "Files" )
384+ if err := os .MkdirAll (filesDir , 0700 ); err != nil {
385+ return err
386+ }
387+ } else {
370388 parentLayerPaths := s .parentIDsToParentPaths (newSnapshot .ParentIDs )
371389
372390 var snapshotInfo snapshots.Info
@@ -375,22 +393,28 @@ func (s *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, k
375393 }
376394
377395 var sizeInBytes uint64
378- if sizeGBstr , ok := snapshotInfo .Labels [rootfsSizeInGBLabel ]; ok {
379- log .G (ctx ).Warnf ("%q label is deprecated, please use %q instead." , rootfsSizeInGBLabel , rootfsSizeInBytesLabel )
380-
381- sizeInGB , err := strconv .ParseUint (sizeGBstr , 10 , 32 )
382- if err != nil {
383- return fmt .Errorf ("failed to parse label %q=%q: %w" , rootfsSizeInGBLabel , sizeGBstr , err )
396+ if kind == snapshots .KindActive {
397+ if sizeGBstr , ok := snapshotInfo .Labels [rootfsSizeInGBLabel ]; ok {
398+ log .G (ctx ).Warnf ("%q label is deprecated, please use %q instead." , rootfsSizeInGBLabel , rootfsSizeInBytesLabel )
399+
400+ sizeInGB , err := strconv .ParseUint (sizeGBstr , 10 , 32 )
401+ if err != nil {
402+ return fmt .Errorf ("failed to parse label %q=%q: %w" , rootfsSizeInGBLabel , sizeGBstr , err )
403+ }
404+ sizeInBytes = sizeInGB * 1024 * 1024 * 1024
384405 }
385- sizeInBytes = sizeInGB * 1024 * 1024 * 1024
386- }
387406
388- // Prefer the newer label in bytes over the deprecated Windows specific GB variant.
389- if sizeBytesStr , ok := snapshotInfo .Labels [rootfsSizeInBytesLabel ]; ok {
390- sizeInBytes , err = strconv .ParseUint (sizeBytesStr , 10 , 64 )
391- if err != nil {
392- return fmt .Errorf ("failed to parse label %q=%q: %w" , rootfsSizeInBytesLabel , sizeBytesStr , err )
407+ // Prefer the newer label in bytes over the deprecated Windows specific GB variant.
408+ if sizeBytesStr , ok := snapshotInfo .Labels [rootfsSizeInBytesLabel ]; ok {
409+ sizeInBytes , err = strconv .ParseUint (sizeBytesStr , 10 , 64 )
410+ if err != nil {
411+ return fmt .Errorf ("failed to parse label %q=%q: %w" , rootfsSizeInBytesLabel , sizeBytesStr , err )
412+ }
393413 }
414+ } else {
415+ // A view is just a read-write snapshot with a _really_ small sandbox, since we cannot actually
416+ // make a read-only mount or junction point. https://superuser.com/q/881544/112473
417+ sizeInBytes = 1024 * 1024 * 1024
394418 }
395419
396420 var makeUVMScratch bool
@@ -415,7 +439,7 @@ func (s *snapshotter) createSnapshot(ctx context.Context, kind snapshots.Kind, k
415439 return nil , err
416440 }
417441
418- return s .mounts (newSnapshot ), nil
442+ return s .mounts (newSnapshot , key ), nil
419443}
420444
421445func (s * snapshotter ) parentIDsToParentPaths (parentIDs []string ) []string {
0 commit comments