@@ -3,16 +3,18 @@ package snapshot
3
3
import (
4
4
"os"
5
5
6
+ "github.com/Microsoft/go-winio/pkg/bindfilter"
6
7
"github.com/containerd/containerd/errdefs"
7
8
"github.com/containerd/containerd/mount"
8
9
"github.com/pkg/errors"
10
+ "golang.org/x/sys/windows"
9
11
)
10
12
11
13
func (lm * localMounter ) Mount () (string , error ) {
12
14
lm .mu .Lock ()
13
15
defer lm .mu .Unlock ()
14
16
15
- if lm .mounts == nil {
17
+ if lm .mounts == nil && lm . mountable != nil {
16
18
mounts , release , err := lm .mountable .Mount ()
17
19
if err != nil {
18
20
return "" , err
@@ -33,9 +35,18 @@ func (lm *localMounter) Mount() (string, error) {
33
35
return "" , errors .Wrap (err , "failed to create temp dir" )
34
36
}
35
37
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
+ }
38
48
}
49
+
39
50
lm .target = dir
40
51
return lm .target , nil
41
52
}
@@ -44,9 +55,32 @@ func (lm *localMounter) Unmount() error {
44
55
lm .mu .Lock ()
45
56
defer lm .mu .Unlock ()
46
57
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
+
47
66
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
+ }
50
84
}
51
85
os .RemoveAll (lm .target )
52
86
lm .target = ""
0 commit comments