github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/daemon/graphdriver/overlay2/overlay.go (about)

     1  // +build linux
     2  
     3  package overlay2 // import "github.com/docker/docker/daemon/graphdriver/overlay2"
     4  
     5  import (
     6  	"bufio"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"io/ioutil"
    11  	"os"
    12  	"os/exec"
    13  	"path"
    14  	"path/filepath"
    15  	"strconv"
    16  	"strings"
    17  	"sync"
    18  
    19  	"github.com/docker/docker/daemon/graphdriver"
    20  	"github.com/docker/docker/daemon/graphdriver/overlayutils"
    21  	"github.com/docker/docker/daemon/graphdriver/quota"
    22  	"github.com/docker/docker/pkg/archive"
    23  	"github.com/docker/docker/pkg/chrootarchive"
    24  	"github.com/docker/docker/pkg/containerfs"
    25  	"github.com/docker/docker/pkg/directory"
    26  	"github.com/docker/docker/pkg/fsutils"
    27  	"github.com/docker/docker/pkg/idtools"
    28  	"github.com/docker/docker/pkg/locker"
    29  	"github.com/docker/docker/pkg/mount"
    30  	"github.com/docker/docker/pkg/parsers"
    31  	"github.com/docker/docker/pkg/parsers/kernel"
    32  	"github.com/docker/docker/pkg/system"
    33  	"github.com/docker/go-units"
    34  	rsystem "github.com/opencontainers/runc/libcontainer/system"
    35  	"github.com/opencontainers/selinux/go-selinux/label"
    36  	"github.com/sirupsen/logrus"
    37  	"golang.org/x/sys/unix"
    38  )
    39  
    40  var (
    41  	// untar defines the untar method
    42  	untar = chrootarchive.UntarUncompressed
    43  )
    44  
    45  // This backend uses the overlay union filesystem for containers
    46  // with diff directories for each layer.
    47  
    48  // This version of the overlay driver requires at least kernel
    49  // 4.0.0 in order to support mounting multiple diff directories.
    50  
    51  // Each container/image has at least a "diff" directory and "link" file.
    52  // If there is also a "lower" file when there are diff layers
    53  // below as well as "merged" and "work" directories. The "diff" directory
    54  // has the upper layer of the overlay and is used to capture any
    55  // changes to the layer. The "lower" file contains all the lower layer
    56  // mounts separated by ":" and ordered from uppermost to lowermost
    57  // layers. The overlay itself is mounted in the "merged" directory,
    58  // and the "work" dir is needed for overlay to work.
    59  
    60  // The "link" file for each layer contains a unique string for the layer.
    61  // Under the "l" directory at the root there will be a symbolic link
    62  // with that unique string pointing the "diff" directory for the layer.
    63  // The symbolic links are used to reference lower layers in the "lower"
    64  // file and on mount. The links are used to shorten the total length
    65  // of a layer reference without requiring changes to the layer identifier
    66  // or root directory. Mounts are always done relative to root and
    67  // referencing the symbolic links in order to ensure the number of
    68  // lower directories can fit in a single page for making the mount
    69  // syscall. A hard upper limit of 128 lower layers is enforced to ensure
    70  // that mounts do not fail due to length.
    71  
    72  const (
    73  	driverName = "overlay2"
    74  	linkDir    = "l"
    75  	lowerFile  = "lower"
    76  	maxDepth   = 128
    77  
    78  	// idLength represents the number of random characters
    79  	// which can be used to create the unique link identifier
    80  	// for every layer. If this value is too long then the
    81  	// page size limit for the mount command may be exceeded.
    82  	// The idLength should be selected such that following equation
    83  	// is true (512 is a buffer for label metadata).
    84  	// ((idLength + len(linkDir) + 1) * maxDepth) <= (pageSize - 512)
    85  	idLength = 26
    86  )
    87  
    88  type overlayOptions struct {
    89  	overrideKernelCheck bool
    90  	quota               quota.Quota
    91  }
    92  
    93  // Driver contains information about the home directory and the list of active
    94  // mounts that are created using this driver.
    95  type Driver struct {
    96  	home          string
    97  	uidMaps       []idtools.IDMap
    98  	gidMaps       []idtools.IDMap
    99  	ctr           *graphdriver.RefCounter
   100  	quotaCtl      *quota.Control
   101  	options       overlayOptions
   102  	naiveDiff     graphdriver.DiffDriver
   103  	supportsDType bool
   104  	locker        *locker.Locker
   105  }
   106  
   107  var (
   108  	backingFs             = "<unknown>"
   109  	projectQuotaSupported = false
   110  
   111  	useNaiveDiffLock sync.Once
   112  	useNaiveDiffOnly bool
   113  )
   114  
   115  func init() {
   116  	graphdriver.Register(driverName, Init)
   117  }
   118  
   119  // Init returns the native diff driver for overlay filesystem.
   120  // If overlay filesystem is not supported on the host, the error
   121  // graphdriver.ErrNotSupported is returned.
   122  // If an overlay filesystem is not supported over an existing filesystem then
   123  // the error graphdriver.ErrIncompatibleFS is returned.
   124  func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
   125  	opts, err := parseOptions(options)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  
   130  	if err := supportsOverlay(); err != nil {
   131  		return nil, graphdriver.ErrNotSupported
   132  	}
   133  
   134  	// require kernel 4.0.0 to ensure multiple lower dirs are supported
   135  	v, err := kernel.GetKernelVersion()
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  
   140  	// Perform feature detection on /var/lib/docker/overlay2 if it's an existing directory.
   141  	// This covers situations where /var/lib/docker/overlay2 is a mount, and on a different
   142  	// filesystem than /var/lib/docker.
   143  	// If the path does not exist, fall back to using /var/lib/docker for feature detection.
   144  	testdir := home
   145  	if _, err := os.Stat(testdir); os.IsNotExist(err) {
   146  		testdir = filepath.Dir(testdir)
   147  	}
   148  
   149  	fsMagic, err := graphdriver.GetFSMagic(testdir)
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  	if fsName, ok := graphdriver.FsNames[fsMagic]; ok {
   154  		backingFs = fsName
   155  	}
   156  
   157  	switch fsMagic {
   158  	case graphdriver.FsMagicAufs, graphdriver.FsMagicEcryptfs, graphdriver.FsMagicNfsFs, graphdriver.FsMagicOverlay, graphdriver.FsMagicZfs:
   159  		logrus.Errorf("'overlay2' is not supported over %s", backingFs)
   160  		return nil, graphdriver.ErrIncompatibleFS
   161  	case graphdriver.FsMagicBtrfs:
   162  		// Support for OverlayFS on BTRFS was added in kernel 4.7
   163  		// See https://btrfs.wiki.kernel.org/index.php/Changelog
   164  		if kernel.CompareKernelVersion(*v, kernel.VersionInfo{Kernel: 4, Major: 7, Minor: 0}) < 0 {
   165  			if !opts.overrideKernelCheck {
   166  				logrus.Errorf("'overlay2' requires kernel 4.7 to use on %s", backingFs)
   167  				return nil, graphdriver.ErrIncompatibleFS
   168  			}
   169  			logrus.Warn("Using pre-4.7.0 kernel for overlay2 on btrfs, may require kernel update")
   170  		}
   171  	}
   172  
   173  	if kernel.CompareKernelVersion(*v, kernel.VersionInfo{Kernel: 4, Major: 0, Minor: 0}) < 0 {
   174  		if opts.overrideKernelCheck {
   175  			logrus.Warn("Using pre-4.0.0 kernel for overlay2, mount failures may require kernel update")
   176  		} else {
   177  			if err := supportsMultipleLowerDir(testdir); err != nil {
   178  				logrus.Debugf("Multiple lower dirs not supported: %v", err)
   179  				return nil, graphdriver.ErrNotSupported
   180  			}
   181  		}
   182  	}
   183  	supportsDType, err := fsutils.SupportsDType(testdir)
   184  	if err != nil {
   185  		return nil, err
   186  	}
   187  	if !supportsDType {
   188  		if !graphdriver.IsInitialized(home) {
   189  			return nil, overlayutils.ErrDTypeNotSupported("overlay2", backingFs)
   190  		}
   191  		// allow running without d_type only for existing setups (#27443)
   192  		logrus.Warn(overlayutils.ErrDTypeNotSupported("overlay2", backingFs))
   193  	}
   194  
   195  	rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  	// Create the driver home dir
   200  	if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0700, idtools.IDPair{rootUID, rootGID}); err != nil {
   201  		return nil, err
   202  	}
   203  
   204  	d := &Driver{
   205  		home:          home,
   206  		uidMaps:       uidMaps,
   207  		gidMaps:       gidMaps,
   208  		ctr:           graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicOverlay)),
   209  		supportsDType: supportsDType,
   210  		locker:        locker.New(),
   211  		options:       *opts,
   212  	}
   213  
   214  	d.naiveDiff = graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps)
   215  
   216  	if backingFs == "xfs" {
   217  		// Try to enable project quota support over xfs.
   218  		if d.quotaCtl, err = quota.NewControl(home); err == nil {
   219  			projectQuotaSupported = true
   220  		} else if opts.quota.Size > 0 {
   221  			return nil, fmt.Errorf("Storage option overlay2.size not supported. Filesystem does not support Project Quota: %v", err)
   222  		}
   223  	} else if opts.quota.Size > 0 {
   224  		// if xfs is not the backing fs then error out if the storage-opt overlay2.size is used.
   225  		return nil, fmt.Errorf("Storage Option overlay2.size only supported for backingFS XFS. Found %v", backingFs)
   226  	}
   227  
   228  	logrus.Debugf("backingFs=%s,  projectQuotaSupported=%v", backingFs, projectQuotaSupported)
   229  
   230  	return d, nil
   231  }
   232  
   233  func parseOptions(options []string) (*overlayOptions, error) {
   234  	o := &overlayOptions{}
   235  	for _, option := range options {
   236  		key, val, err := parsers.ParseKeyValueOpt(option)
   237  		if err != nil {
   238  			return nil, err
   239  		}
   240  		key = strings.ToLower(key)
   241  		switch key {
   242  		case "overlay2.override_kernel_check":
   243  			o.overrideKernelCheck, err = strconv.ParseBool(val)
   244  			if err != nil {
   245  				return nil, err
   246  			}
   247  		case "overlay2.size":
   248  			size, err := units.RAMInBytes(val)
   249  			if err != nil {
   250  				return nil, err
   251  			}
   252  			o.quota.Size = uint64(size)
   253  		default:
   254  			return nil, fmt.Errorf("overlay2: unknown option %s", key)
   255  		}
   256  	}
   257  	return o, nil
   258  }
   259  
   260  func supportsOverlay() error {
   261  	// We can try to modprobe overlay first before looking at
   262  	// proc/filesystems for when overlay is supported
   263  	exec.Command("modprobe", "overlay").Run()
   264  
   265  	f, err := os.Open("/proc/filesystems")
   266  	if err != nil {
   267  		return err
   268  	}
   269  	defer f.Close()
   270  
   271  	s := bufio.NewScanner(f)
   272  	for s.Scan() {
   273  		if s.Text() == "nodev\toverlay" {
   274  			return nil
   275  		}
   276  	}
   277  	logrus.Error("'overlay' not found as a supported filesystem on this host. Please ensure kernel is new enough and has overlay support loaded.")
   278  	return graphdriver.ErrNotSupported
   279  }
   280  
   281  func useNaiveDiff(home string) bool {
   282  	useNaiveDiffLock.Do(func() {
   283  		if err := doesSupportNativeDiff(home); err != nil {
   284  			logrus.Warnf("Not using native diff for overlay2, this may cause degraded performance for building images: %v", err)
   285  			useNaiveDiffOnly = true
   286  		}
   287  	})
   288  	return useNaiveDiffOnly
   289  }
   290  
   291  func (d *Driver) String() string {
   292  	return driverName
   293  }
   294  
   295  // Status returns current driver information in a two dimensional string array.
   296  // Output contains "Backing Filesystem" used in this implementation.
   297  func (d *Driver) Status() [][2]string {
   298  	return [][2]string{
   299  		{"Backing Filesystem", backingFs},
   300  		{"Supports d_type", strconv.FormatBool(d.supportsDType)},
   301  		{"Native Overlay Diff", strconv.FormatBool(!useNaiveDiff(d.home))},
   302  	}
   303  }
   304  
   305  // GetMetadata returns metadata about the overlay driver such as the LowerDir,
   306  // UpperDir, WorkDir, and MergeDir used to store data.
   307  func (d *Driver) GetMetadata(id string) (map[string]string, error) {
   308  	dir := d.dir(id)
   309  	if _, err := os.Stat(dir); err != nil {
   310  		return nil, err
   311  	}
   312  
   313  	metadata := map[string]string{
   314  		"WorkDir":   path.Join(dir, "work"),
   315  		"MergedDir": path.Join(dir, "merged"),
   316  		"UpperDir":  path.Join(dir, "diff"),
   317  	}
   318  
   319  	lowerDirs, err := d.getLowerDirs(id)
   320  	if err != nil {
   321  		return nil, err
   322  	}
   323  	if len(lowerDirs) > 0 {
   324  		metadata["LowerDir"] = strings.Join(lowerDirs, ":")
   325  	}
   326  
   327  	return metadata, nil
   328  }
   329  
   330  // Cleanup any state created by overlay which should be cleaned when daemon
   331  // is being shutdown. For now, we just have to unmount the bind mounted
   332  // we had created.
   333  func (d *Driver) Cleanup() error {
   334  	return mount.RecursiveUnmount(d.home)
   335  }
   336  
   337  // CreateReadWrite creates a layer that is writable for use as a container
   338  // file system.
   339  func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
   340  	if opts != nil && len(opts.StorageOpt) != 0 && !projectQuotaSupported {
   341  		return fmt.Errorf("--storage-opt is supported only for overlay over xfs with 'pquota' mount option")
   342  	}
   343  
   344  	if opts == nil {
   345  		opts = &graphdriver.CreateOpts{
   346  			StorageOpt: map[string]string{},
   347  		}
   348  	}
   349  
   350  	if _, ok := opts.StorageOpt["size"]; !ok {
   351  		if opts.StorageOpt == nil {
   352  			opts.StorageOpt = map[string]string{}
   353  		}
   354  		opts.StorageOpt["size"] = strconv.FormatUint(d.options.quota.Size, 10)
   355  	}
   356  
   357  	return d.create(id, parent, opts)
   358  }
   359  
   360  // Create is used to create the upper, lower, and merge directories required for overlay fs for a given id.
   361  // The parent filesystem is used to configure these directories for the overlay.
   362  func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr error) {
   363  	if opts != nil && len(opts.StorageOpt) != 0 {
   364  		if _, ok := opts.StorageOpt["size"]; ok {
   365  			return fmt.Errorf("--storage-opt size is only supported for ReadWrite Layers")
   366  		}
   367  	}
   368  	return d.create(id, parent, opts)
   369  }
   370  
   371  func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr error) {
   372  	dir := d.dir(id)
   373  
   374  	rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
   375  	if err != nil {
   376  		return err
   377  	}
   378  	root := idtools.IDPair{UID: rootUID, GID: rootGID}
   379  
   380  	if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil {
   381  		return err
   382  	}
   383  	if err := idtools.MkdirAndChown(dir, 0700, root); err != nil {
   384  		return err
   385  	}
   386  
   387  	defer func() {
   388  		// Clean up on failure
   389  		if retErr != nil {
   390  			os.RemoveAll(dir)
   391  		}
   392  	}()
   393  
   394  	if opts != nil && len(opts.StorageOpt) > 0 {
   395  		driver := &Driver{}
   396  		if err := d.parseStorageOpt(opts.StorageOpt, driver); err != nil {
   397  			return err
   398  		}
   399  
   400  		if driver.options.quota.Size > 0 {
   401  			// Set container disk quota limit
   402  			if err := d.quotaCtl.SetQuota(dir, driver.options.quota); err != nil {
   403  				return err
   404  			}
   405  		}
   406  	}
   407  
   408  	if err := idtools.MkdirAndChown(path.Join(dir, "diff"), 0755, root); err != nil {
   409  		return err
   410  	}
   411  
   412  	lid := generateID(idLength)
   413  	if err := os.Symlink(path.Join("..", id, "diff"), path.Join(d.home, linkDir, lid)); err != nil {
   414  		return err
   415  	}
   416  
   417  	// Write link id to link file
   418  	if err := ioutil.WriteFile(path.Join(dir, "link"), []byte(lid), 0644); err != nil {
   419  		return err
   420  	}
   421  
   422  	// if no parent directory, done
   423  	if parent == "" {
   424  		return nil
   425  	}
   426  
   427  	if err := idtools.MkdirAndChown(path.Join(dir, "work"), 0700, root); err != nil {
   428  		return err
   429  	}
   430  
   431  	lower, err := d.getLower(parent)
   432  	if err != nil {
   433  		return err
   434  	}
   435  	if lower != "" {
   436  		if err := ioutil.WriteFile(path.Join(dir, lowerFile), []byte(lower), 0666); err != nil {
   437  			return err
   438  		}
   439  	}
   440  
   441  	return nil
   442  }
   443  
   444  // Parse overlay storage options
   445  func (d *Driver) parseStorageOpt(storageOpt map[string]string, driver *Driver) error {
   446  	// Read size to set the disk project quota per container
   447  	for key, val := range storageOpt {
   448  		key := strings.ToLower(key)
   449  		switch key {
   450  		case "size":
   451  			size, err := units.RAMInBytes(val)
   452  			if err != nil {
   453  				return err
   454  			}
   455  			driver.options.quota.Size = uint64(size)
   456  		default:
   457  			return fmt.Errorf("Unknown option %s", key)
   458  		}
   459  	}
   460  
   461  	return nil
   462  }
   463  
   464  func (d *Driver) getLower(parent string) (string, error) {
   465  	parentDir := d.dir(parent)
   466  
   467  	// Ensure parent exists
   468  	if _, err := os.Lstat(parentDir); err != nil {
   469  		return "", err
   470  	}
   471  
   472  	// Read Parent link fileA
   473  	parentLink, err := ioutil.ReadFile(path.Join(parentDir, "link"))
   474  	if err != nil {
   475  		return "", err
   476  	}
   477  	lowers := []string{path.Join(linkDir, string(parentLink))}
   478  
   479  	parentLower, err := ioutil.ReadFile(path.Join(parentDir, lowerFile))
   480  	if err == nil {
   481  		parentLowers := strings.Split(string(parentLower), ":")
   482  		lowers = append(lowers, parentLowers...)
   483  	}
   484  	if len(lowers) > maxDepth {
   485  		return "", errors.New("max depth exceeded")
   486  	}
   487  	return strings.Join(lowers, ":"), nil
   488  }
   489  
   490  func (d *Driver) dir(id string) string {
   491  	return path.Join(d.home, id)
   492  }
   493  
   494  func (d *Driver) getLowerDirs(id string) ([]string, error) {
   495  	var lowersArray []string
   496  	lowers, err := ioutil.ReadFile(path.Join(d.dir(id), lowerFile))
   497  	if err == nil {
   498  		for _, s := range strings.Split(string(lowers), ":") {
   499  			lp, err := os.Readlink(path.Join(d.home, s))
   500  			if err != nil {
   501  				return nil, err
   502  			}
   503  			lowersArray = append(lowersArray, path.Clean(path.Join(d.home, linkDir, lp)))
   504  		}
   505  	} else if !os.IsNotExist(err) {
   506  		return nil, err
   507  	}
   508  	return lowersArray, nil
   509  }
   510  
   511  // Remove cleans the directories that are created for this id.
   512  func (d *Driver) Remove(id string) error {
   513  	d.locker.Lock(id)
   514  	defer d.locker.Unlock(id)
   515  	dir := d.dir(id)
   516  	lid, err := ioutil.ReadFile(path.Join(dir, "link"))
   517  	if err == nil {
   518  		if err := os.RemoveAll(path.Join(d.home, linkDir, string(lid))); err != nil {
   519  			logrus.Debugf("Failed to remove link: %v", err)
   520  		}
   521  	}
   522  
   523  	if err := system.EnsureRemoveAll(dir); err != nil && !os.IsNotExist(err) {
   524  		return err
   525  	}
   526  	return nil
   527  }
   528  
   529  // Get creates and mounts the required file system for the given id and returns the mount path.
   530  func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr error) {
   531  	d.locker.Lock(id)
   532  	defer d.locker.Unlock(id)
   533  	dir := d.dir(id)
   534  	if _, err := os.Stat(dir); err != nil {
   535  		return nil, err
   536  	}
   537  
   538  	diffDir := path.Join(dir, "diff")
   539  	lowers, err := ioutil.ReadFile(path.Join(dir, lowerFile))
   540  	if err != nil {
   541  		// If no lower, just return diff directory
   542  		if os.IsNotExist(err) {
   543  			return containerfs.NewLocalContainerFS(diffDir), nil
   544  		}
   545  		return nil, err
   546  	}
   547  
   548  	mergedDir := path.Join(dir, "merged")
   549  	if count := d.ctr.Increment(mergedDir); count > 1 {
   550  		return containerfs.NewLocalContainerFS(mergedDir), nil
   551  	}
   552  	defer func() {
   553  		if retErr != nil {
   554  			if c := d.ctr.Decrement(mergedDir); c <= 0 {
   555  				if mntErr := unix.Unmount(mergedDir, 0); mntErr != nil {
   556  					logrus.Errorf("error unmounting %v: %v", mergedDir, mntErr)
   557  				}
   558  				// Cleanup the created merged directory; see the comment in Put's rmdir
   559  				if rmErr := unix.Rmdir(mergedDir); rmErr != nil && !os.IsNotExist(rmErr) {
   560  					logrus.Debugf("Failed to remove %s: %v: %v", id, rmErr, err)
   561  				}
   562  			}
   563  		}
   564  	}()
   565  
   566  	workDir := path.Join(dir, "work")
   567  	splitLowers := strings.Split(string(lowers), ":")
   568  	absLowers := make([]string, len(splitLowers))
   569  	for i, s := range splitLowers {
   570  		absLowers[i] = path.Join(d.home, s)
   571  	}
   572  	opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", strings.Join(absLowers, ":"), path.Join(dir, "diff"), path.Join(dir, "work"))
   573  	mountData := label.FormatMountLabel(opts, mountLabel)
   574  	mount := unix.Mount
   575  	mountTarget := mergedDir
   576  
   577  	rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
   578  	if err != nil {
   579  		return nil, err
   580  	}
   581  	if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.IDPair{rootUID, rootGID}); err != nil {
   582  		return nil, err
   583  	}
   584  
   585  	pageSize := unix.Getpagesize()
   586  
   587  	// Go can return a larger page size than supported by the system
   588  	// as of go 1.7. This will be fixed in 1.8 and this block can be
   589  	// removed when building with 1.8.
   590  	// See https://github.com/golang/go/commit/1b9499b06989d2831e5b156161d6c07642926ee1
   591  	// See https://github.com/docker/docker/issues/27384
   592  	if pageSize > 4096 {
   593  		pageSize = 4096
   594  	}
   595  
   596  	// Use relative paths and mountFrom when the mount data has exceeded
   597  	// the page size. The mount syscall fails if the mount data cannot
   598  	// fit within a page and relative links make the mount data much
   599  	// smaller at the expense of requiring a fork exec to chroot.
   600  	if len(mountData) > pageSize {
   601  		opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", string(lowers), path.Join(id, "diff"), path.Join(id, "work"))
   602  		mountData = label.FormatMountLabel(opts, mountLabel)
   603  		if len(mountData) > pageSize {
   604  			return nil, fmt.Errorf("cannot mount layer, mount label too large %d", len(mountData))
   605  		}
   606  
   607  		mount = func(source string, target string, mType string, flags uintptr, label string) error {
   608  			return mountFrom(d.home, source, target, mType, flags, label)
   609  		}
   610  		mountTarget = path.Join(id, "merged")
   611  	}
   612  
   613  	if err := mount("overlay", mountTarget, "overlay", 0, mountData); err != nil {
   614  		return nil, fmt.Errorf("error creating overlay mount to %s: %v", mergedDir, err)
   615  	}
   616  
   617  	// chown "workdir/work" to the remapped root UID/GID. Overlay fs inside a
   618  	// user namespace requires this to move a directory from lower to upper.
   619  	if err := os.Chown(path.Join(workDir, "work"), rootUID, rootGID); err != nil {
   620  		return nil, err
   621  	}
   622  
   623  	return containerfs.NewLocalContainerFS(mergedDir), nil
   624  }
   625  
   626  // Put unmounts the mount path created for the give id.
   627  // It also removes the 'merged' directory to force the kernel to unmount the
   628  // overlay mount in other namespaces.
   629  func (d *Driver) Put(id string) error {
   630  	d.locker.Lock(id)
   631  	defer d.locker.Unlock(id)
   632  	dir := d.dir(id)
   633  	_, err := ioutil.ReadFile(path.Join(dir, lowerFile))
   634  	if err != nil {
   635  		// If no lower, no mount happened and just return directly
   636  		if os.IsNotExist(err) {
   637  			return nil
   638  		}
   639  		return err
   640  	}
   641  
   642  	mountpoint := path.Join(dir, "merged")
   643  	if count := d.ctr.Decrement(mountpoint); count > 0 {
   644  		return nil
   645  	}
   646  	if err := unix.Unmount(mountpoint, unix.MNT_DETACH); err != nil {
   647  		logrus.Debugf("Failed to unmount %s overlay: %s - %v", id, mountpoint, err)
   648  	}
   649  	// Remove the mountpoint here. Removing the mountpoint (in newer kernels)
   650  	// will cause all other instances of this mount in other mount namespaces
   651  	// to be unmounted. This is necessary to avoid cases where an overlay mount
   652  	// that is present in another namespace will cause subsequent mounts
   653  	// operations to fail with ebusy.  We ignore any errors here because this may
   654  	// fail on older kernels which don't have
   655  	// torvalds/linux@8ed936b5671bfb33d89bc60bdcc7cf0470ba52fe applied.
   656  	if err := unix.Rmdir(mountpoint); err != nil && !os.IsNotExist(err) {
   657  		logrus.Debugf("Failed to remove %s overlay: %v", id, err)
   658  	}
   659  	return nil
   660  }
   661  
   662  // Exists checks to see if the id is already mounted.
   663  func (d *Driver) Exists(id string) bool {
   664  	_, err := os.Stat(d.dir(id))
   665  	return err == nil
   666  }
   667  
   668  // isParent determines whether the given parent is the direct parent of the
   669  // given layer id
   670  func (d *Driver) isParent(id, parent string) bool {
   671  	lowers, err := d.getLowerDirs(id)
   672  	if err != nil {
   673  		return false
   674  	}
   675  	if parent == "" && len(lowers) > 0 {
   676  		return false
   677  	}
   678  
   679  	parentDir := d.dir(parent)
   680  	var ld string
   681  	if len(lowers) > 0 {
   682  		ld = filepath.Dir(lowers[0])
   683  	}
   684  	if ld == "" && parent == "" {
   685  		return true
   686  	}
   687  	return ld == parentDir
   688  }
   689  
   690  // ApplyDiff applies the new layer into a root
   691  func (d *Driver) ApplyDiff(id string, parent string, diff io.Reader) (size int64, err error) {
   692  	if !d.isParent(id, parent) {
   693  		return d.naiveDiff.ApplyDiff(id, parent, diff)
   694  	}
   695  
   696  	applyDir := d.getDiffPath(id)
   697  
   698  	logrus.Debugf("Applying tar in %s", applyDir)
   699  	// Overlay doesn't need the parent id to apply the diff
   700  	if err := untar(diff, applyDir, &archive.TarOptions{
   701  		UIDMaps:        d.uidMaps,
   702  		GIDMaps:        d.gidMaps,
   703  		WhiteoutFormat: archive.OverlayWhiteoutFormat,
   704  		InUserNS:       rsystem.RunningInUserNS(),
   705  	}); err != nil {
   706  		return 0, err
   707  	}
   708  
   709  	return directory.Size(applyDir)
   710  }
   711  
   712  func (d *Driver) getDiffPath(id string) string {
   713  	dir := d.dir(id)
   714  
   715  	return path.Join(dir, "diff")
   716  }
   717  
   718  // DiffSize calculates the changes between the specified id
   719  // and its parent and returns the size in bytes of the changes
   720  // relative to its base filesystem directory.
   721  func (d *Driver) DiffSize(id, parent string) (size int64, err error) {
   722  	if useNaiveDiff(d.home) || !d.isParent(id, parent) {
   723  		return d.naiveDiff.DiffSize(id, parent)
   724  	}
   725  	return directory.Size(d.getDiffPath(id))
   726  }
   727  
   728  // Diff produces an archive of the changes between the specified
   729  // layer and its parent layer which may be "".
   730  func (d *Driver) Diff(id, parent string) (io.ReadCloser, error) {
   731  	if useNaiveDiff(d.home) || !d.isParent(id, parent) {
   732  		return d.naiveDiff.Diff(id, parent)
   733  	}
   734  
   735  	diffPath := d.getDiffPath(id)
   736  	logrus.Debugf("Tar with options on %s", diffPath)
   737  	return archive.TarWithOptions(diffPath, &archive.TarOptions{
   738  		Compression:    archive.Uncompressed,
   739  		UIDMaps:        d.uidMaps,
   740  		GIDMaps:        d.gidMaps,
   741  		WhiteoutFormat: archive.OverlayWhiteoutFormat,
   742  	})
   743  }
   744  
   745  // Changes produces a list of changes between the specified layer and its
   746  // parent layer. If parent is "", then all changes will be ADD changes.
   747  func (d *Driver) Changes(id, parent string) ([]archive.Change, error) {
   748  	if useNaiveDiff(d.home) || !d.isParent(id, parent) {
   749  		return d.naiveDiff.Changes(id, parent)
   750  	}
   751  	// Overlay doesn't have snapshots, so we need to get changes from all parent
   752  	// layers.
   753  	diffPath := d.getDiffPath(id)
   754  	layers, err := d.getLowerDirs(id)
   755  	if err != nil {
   756  		return nil, err
   757  	}
   758  
   759  	return archive.OverlayChanges(layers, diffPath)
   760  }