mount.go 4.2 KB

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