From 670946bf7685c609a7a0067245d64cd8807bd11b Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Mon, 22 Aug 2016 11:43:10 -0700 Subject: [PATCH] Avoid fork on mount for overlay2 in common case In the common case where the user is using /var/lib/docker and an image with less than 60 layers, forking is not needed. Calculate whether absolute paths can be used and avoid forking to mount in those cases. Signed-off-by: Derek McGowan (github: dmcgowan) Upstream-commit: c13a985fa1196a5ed782d5ac68a4bbb68dd529ca Component: engine --- .../daemon/graphdriver/overlay2/mount.go | 4 +-- .../daemon/graphdriver/overlay2/overlay.go | 33 ++++++++++++++++--- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/components/engine/daemon/graphdriver/overlay2/mount.go b/components/engine/daemon/graphdriver/overlay2/mount.go index 44456bbb67..60e248b6d7 100644 --- a/components/engine/daemon/graphdriver/overlay2/mount.go +++ b/components/engine/daemon/graphdriver/overlay2/mount.go @@ -31,12 +31,12 @@ type mountOptions struct { Flag uint32 } -func mountFrom(dir, device, target, mType, label string) error { +func mountFrom(dir, device, target, mType string, flags uintptr, label string) error { options := &mountOptions{ Device: device, Target: target, Type: mType, - Flag: 0, + Flag: uint32(flags), Label: label, } diff --git a/components/engine/daemon/graphdriver/overlay2/overlay.go b/components/engine/daemon/graphdriver/overlay2/overlay.go index 136d058d5d..a348a330b9 100644 --- a/components/engine/daemon/graphdriver/overlay2/overlay.go +++ b/components/engine/daemon/graphdriver/overlay2/overlay.go @@ -409,13 +409,36 @@ func (d *Driver) Get(id string, mountLabel string) (s string, err error) { }() workDir := path.Join(dir, "work") - opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", string(lowers), path.Join(id, "diff"), path.Join(id, "work")) - mountLabel = label.FormatMountLabel(opts, mountLabel) - if len(mountLabel) > syscall.Getpagesize() { - return "", fmt.Errorf("cannot mount layer, mount label too large %d", len(mountLabel)) + splitLowers := strings.Split(string(lowers), ":") + absLowers := make([]string, len(splitLowers)) + for i, s := range splitLowers { + absLowers[i] = path.Join(d.home, s) + } + opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", strings.Join(absLowers, ":"), path.Join(dir, "diff"), path.Join(dir, "work")) + mountData := label.FormatMountLabel(opts, mountLabel) + mount := syscall.Mount + mountTarget := mergedDir + + pageSize := syscall.Getpagesize() + + // Use relative paths and mountFrom when the mount data has exceeded + // the page size. The mount syscall fails if the mount data cannot + // fit within a page and relative links make the mount data much + // smaller at the expense of requiring a fork exec to chroot. + if len(mountData) > pageSize { + opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", string(lowers), path.Join(id, "diff"), path.Join(id, "work")) + mountData = label.FormatMountLabel(opts, mountLabel) + if len(mountData) > pageSize { + return "", fmt.Errorf("cannot mount layer, mount label too large %d", len(mountData)) + } + + mount = func(source string, target string, mType string, flags uintptr, label string) error { + return mountFrom(d.home, source, target, mType, flags, label) + } + mountTarget = path.Join(id, "merged") } - if err := mountFrom(d.home, "overlay", path.Join(id, "merged"), "overlay", mountLabel); err != nil { + if err := mount("overlay", mountTarget, "overlay", 0, mountData); err != nil { return "", fmt.Errorf("error creating overlay mount to %s: %v", mergedDir, err) }