Skip to content

Commit 1533b68

Browse files
dmcgowanruncom
authored andcommitted
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 <derek@mcgstyle.net> (github: dmcgowan)
1 parent 85d7426 commit 1533b68

2 files changed

Lines changed: 30 additions & 7 deletions

File tree

daemon/graphdriver/overlay2/mount.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ type mountOptions struct {
3131
Flag uint32
3232
}
3333

34-
func mountFrom(dir, device, target, mType, label string) error {
34+
func mountFrom(dir, device, target, mType string, flags uintptr, label string) error {
3535
options := &mountOptions{
3636
Device: device,
3737
Target: target,
3838
Type: mType,
39-
Flag: 0,
39+
Flag: uint32(flags),
4040
Label: label,
4141
}
4242

daemon/graphdriver/overlay2/overlay.go

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -483,13 +483,36 @@ func (d *Driver) Get(id string, mountLabel string) (s string, err error) {
483483
}()
484484

485485
workDir := path.Join(dir, "work")
486-
opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", string(lowers), path.Join(id, "diff"), path.Join(id, "work"))
487-
mountLabel = label.FormatMountLabel(opts, mountLabel)
488-
if len(mountLabel) > syscall.Getpagesize() {
489-
return "", fmt.Errorf("cannot mount layer, mount label too large %d", len(mountLabel))
486+
splitLowers := strings.Split(string(lowers), ":")
487+
absLowers := make([]string, len(splitLowers))
488+
for i, s := range splitLowers {
489+
absLowers[i] = path.Join(d.home, s)
490+
}
491+
opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", strings.Join(absLowers, ":"), path.Join(dir, "diff"), path.Join(dir, "work"))
492+
mountData := label.FormatMountLabel(opts, mountLabel)
493+
mount := syscall.Mount
494+
mountTarget := mergedDir
495+
496+
pageSize := syscall.Getpagesize()
497+
498+
// Use relative paths and mountFrom when the mount data has exceeded
499+
// the page size. The mount syscall fails if the mount data cannot
500+
// fit within a page and relative links make the mount data much
501+
// smaller at the expense of requiring a fork exec to chroot.
502+
if len(mountData) > pageSize {
503+
opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", string(lowers), path.Join(id, "diff"), path.Join(id, "work"))
504+
mountData = label.FormatMountLabel(opts, mountLabel)
505+
if len(mountData) > pageSize {
506+
return "", fmt.Errorf("cannot mount layer, mount label too large %d", len(mountData))
507+
}
508+
509+
mount = func(source string, target string, mType string, flags uintptr, label string) error {
510+
return mountFrom(d.home, source, target, mType, flags, label)
511+
}
512+
mountTarget = path.Join(id, "merged")
490513
}
491514

492-
if err := mountFrom(d.home, "overlay", path.Join(id, "merged"), "overlay", mountLabel); err != nil {
515+
if err := mount("overlay", mountTarget, "overlay", 0, mountData); err != nil {
493516
return "", fmt.Errorf("error creating overlay mount to %s: %v", mergedDir, err)
494517
}
495518

0 commit comments

Comments
 (0)