123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- 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"
- )
- // 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
- // Mounted returns a target mountpoint if it's already mounted
- Mounted(containerID string) (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 {
- mnter := mounter{
- home: home,
- snapshotter: snapshotter,
- idMap: idMap,
- }
- if inSlice(refCountedFileSystems, snapshotter) {
- return &refCountMounter{
- base: mnter,
- rc: graphdriver.NewRefCounter(checker()),
- locker: locker.New(),
- }
- }
- return &mnter
- }
- 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)
- }
|