Merge pull request #9151 from tonistiigi/aufs-clipping-fix

Fix AUFS silent mount errors on many layers
This commit is contained in:
Michael Crosby 2014-11-14 17:35:07 -08:00
commit 8682bac309
2 changed files with 64 additions and 33 deletions

View file

@ -412,39 +412,44 @@ func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err erro
}
}()
if err = a.tryMount(ro, rw, target, mountLabel); err != nil {
if err = a.mountRw(rw, target, mountLabel); err != nil {
return
}
// Mount options are clipped to page size(4096 bytes). If there are more
// layers then these are remounted individually using append.
for _, layer := range ro {
data := label.FormatMountLabel(fmt.Sprintf("append:%s=ro+wh", layer), mountLabel)
if err = mount("none", target, "aufs", MsRemount, data); err != nil {
return
b := make([]byte, syscall.Getpagesize()-len(mountLabel)-50) // room for xino & mountLabel
bp := copy(b, fmt.Sprintf("br:%s=rw", rw))
firstMount := true
i := 0
for {
for ; i < len(ro); i++ {
layer := fmt.Sprintf(":%s=ro+wh", ro[i])
if firstMount {
if bp+len(layer) > len(b) {
break
}
bp += copy(b[bp:], layer)
} else {
data := label.FormatMountLabel(fmt.Sprintf("append%s", layer), mountLabel)
if err = mount("none", target, "aufs", MsRemount, data); err != nil {
return
}
}
}
if firstMount {
data := label.FormatMountLabel(fmt.Sprintf("%s,xino=/dev/shm/aufs.xino", string(b[:bp])), mountLabel)
if err = mount("none", target, "aufs", 0, data); err != nil {
return
}
firstMount = false
}
if i == len(ro) {
break
}
}
return
}
// Try to mount using the aufs fast path, if this fails then
// append ro layers.
func (a *Driver) tryMount(ro []string, rw, target, mountLabel string) (err error) {
var (
rwBranch = fmt.Sprintf("%s=rw", rw)
roBranches = fmt.Sprintf("%s=ro+wh:", strings.Join(ro, "=ro+wh:"))
data = label.FormatMountLabel(fmt.Sprintf("br:%v:%v,xino=/dev/shm/aufs.xino", rwBranch, roBranches), mountLabel)
)
return mount("none", target, "aufs", 0, data)
}
func (a *Driver) mountRw(rw, target, mountLabel string) error {
data := label.FormatMountLabel(fmt.Sprintf("br:%s,xino=/dev/shm/aufs.xino", rw), mountLabel)
return mount("none", target, "aufs", 0, data)
}
func rollbackMount(target string, err error) {
if err != nil {
Unmount(target)
}
}

View file

@ -635,9 +635,13 @@ func hash(c string) string {
return hex.EncodeToString(h.Sum(nil))
}
func TestMountMoreThan42Layers(t *testing.T) {
d := newDriver(t)
defer os.RemoveAll(tmp)
func testMountMoreThan42Layers(t *testing.T, mountPath string) {
if err := os.MkdirAll(mountPath, 0755); err != nil {
t.Fatal(err)
}
d := testInit(mountPath, t).(*Driver)
defer os.RemoveAll(mountPath)
defer d.Cleanup()
var last string
var expected int
@ -695,3 +699,25 @@ func TestMountMoreThan42Layers(t *testing.T) {
t.Fatalf("Expected %d got %d", expected, len(files))
}
}
func TestMountMoreThan42Layers(t *testing.T) {
testMountMoreThan42Layers(t, tmp)
}
func TestMountMoreThan42LayersMatchingPathLength(t *testing.T) {
tmp := "aufs-tests"
for {
// This finds a mount path so that when combined into aufs mount options
// 4096 byte boundary would be in between the paths or in permission
// section. For '/tmp' it will use '/tmp/aufs-tests00000000/aufs'
mountPath := path.Join(os.TempDir(), tmp, "aufs")
pathLength := 77 + len(mountPath)
if mod := 4095 % pathLength; mod == 0 || mod > pathLength-2 {
t.Logf("Using path: %s", mountPath)
testMountMoreThan42Layers(t, mountPath)
return
}
tmp += "0"
}
}