github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/daemon/graphdriver/overlay2/overlay.go (about)

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