/
mount.go
152 lines (124 loc) · 3.74 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
142
143
144
145
146
147
148
149
150
151
152
package snapshotter
import (
"context"
"os"
"path/filepath"
"github.com/containerd/containerd/mount"
"github.com/containerd/log"
"github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/idtools"
"github.com/moby/locker"
"github.com/moby/sys/mountinfo"
)
// 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
// Mounted returns a target mountpoint if it's already mounted
Mounted(containerID string) (string, error)
}
// NewMounter creates a new mounter for the provided snapshotter
func NewMounter(home string, snapshotter string, idMap idtools.IdentityMapping) *refCountMounter {
return &refCountMounter{
base: mounter{
home: home,
snapshotter: snapshotter,
idMap: idMap,
},
rc: graphdriver.NewRefCounter(checker()),
locker: locker.New(),
}
}
type refCountMounter struct {
rc *graphdriver.RefCounter
locker *locker.Locker
base mounter
}
func (m *refCountMounter) Mount(mounts []mount.Mount, containerID string) (target string, retErr error) {
target = m.base.target(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 {
log.G(context.TODO()).Errorf("error unmounting %s: %v", target, mntErr)
}
if rmErr := os.Remove(target); rmErr != nil && !os.IsNotExist(rmErr) {
log.G(context.TODO()).Debugf("Failed to remove %s: %v: %v", target, rmErr, err)
}
}
}
}()
return m.base.Mount(mounts, containerID)
}
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 {
log.G(context.TODO()).Debugf("Failed to unmount %s: %v", target, err)
}
if err := os.Remove(target); err != nil {
log.G(context.TODO()).WithError(err).WithField("dir", target).Error("failed to remove mount temp dir")
}
return nil
}
func (m *refCountMounter) Mounted(containerID string) (string, error) {
mounted, err := m.base.Mounted(containerID)
if err != nil || mounted == "" {
return mounted, err
}
target := m.base.target(containerID)
// Check if the refcount is non-zero.
m.rc.Increment(target)
if m.rc.Decrement(target) > 0 {
return mounted, nil
}
return "", nil
}
type mounter struct {
home string
snapshotter string
idMap idtools.IdentityMapping
}
func (m mounter) Mount(mounts []mount.Mount, containerID string) (string, error) {
target := m.target(containerID)
root := m.idMap.RootPair()
if err := idtools.MkdirAllAndChown(filepath.Dir(target), 0o710, idtools.Identity{
UID: idtools.CurrentIdentity().UID,
GID: root.GID,
}); err != nil {
return "", err
}
if err := idtools.MkdirAllAndChown(target, 0o710, root); err != nil {
return "", err
}
return target, mount.All(mounts, target)
}
func (m mounter) Unmount(target string) error {
return unmount(target)
}
func (m mounter) Mounted(containerID string) (string, error) {
target := m.target(containerID)
mounted, err := mountinfo.Mounted(target)
if err != nil || !mounted {
return "", err
}
return target, nil
}
func (m mounter) target(containerID string) string {
return filepath.Join(m.home, "rootfs", m.snapshotter, containerID)
}