Skip to content

Commit b9cd7b5

Browse files
authored
Merge pull request adamlaska#261 from kolyshkin/19.03-aufs-lock
[19.03 backport ENGCORE-831] aufs optimizations moby#39107
2 parents ceb773e + a81278b commit b9cd7b5

2 files changed

Lines changed: 65 additions & 35 deletions

File tree

daemon/graphdriver/aufs/aufs.go

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ func init() {
7272

7373
// Driver contains information about the filesystem mounted.
7474
type Driver struct {
75-
sync.Mutex
7675
root string
7776
uidMaps []idtools.IDMap
7877
gidMaps []idtools.IDMap
@@ -81,6 +80,7 @@ type Driver struct {
8180
pathCache map[string]string
8281
naiveDiff graphdriver.DiffDriver
8382
locker *locker.Locker
83+
mntL sync.Mutex
8484
}
8585

8686
// Init returns a new AUFS driver.
@@ -327,11 +327,11 @@ func (a *Driver) Remove(id string) error {
327327
break
328328
}
329329

330-
if err != unix.EBUSY {
331-
return errors.Wrapf(err, "aufs: unmount error: %s", mountpoint)
330+
if errors.Cause(err) != unix.EBUSY {
331+
return errors.Wrap(err, "aufs: unmount error")
332332
}
333333
if retries >= 5 {
334-
return errors.Wrapf(err, "aufs: unmount error after retries: %s", mountpoint)
334+
return errors.Wrap(err, "aufs: unmount error after retries")
335335
}
336336
// If unmount returns EBUSY, it could be a transient error. Sleep and retry.
337337
retries++
@@ -437,7 +437,7 @@ func (a *Driver) Put(id string) error {
437437

438438
err := a.unmount(m)
439439
if err != nil {
440-
logger.Debugf("Failed to unmount %s aufs: %v", id, err)
440+
logger.WithError(err).WithField("method", "Put()").Warn()
441441
}
442442
return err
443443
}
@@ -547,9 +547,6 @@ func (a *Driver) getParentLayerPaths(id string) ([]string, error) {
547547
}
548548

549549
func (a *Driver) mount(id string, target string, mountLabel string, layers []string) error {
550-
a.Lock()
551-
defer a.Unlock()
552-
553550
// If the id is mounted or we get an error return
554551
if mounted, err := a.mounted(target); err != nil || mounted {
555552
return err
@@ -564,9 +561,6 @@ func (a *Driver) mount(id string, target string, mountLabel string, layers []str
564561
}
565562

566563
func (a *Driver) unmount(mountPath string) error {
567-
a.Lock()
568-
defer a.Unlock()
569-
570564
if mounted, err := a.mounted(mountPath); err != nil || !mounted {
571565
return err
572566
}
@@ -579,23 +573,20 @@ func (a *Driver) mounted(mountpoint string) (bool, error) {
579573

580574
// Cleanup aufs and unmount all mountpoints
581575
func (a *Driver) Cleanup() error {
582-
var dirs []string
583-
if err := filepath.Walk(a.mntPath(), func(path string, info os.FileInfo, err error) error {
584-
if err != nil {
585-
return err
586-
}
587-
if !info.IsDir() {
588-
return nil
589-
}
590-
dirs = append(dirs, path)
591-
return nil
592-
}); err != nil {
593-
return err
576+
dir := a.mntPath()
577+
files, err := ioutil.ReadDir(dir)
578+
if err != nil {
579+
return errors.Wrap(err, "aufs readdir error")
594580
}
581+
for _, f := range files {
582+
if !f.IsDir() {
583+
continue
584+
}
585+
586+
m := path.Join(dir, f.Name())
595587

596-
for _, m := range dirs {
597588
if err := a.unmount(m); err != nil {
598-
logger.Debugf("error unmounting %s: %s", m, err)
589+
logger.WithError(err).WithField("method", "Cleanup()").Warn()
599590
}
600591
}
601592
return mount.RecursiveUnmount(a.root)
@@ -604,7 +595,7 @@ func (a *Driver) Cleanup() error {
604595
func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err error) {
605596
defer func() {
606597
if err != nil {
607-
Unmount(target)
598+
mount.Unmount(target)
608599
}
609600
}()
610601

@@ -632,14 +623,29 @@ func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err erro
632623
opts += ",dirperm1"
633624
}
634625
data := label.FormatMountLabel(fmt.Sprintf("%s,%s", string(b[:bp]), opts), mountLabel)
635-
if err = unix.Mount("none", target, "aufs", 0, data); err != nil {
626+
a.mntL.Lock()
627+
err = unix.Mount("none", target, "aufs", 0, data)
628+
a.mntL.Unlock()
629+
if err != nil {
630+
err = errors.Wrap(err, "mount target="+target+" data="+data)
636631
return
637632
}
638633

639-
for ; index < len(ro); index++ {
640-
layer := fmt.Sprintf(":%s=ro+wh", ro[index])
641-
data := label.FormatMountLabel(fmt.Sprintf("append%s", layer), mountLabel)
642-
if err = unix.Mount("none", target, "aufs", unix.MS_REMOUNT, data); err != nil {
634+
for index < len(ro) {
635+
bp = 0
636+
for ; index < len(ro); index++ {
637+
layer := fmt.Sprintf("append:%s=ro+wh,", ro[index])
638+
if bp+len(layer) > len(b) {
639+
break
640+
}
641+
bp += copy(b[bp:], layer)
642+
}
643+
data := label.FormatMountLabel(string(b[:bp]), mountLabel)
644+
a.mntL.Lock()
645+
err = unix.Mount("none", target, "aufs", unix.MS_REMOUNT, data)
646+
a.mntL.Unlock()
647+
if err != nil {
648+
err = errors.Wrap(err, "mount target="+target+" flags=MS_REMOUNT data="+data)
643649
return
644650
}
645651
}

daemon/graphdriver/aufs/mount.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,38 @@ package aufs // import "github.com/docker/docker/daemon/graphdriver/aufs"
44

55
import (
66
"os/exec"
7+
"syscall"
78

8-
"golang.org/x/sys/unix"
9+
"github.com/docker/docker/pkg/mount"
910
)
1011

1112
// Unmount the target specified.
1213
func Unmount(target string) error {
13-
if err := exec.Command("auplink", target, "flush").Run(); err != nil {
14-
logger.WithError(err).Warnf("Couldn't run auplink before unmount %s", target)
14+
const (
15+
EINVAL = 22 // if auplink returns this,
16+
retries = 3 // retry a few times
17+
)
18+
19+
for i := 0; ; i++ {
20+
out, err := exec.Command("auplink", target, "flush").CombinedOutput()
21+
if err == nil {
22+
break
23+
}
24+
rc := 0
25+
if exiterr, ok := err.(*exec.ExitError); ok {
26+
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
27+
rc = status.ExitStatus()
28+
}
29+
}
30+
if i >= retries || rc != EINVAL {
31+
logger.WithError(err).WithField("method", "Unmount").Warnf("auplink flush failed: %s", out)
32+
break
33+
}
34+
// auplink failed to find target in /proc/self/mounts because
35+
// kernel can't guarantee continuity while reading from it
36+
// while mounts table is being changed
37+
logger.Debugf("auplink flush error (retrying %d/%d): %s", i+1, retries, out)
1538
}
16-
return unix.Unmount(target, 0)
39+
40+
return mount.Unmount(target)
1741
}

0 commit comments

Comments
 (0)