github.com/rawahars/moby@v24.0.4+incompatible/daemon/snapshotter/mount.go (about)

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