/
mount.go
141 lines (114 loc) · 3.48 KB
/
mount.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package snapshotter
import (
"os"
"path/filepath"
"github.com/containerd/containerd/mount"
"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/idtools"
"github.com/moby/locker"
"github.com/sirupsen/logrus"
)
const mountsDir = "rootfs"
// List of known filesystems that can't be re-mounted or have shared layers
var refCountedFileSystems = []string{"fuse-overlayfs", "overlayfs", "stargz", "zfs"}
// Mounter handles mounting/unmounting things coming in from a snapshotter
// with optional reference counting if needed by the filesystem
type Mounter interface {
// Mount mounts the rootfs for a container and returns the mount point
Mount(mounts []mount.Mount, containerID string) (string, error)
// Unmount unmounts the container rootfs
Unmount(target string) error
}
// inSlice tests whether a string is contained in a slice of strings or not.
// Comparison is case sensitive
func inSlice(slice []string, s string) bool {
for _, ss := range slice {
if s == ss {
return true
}
}
return false
}
// NewMounter creates a new mounter for the provided snapshotter
func NewMounter(home string, snapshotter string, idMap idtools.IdentityMapping) Mounter {
if inSlice(refCountedFileSystems, snapshotter) {
return &refCountMounter{
home: home,
snapshotter: snapshotter,
rc: graphdriver.NewRefCounter(checker()),
locker: locker.New(),
idMap: idMap,
}
}
return mounter{
home: home,
snapshotter: snapshotter,
idMap: idMap,
}
}
type refCountMounter struct {
home string
snapshotter string
rc *graphdriver.RefCounter
locker *locker.Locker
idMap idtools.IdentityMapping
}
func (m *refCountMounter) Mount(mounts []mount.Mount, containerID string) (target string, retErr error) {
target = filepath.Join(m.home, mountsDir, m.snapshotter, containerID)
_, err := os.Stat(target)
if err != nil && !os.IsNotExist(err) {
return "", err
}
if count := m.rc.Increment(target); count > 1 {
return target, nil
}
m.locker.Lock(target)
defer m.locker.Unlock(target)
defer func() {
if retErr != nil {
if c := m.rc.Decrement(target); c <= 0 {
if mntErr := unmount(target); mntErr != nil {
logrus.Errorf("error unmounting %s: %v", target, mntErr)
}
if rmErr := os.Remove(target); rmErr != nil && !os.IsNotExist(rmErr) {
logrus.Debugf("Failed to remove %s: %v: %v", target, rmErr, err)
}
}
}
}()
root := m.idMap.RootPair()
if err := idtools.MkdirAllAndChown(target, 0700, root); err != nil {
return "", err
}
return target, mount.All(mounts, target)
}
func (m *refCountMounter) Unmount(target string) error {
if count := m.rc.Decrement(target); count > 0 {
return nil
}
m.locker.Lock(target)
defer m.locker.Unlock(target)
if err := unmount(target); err != nil {
logrus.Debugf("Failed to unmount %s: %v", target, err)
}
if err := os.Remove(target); err != nil {
logrus.WithError(err).WithField("dir", target).Error("failed to remove mount temp dir")
}
return nil
}
type mounter struct {
home string
snapshotter string
idMap idtools.IdentityMapping
}
func (m mounter) Mount(mounts []mount.Mount, containerID string) (string, error) {
target := filepath.Join(m.home, mountsDir, m.snapshotter, containerID)
root := m.idMap.RootPair()
if err := idtools.MkdirAndChown(target, 0700, root); err != nil {
return "", err
}
return target, mount.All(mounts, target)
}
func (m mounter) Unmount(target string) error {
return unmount(target)
}