Skip to content

Commit 34f9de9

Browse files
committed
fix: wcow: fix race condition in localmounter
> WIP: still ongoing with investigation to determine > exactly which process is accessing the file, will > update on the issue #5807 thread for the records. Fix the race condition with maximum 2 retries. From several tests, 1 retry seems to be enough, even without backoff. Added a simple linear backoff for each retry starting at 30 ms. fixes #5807 Signed-off-by: Anthony Nandaa <profnandaa@gmail.com>
1 parent 648ec56 commit 34f9de9

File tree

1 file changed

+29
-3
lines changed

1 file changed

+29
-3
lines changed

snapshot/localmounter_windows.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package snapshot
22

33
import (
44
"os"
5+
"strings"
6+
"time"
57

68
"github.com/Microsoft/go-winio/pkg/bindfilter"
79
"github.com/containerd/containerd/v2/core/mount"
@@ -46,18 +48,42 @@ func (lm *localMounter) Mount() (string, error) {
4648
// The Windows snapshotter does not have any notion of bind mounts. We emulate
4749
// bind mounts here using the bind filter.
4850
if err := bindfilter.ApplyFileBinding(dir, m.Source, m.ReadOnly()); err != nil {
49-
return "", errors.Wrapf(err, "failed to mount %v: %+v", m, err)
51+
return "", errors.Wrapf(err, "failed to mount %v", m)
5052
}
5153
} else {
52-
if err := m.Mount(dir); err != nil {
53-
return "", errors.Wrapf(err, "failed to mount %v: %+v", m, err)
54+
// see https://github.com/moby/buildkit/issues/5807
55+
// if it's a race condition issue, do max 2 retries with some small backoff
56+
// should adjust the retries if this persists but 1 retry
57+
// seems to be enough.
58+
if err := mountWithRetries(m, dir, 2); err != nil {
59+
return "", errors.Wrapf(err, "failed to mount %v", m)
5460
}
5561
}
5662

5763
lm.target = dir
5864
return lm.target, nil
5965
}
6066

67+
func mountWithRetries(m mount.Mount, dir string, retries int) error {
68+
errStr := "cannot access the file because it is being used by another process"
69+
backoff := 30 * time.Millisecond
70+
var err error
71+
72+
for i := range retries + 1 {
73+
err = m.Mount(dir)
74+
if err == nil {
75+
return nil
76+
}
77+
if strings.Contains(err.Error(), errStr) {
78+
time.Sleep(time.Duration(i+1) * backoff)
79+
continue
80+
}
81+
return err
82+
}
83+
84+
return err
85+
}
86+
6187
func (lm *localMounter) Unmount() error {
6288
lm.mu.Lock()
6389
defer lm.mu.Unlock()

0 commit comments

Comments
 (0)