mount.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. package snapshotter
  2. import (
  3. "context"
  4. "os"
  5. "path/filepath"
  6. "github.com/containerd/containerd/log"
  7. "github.com/containerd/containerd/mount"
  8. "github.com/docker/docker/daemon/graphdriver"
  9. "github.com/docker/docker/pkg/idtools"
  10. "github.com/moby/locker"
  11. )
  12. const mountsDir = "rootfs"
  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. }
  23. // inSlice tests whether a string is contained in a slice of strings or not.
  24. // Comparison is case sensitive
  25. func inSlice(slice []string, s string) bool {
  26. for _, ss := range slice {
  27. if s == ss {
  28. return true
  29. }
  30. }
  31. return false
  32. }
  33. // NewMounter creates a new mounter for the provided snapshotter
  34. func NewMounter(home string, snapshotter string, idMap idtools.IdentityMapping) Mounter {
  35. if inSlice(refCountedFileSystems, snapshotter) {
  36. return &refCountMounter{
  37. home: home,
  38. snapshotter: snapshotter,
  39. rc: graphdriver.NewRefCounter(checker()),
  40. locker: locker.New(),
  41. idMap: idMap,
  42. }
  43. }
  44. return mounter{
  45. home: home,
  46. snapshotter: snapshotter,
  47. idMap: idMap,
  48. }
  49. }
  50. type refCountMounter struct {
  51. home string
  52. snapshotter string
  53. rc *graphdriver.RefCounter
  54. locker *locker.Locker
  55. idMap idtools.IdentityMapping
  56. }
  57. func (m *refCountMounter) Mount(mounts []mount.Mount, containerID string) (target string, retErr error) {
  58. target = filepath.Join(m.home, mountsDir, m.snapshotter, containerID)
  59. _, err := os.Stat(target)
  60. if err != nil && !os.IsNotExist(err) {
  61. return "", err
  62. }
  63. if count := m.rc.Increment(target); count > 1 {
  64. return target, nil
  65. }
  66. m.locker.Lock(target)
  67. defer m.locker.Unlock(target)
  68. defer func() {
  69. if retErr != nil {
  70. if c := m.rc.Decrement(target); c <= 0 {
  71. if mntErr := unmount(target); mntErr != nil {
  72. log.G(context.TODO()).Errorf("error unmounting %s: %v", target, mntErr)
  73. }
  74. if rmErr := os.Remove(target); rmErr != nil && !os.IsNotExist(rmErr) {
  75. log.G(context.TODO()).Debugf("Failed to remove %s: %v: %v", target, rmErr, err)
  76. }
  77. }
  78. }
  79. }()
  80. root := m.idMap.RootPair()
  81. if err := idtools.MkdirAllAndChown(target, 0700, root); err != nil {
  82. return "", err
  83. }
  84. return target, mount.All(mounts, target)
  85. }
  86. func (m *refCountMounter) Unmount(target string) error {
  87. if count := m.rc.Decrement(target); count > 0 {
  88. return nil
  89. }
  90. m.locker.Lock(target)
  91. defer m.locker.Unlock(target)
  92. if err := unmount(target); err != nil {
  93. log.G(context.TODO()).Debugf("Failed to unmount %s: %v", target, err)
  94. }
  95. if err := os.Remove(target); err != nil {
  96. log.G(context.TODO()).WithError(err).WithField("dir", target).Error("failed to remove mount temp dir")
  97. }
  98. return nil
  99. }
  100. type mounter struct {
  101. home string
  102. snapshotter string
  103. idMap idtools.IdentityMapping
  104. }
  105. func (m mounter) Mount(mounts []mount.Mount, containerID string) (string, error) {
  106. target := filepath.Join(m.home, mountsDir, m.snapshotter, containerID)
  107. root := m.idMap.RootPair()
  108. if err := idtools.MkdirAndChown(target, 0700, root); err != nil {
  109. return "", err
  110. }
  111. return target, mount.All(mounts, target)
  112. }
  113. func (m mounter) Unmount(target string) error {
  114. return unmount(target)
  115. }