From 6d34c50e898507e461300ecf91ed661011bc15ab Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Tue, 26 Nov 2013 10:50:53 -0800 Subject: [PATCH] Increase max image depth to 127 --- graphdriver/aufs/aufs.go | 54 +++++++++++++++++-------- graphdriver/aufs/aufs_test.go | 71 +++++++++++++++++++++++++++++++++ graphdriver/aufs/mount_linux.go | 2 +- runtime.go | 6 ++- 4 files changed, 113 insertions(+), 20 deletions(-) diff --git a/graphdriver/aufs/aufs.go b/graphdriver/aufs/aufs.go index bd3ad6ebf6..558c64c5bb 100644 --- a/graphdriver/aufs/aufs.go +++ b/graphdriver/aufs/aufs.go @@ -26,11 +26,11 @@ import ( "github.com/dotcloud/docker/archive" "github.com/dotcloud/docker/graphdriver" "github.com/dotcloud/docker/utils" - "log" "os" "os/exec" "path" "strings" + "syscall" ) func init() { @@ -313,24 +313,44 @@ func (a *Driver) Cleanup() error { return nil } -func (a *Driver) aufsMount(ro []string, rw, target string) error { - rwBranch := fmt.Sprintf("%v=rw", rw) - roBranches := "" - for _, layer := range ro { - roBranches += fmt.Sprintf("%v=ro+wh:", layer) - } - branches := fmt.Sprintf("br:%v:%v,xino=/dev/shm/aufs.xino", rwBranch, roBranches) +func (a *Driver) aufsMount(ro []string, rw, target string) (err error) { + defer func() { + if err != nil { + Unmount(target) + } + }() - //if error, try to load aufs kernel module - if err := mount("none", target, "aufs", 0, branches); err != nil { - log.Printf("Kernel does not support AUFS, trying to load the AUFS module with modprobe...") - if err := exec.Command("modprobe", "aufs").Run(); err != nil { - return fmt.Errorf("Unable to load the AUFS module") + if err = a.tryMount(ro, rw, target); err != nil { + if err = a.mountRw(rw, target); err != nil { + return } - log.Printf("...module loaded.") - if err := mount("none", target, "aufs", 0, branches); err != nil { - return fmt.Errorf("Unable to mount using aufs %s", err) + + for _, layer := range ro { + branch := fmt.Sprintf("append:%s=ro+wh", layer) + if err = mount("none", target, "aufs", syscall.MS_REMOUNT, branch); err != nil { + return + } } } - return nil + return +} + +// Try to mount using the aufs fast path, if this fails then +// append ro layers. +func (a *Driver) tryMount(ro []string, rw, target string) (err error) { + var ( + rwBranch = fmt.Sprintf("%s=rw", rw) + roBranches = fmt.Sprintf("%s=ro+wh:", strings.Join(ro, "=ro+wh:")) + ) + return mount("none", target, "aufs", 0, fmt.Sprintf("br:%v:%v,xino=/dev/shm/aufs.xino", rwBranch, roBranches)) +} + +func (a *Driver) mountRw(rw, target string) error { + return mount("none", target, "aufs", 0, fmt.Sprintf("br:%s,xino=/dev/shm/aufs.xino", rw)) +} + +func rollbackMount(target string, err error) { + if err != nil { + Unmount(target) + } } diff --git a/graphdriver/aufs/aufs_test.go b/graphdriver/aufs/aufs_test.go index 2970311389..c43bd74038 100644 --- a/graphdriver/aufs/aufs_test.go +++ b/graphdriver/aufs/aufs_test.go @@ -1,7 +1,11 @@ package aufs import ( + "crypto/sha256" + "encoding/hex" + "fmt" "github.com/dotcloud/docker/archive" + "io/ioutil" "os" "path" "testing" @@ -621,3 +625,70 @@ func TestApplyDiff(t *testing.T) { t.Fatal(err) } } + +func hash(c string) string { + h := sha256.New() + fmt.Fprint(h, c) + return hex.EncodeToString(h.Sum(nil)) +} + +func TestMountMoreThan42Layers(t *testing.T) { + d := newDriver(t) + defer os.RemoveAll(tmp) + defer d.Cleanup() + var last string + var expected int + + for i := 1; i < 127; i++ { + expected++ + var ( + parent = fmt.Sprintf("%d", i-1) + current = fmt.Sprintf("%d", i) + ) + + if parent == "0" { + parent = "" + } else { + parent = hash(parent) + } + current = hash(current) + + if err := d.Create(current, parent); err != nil { + t.Logf("Current layer %d", i) + t.Fatal(err) + } + point, err := d.Get(current) + if err != nil { + t.Logf("Current layer %d", i) + t.Fatal(err) + } + f, err := os.Create(path.Join(point, current)) + if err != nil { + t.Logf("Current layer %d", i) + t.Fatal(err) + } + f.Close() + + if i%10 == 0 { + if err := os.Remove(path.Join(point, parent)); err != nil { + t.Logf("Current layer %d", i) + t.Fatal(err) + } + expected-- + } + last = current + } + + // Perform the actual mount for the top most image + point, err := d.Get(last) + if err != nil { + t.Fatal(err) + } + files, err := ioutil.ReadDir(point) + if err != nil { + t.Fatal(err) + } + if len(files) != expected { + t.Fatalf("Expected %d got %d", expected, len(files)) + } +} diff --git a/graphdriver/aufs/mount_linux.go b/graphdriver/aufs/mount_linux.go index 7122b73cea..8062bae420 100644 --- a/graphdriver/aufs/mount_linux.go +++ b/graphdriver/aufs/mount_linux.go @@ -2,6 +2,6 @@ package aufs import "syscall" -func mount(source string, target string, fstype string, flags uintptr, data string) (err error) { +func mount(source string, target string, fstype string, flags uintptr, data string) error { return syscall.Mount(source, target, fstype, flags, data) } diff --git a/runtime.go b/runtime.go index f58be836bd..175bfa435e 100644 --- a/runtime.go +++ b/runtime.go @@ -24,8 +24,10 @@ import ( "time" ) -// Set the max depth to the aufs restriction -const MaxImageDepth = 42 +// Set the max depth to the aufs default that most +// kernels are compiled with +// For more information see: http://sourceforge.net/p/aufs/aufs3-standalone/ci/aufs3.12/tree/config.mk +const MaxImageDepth = 127 var defaultDns = []string{"8.8.8.8", "8.8.4.4"}