@@ -3,16 +3,18 @@ package snapshot
33import (
44 "os"
55
6+ "github.com/Microsoft/go-winio/pkg/bindfilter"
67 "github.com/containerd/containerd/errdefs"
78 "github.com/containerd/containerd/mount"
89 "github.com/pkg/errors"
10+ "golang.org/x/sys/windows"
911)
1012
1113func (lm * localMounter ) Mount () (string , error ) {
1214 lm .mu .Lock ()
1315 defer lm .mu .Unlock ()
1416
15- if lm .mounts == nil {
17+ if lm .mounts == nil && lm . mountable != nil {
1618 mounts , release , err := lm .mountable .Mount ()
1719 if err != nil {
1820 return "" , err
@@ -33,9 +35,18 @@ func (lm *localMounter) Mount() (string, error) {
3335 return "" , errors .Wrap (err , "failed to create temp dir" )
3436 }
3537
36- if err := m .Mount (dir ); err != nil {
37- return "" , errors .Wrapf (err , "failed to mount %v: %+v" , m , err )
38+ if m .Type == "bind" || m .Type == "rbind" {
39+ // The Windows snapshotter does not have any notion of bind mounts. We emulate
40+ // bind mounts here using the bind filter.
41+ if err := bindfilter .ApplyFileBinding (dir , m .Source , m .ReadOnly ()); err != nil {
42+ return "" , errors .Wrapf (err , "failed to mount %v: %+v" , m , err )
43+ }
44+ } else {
45+ if err := m .Mount (dir ); err != nil {
46+ return "" , errors .Wrapf (err , "failed to mount %v: %+v" , m , err )
47+ }
3848 }
49+
3950 lm .target = dir
4051 return lm .target , nil
4152}
@@ -44,9 +55,32 @@ func (lm *localMounter) Unmount() error {
4455 lm .mu .Lock ()
4556 defer lm .mu .Unlock ()
4657
58+ // NOTE(gabriel-samfira): Should we just return nil if len(lm.mounts) == 0?
59+ // Calling Mount() would fail on an instance of the localMounter where mounts contains
60+ // anything other than 1 mount.
61+ if len (lm .mounts ) != 1 {
62+ return errors .Wrapf (errdefs .ErrNotImplemented , "request to mount %d layers, only 1 is supported" , len (lm .mounts ))
63+ }
64+ m := lm .mounts [0 ]
65+
4766 if lm .target != "" {
48- if err := mount .Unmount (lm .target , 0 ); err != nil {
49- return err
67+ if m .Type == "bind" || m .Type == "rbind" {
68+ if err := bindfilter .RemoveFileBinding (lm .target ); err != nil {
69+ // The following two errors denote that lm.target is not a mount point.
70+ if ! errors .Is (err , windows .ERROR_INVALID_PARAMETER ) && ! errors .Is (err , windows .ERROR_NOT_FOUND ) {
71+ return errors .Wrapf (err , "failed to unmount %v: %+v" , lm .target , err )
72+ }
73+ }
74+ } else {
75+ // The containerd snapshotter uses the bind filter internally to mount windows-layer
76+ // volumes. We use same bind filter here to emulate bind mounts. In theory we could
77+ // simply call mount.Unmount() here, without the extra check for bind mounts and explicit
78+ // call to bindfilter.RemoveFileBinding() (above), but this would operate under the
79+ // assumption that the internal implementation in containerd will always be based on the
80+ // bind filter, which feels brittle.
81+ if err := mount .Unmount (lm .target , 0 ); err != nil {
82+ return errors .Wrapf (err , "failed to unmount %v: %+v" , lm .target , err )
83+ }
5084 }
5185 os .RemoveAll (lm .target )
5286 lm .target = ""
0 commit comments