github.com/moby/docker@v26.1.3+incompatible/daemon/snapshotter/mount.go (about) 1 package snapshotter 2 3 import ( 4 "context" 5 "os" 6 "path/filepath" 7 8 "github.com/containerd/containerd/mount" 9 "github.com/containerd/log" 10 "github.com/docker/docker/daemon/graphdriver" 11 "github.com/docker/docker/pkg/idtools" 12 "github.com/moby/locker" 13 "github.com/moby/sys/mountinfo" 14 ) 15 16 // Mounter handles mounting/unmounting things coming in from a snapshotter 17 // with optional reference counting if needed by the filesystem 18 type Mounter interface { 19 // Mount mounts the rootfs for a container and returns the mount point 20 Mount(mounts []mount.Mount, containerID string) (string, error) 21 // Unmount unmounts the container rootfs 22 Unmount(target string) error 23 // Mounted returns a target mountpoint if it's already mounted 24 Mounted(containerID string) (string, error) 25 } 26 27 // NewMounter creates a new mounter for the provided snapshotter 28 func NewMounter(home string, snapshotter string, idMap idtools.IdentityMapping) *refCountMounter { 29 return &refCountMounter{ 30 base: mounter{ 31 home: home, 32 snapshotter: snapshotter, 33 idMap: idMap, 34 }, 35 rc: graphdriver.NewRefCounter(checker()), 36 locker: locker.New(), 37 } 38 } 39 40 type refCountMounter struct { 41 rc *graphdriver.RefCounter 42 locker *locker.Locker 43 base mounter 44 } 45 46 func (m *refCountMounter) Mount(mounts []mount.Mount, containerID string) (target string, retErr error) { 47 target = m.base.target(containerID) 48 49 _, err := os.Stat(target) 50 if err != nil && !os.IsNotExist(err) { 51 return "", err 52 } 53 54 if count := m.rc.Increment(target); count > 1 { 55 return target, nil 56 } 57 58 m.locker.Lock(target) 59 defer m.locker.Unlock(target) 60 61 defer func() { 62 if retErr != nil { 63 if c := m.rc.Decrement(target); c <= 0 { 64 if mntErr := unmount(target); mntErr != nil { 65 log.G(context.TODO()).Errorf("error unmounting %s: %v", target, mntErr) 66 } 67 if rmErr := os.Remove(target); rmErr != nil && !os.IsNotExist(rmErr) { 68 log.G(context.TODO()).Debugf("Failed to remove %s: %v: %v", target, rmErr, err) 69 } 70 } 71 } 72 }() 73 74 return m.base.Mount(mounts, containerID) 75 } 76 77 func (m *refCountMounter) Unmount(target string) error { 78 if count := m.rc.Decrement(target); count > 0 { 79 return nil 80 } 81 82 m.locker.Lock(target) 83 defer m.locker.Unlock(target) 84 85 if err := unmount(target); err != nil { 86 log.G(context.TODO()).Debugf("Failed to unmount %s: %v", target, err) 87 } 88 89 if err := os.Remove(target); err != nil { 90 log.G(context.TODO()).WithError(err).WithField("dir", target).Error("failed to remove mount temp dir") 91 } 92 93 return nil 94 } 95 96 func (m *refCountMounter) Mounted(containerID string) (string, error) { 97 mounted, err := m.base.Mounted(containerID) 98 if err != nil || mounted == "" { 99 return mounted, err 100 } 101 102 target := m.base.target(containerID) 103 104 // Check if the refcount is non-zero. 105 m.rc.Increment(target) 106 if m.rc.Decrement(target) > 0 { 107 return mounted, nil 108 } 109 110 return "", nil 111 } 112 113 type mounter struct { 114 home string 115 snapshotter string 116 idMap idtools.IdentityMapping 117 } 118 119 func (m mounter) Mount(mounts []mount.Mount, containerID string) (string, error) { 120 target := m.target(containerID) 121 122 root := m.idMap.RootPair() 123 if err := idtools.MkdirAllAndChown(filepath.Dir(target), 0o710, idtools.Identity{ 124 UID: idtools.CurrentIdentity().UID, 125 GID: root.GID, 126 }); err != nil { 127 return "", err 128 } 129 if err := idtools.MkdirAllAndChown(target, 0o710, root); err != nil { 130 return "", err 131 } 132 133 return target, mount.All(mounts, target) 134 } 135 136 func (m mounter) Unmount(target string) error { 137 return unmount(target) 138 } 139 140 func (m mounter) Mounted(containerID string) (string, error) { 141 target := m.target(containerID) 142 143 mounted, err := mountinfo.Mounted(target) 144 if err != nil || !mounted { 145 return "", err 146 } 147 return target, nil 148 } 149 150 func (m mounter) target(containerID string) string { 151 return filepath.Join(m.home, "rootfs", m.snapshotter, containerID) 152 }