Skip to content

Commit b781ad4

Browse files
djeebusdjeebot
andauthored
Only wait up to 5 seconds to mount nfs (#2317)
Co-authored-by: djeebot <djeebot@users.noreply.github.com>
1 parent 393d0af commit b781ad4

3 files changed

Lines changed: 66 additions & 13 deletions

File tree

packages/envd/internal/api/init.go

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"os/exec"
1212
"strings"
1313
"sync"
14+
"sync/atomic"
1415
"time"
1516

1617
"github.com/awnumar/memguard"
@@ -217,16 +218,7 @@ func (a *API) SetData(ctx context.Context, logger zerolog.Logger, data PostInitJ
217218
}
218219

219220
if data.VolumeMounts != nil {
220-
var wg sync.WaitGroup
221-
for _, volume := range *data.VolumeMounts {
222-
logger.Debug().Msgf("Mounting %s at %q", volume.NfsTarget, volume.Path)
223-
224-
wg.Go(func() {
225-
a.setupNfs(context.WithoutCancel(ctx), volume.NfsTarget, volume.Path)
226-
})
227-
}
228-
229-
wg.Wait()
221+
a.setupNFS(ctx, logger, *data.VolumeMounts)
230222
}
231223

232224
return nil
@@ -247,7 +239,61 @@ var nfsOptions = strings.Join([]string{
247239
"noacl", // no reason for acl in the sandbox
248240
}, ",")
249241

250-
func (a *API) setupNfs(ctx context.Context, nfsTarget, path string) {
242+
const nfsMountTimeout = 5 * time.Second
243+
244+
func (a *API) setupNFS(ctx context.Context, logger zerolog.Logger, mounts []VolumeMount) {
245+
// Already fully mounted, nothing to do
246+
if a.isMountedNFS.Load() {
247+
logger.Debug().Msg("NFS volumes already mounted")
248+
249+
return
250+
}
251+
252+
// Prevent concurrent mounting attempts
253+
if !a.isMountingNFS.CompareAndSwap(false, true) {
254+
logger.Debug().Msg("NFS volumes already mounting")
255+
256+
return
257+
}
258+
defer a.isMountingNFS.Store(false)
259+
260+
logger.Debug().Msg("Mounting NFS volumes")
261+
262+
ctx = context.WithoutCancel(ctx)
263+
ctx, cancel := context.WithTimeout(ctx, nfsMountTimeout)
264+
defer cancel()
265+
266+
var wg sync.WaitGroup
267+
var allSucceeded atomic.Bool
268+
allSucceeded.Store(true)
269+
270+
for _, volume := range mounts {
271+
// Skip already mounted paths
272+
if _, ok := a.mountedPaths.Load(volume.Path); ok {
273+
logger.Debug().Msgf("Skipping already mounted %q", volume.Path)
274+
275+
continue
276+
}
277+
278+
logger.Debug().Msgf("Mounting %s at %q", volume.NfsTarget, volume.Path)
279+
280+
wg.Go(func() {
281+
if a.mountNFS(ctx, volume.NfsTarget, volume.Path) {
282+
a.mountedPaths.Store(volume.Path, true)
283+
} else {
284+
allSucceeded.Store(false)
285+
}
286+
})
287+
}
288+
289+
wg.Wait()
290+
291+
if allSucceeded.Load() {
292+
a.isMountedNFS.Store(true)
293+
}
294+
}
295+
296+
func (a *API) mountNFS(ctx context.Context, nfsTarget, path string) bool {
251297
commands := [][]string{
252298
{"mkdir", "-p", path},
253299
{"mount", "-v", "-t", "nfs", "-o", "fg,hard," + nfsOptions, nfsTarget, path},
@@ -264,9 +310,11 @@ func (a *API) setupNfs(ctx context.Context, nfsTarget, path string) {
264310
Msg("Mount NFS")
265311

266312
if err != nil {
267-
return
313+
return false
268314
}
269315
}
316+
317+
return true
270318
}
271319

272320
func (a *API) SetupHyperloop(address string) {

packages/envd/internal/api/store.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/json"
66
"net/http"
77
"sync"
8+
"sync/atomic"
89

910
"github.com/rs/zerolog"
1011

@@ -37,6 +38,10 @@ type API struct {
3738

3839
lastSetTime *utils.AtomicMax
3940
initLock sync.Mutex
41+
42+
isMountingNFS atomic.Bool
43+
isMountedNFS atomic.Bool
44+
mountedPaths sync.Map // tracks successfully mounted paths
4045
}
4146

4247
func New(l *zerolog.Logger, defaults *execcontext.Defaults, mmdsChan chan *host.MMDSOpts, isNotFC bool) *API {

packages/envd/pkg/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
package pkg
22

3-
const Version = "0.5.10"
3+
const Version = "0.5.11"

0 commit comments

Comments
 (0)