Skip to content

Commit 8f111be

Browse files
ayushr2gvisor-bot
authored andcommitted
Wait for main MF loading to start before writing to it during restore.
When using async page loading (the checkpoint image has compression=none), the kernel and memory files are loaded in parallel. A step in kernel loading tries writing to the main MemoryFile. Ensure that step happens after the main MemoryFile has started being loaded (i.e. mainMF.LoadFrom() method has returned successfully). MemoryFile.asyncPageLoad field needs to be initialized before it can be written to. Fixes #11842 PiperOrigin-RevId: 779995419
1 parent 85e7611 commit 8f111be

File tree

3 files changed

+33
-12
lines changed

3 files changed

+33
-12
lines changed

pkg/sentry/kernel/kernel.go

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ func (k *Kernel) invalidateUnsavableMappings(ctx context.Context) error {
758758
}
759759

760760
// LoadFrom returns a new Kernel loaded from args.
761-
func (k *Kernel) LoadFrom(ctx context.Context, r io.Reader, loadMFs bool, timeReady chan struct{}, net inet.Stack, clocks sentrytime.Clocks, vfsOpts *vfs.CompleteRestoreOptions, saveRestoreNet bool) error {
761+
func (k *Kernel) LoadFrom(ctx context.Context, r io.Reader, asyncMFLoader *AsyncMFLoader, timeReady chan struct{}, net inet.Stack, clocks sentrytime.Clocks, vfsOpts *vfs.CompleteRestoreOptions, saveRestoreNet bool) error {
762762
loadStart := time.Now()
763763

764764
k.runningTasksCond.L = &k.runningTasksMu
@@ -794,14 +794,6 @@ func (k *Kernel) LoadFrom(ctx context.Context, r io.Reader, loadMFs bool, timeRe
794794
log.Infof("Kernel load stats: %s", stats.String())
795795
log.Infof("Kernel load took [%s].", time.Since(kernelStart))
796796

797-
if loadMFs {
798-
mfStart := time.Now()
799-
if err := k.loadMemoryFiles(ctx, r); err != nil {
800-
return fmt.Errorf("failed to load memory files: %w", err)
801-
}
802-
log.Infof("Memory files load took [%s].", time.Since(mfStart))
803-
}
804-
805797
if !saveRestoreNet {
806798
// rootNetworkNamespace and stack should be populated after
807799
// loading the state file. Reset the stack before restoring the
@@ -810,6 +802,21 @@ func (k *Kernel) LoadFrom(ctx context.Context, r io.Reader, loadMFs bool, timeRe
810802
k.rootNetworkNamespace.RestoreRootStack(net)
811803
}
812804

805+
if asyncMFLoader == nil {
806+
mfStart := time.Now()
807+
if err := k.loadMemoryFiles(ctx, r); err != nil {
808+
return fmt.Errorf("failed to load memory files: %w", err)
809+
}
810+
log.Infof("Memory files load took [%s].", time.Since(mfStart))
811+
} else {
812+
// Timekeeper restore below tries writing to the main MF. If async page
813+
// loading is being used, we need to make sure that the main MF loading has
814+
// started before we try to write to it.
815+
if err := asyncMFLoader.WaitMainMFStart(); err != nil {
816+
return fmt.Errorf("main MF start failed: %w", err)
817+
}
818+
}
819+
813820
k.Timekeeper().SetClocks(clocks, k.vdsoParams)
814821

815822
if timeReady != nil {

pkg/sentry/kernel/kernel_restore.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ type AsyncMFLoader struct {
256256
// MemoryFiles, once they are known. This channel is written to exactly once.
257257
privateMFsChan chan map[string]*pgalloc.MemoryFile
258258

259+
mainMFStartWg sync.WaitGroup
260+
mainMetadataErr error
261+
259262
metadataWg sync.WaitGroup
260263
metadataErr error
261264

@@ -275,6 +278,7 @@ func NewAsyncMFLoader(pagesMetadata, pagesFile *fd.FD, mainMF *pgalloc.MemoryFil
275278
mfl := &AsyncMFLoader{
276279
privateMFsChan: make(chan map[string]*pgalloc.MemoryFile, 1),
277280
}
281+
mfl.mainMFStartWg.Add(1)
278282
mfl.metadataWg.Add(1)
279283
mfl.loadWg.Add(1)
280284
go mfl.backgroundGoroutine(pagesMetadata, pagesFile, mainMF, timeline)
@@ -318,9 +322,12 @@ func (mfl *AsyncMFLoader) backgroundGoroutine(pagesMetadataFD, pagesFileFD *fd.F
318322
timeline.Reached("loading mainMF")
319323
log.Infof("Loading metadata for main MemoryFile: %p", mainMF)
320324
ctx := context.Background()
321-
if err := mainMF.LoadFrom(ctx, pagesMetadata, &opts); err != nil {
325+
err := mainMF.LoadFrom(ctx, pagesMetadata, &opts)
326+
mfl.metadataErr = err
327+
mfl.mainMetadataErr = err
328+
mfl.mainMFStartWg.Done()
329+
if err != nil {
322330
log.Warningf("Failed to load main MemoryFile %p: %v", mainMF, err)
323-
mfl.metadataErr = err
324331
return
325332
}
326333
timeline.Reached("waiting for privateMF info")
@@ -353,6 +360,13 @@ func (mfl *AsyncMFLoader) KickoffPrivate(mfmap map[string]*pgalloc.MemoryFile) {
353360
mfl.privateMFsChan <- mfmap
354361
}
355362

363+
// WaitMainMFStart waits for the background goroutine to successfully start
364+
// asynchronously loading the main MemoryFile.
365+
func (mfl *AsyncMFLoader) WaitMainMFStart() error {
366+
mfl.mainMFStartWg.Wait()
367+
return mfl.mainMetadataErr
368+
}
369+
356370
// WaitMetadata waits for the background goroutine to successfully complete
357371
// reading all MemoryFile metadata and report any errors.
358372
func (mfl *AsyncMFLoader) WaitMetadata() error {

runsc/boot/restore.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ func (r *restorer) restore(l *Loader) error {
276276

277277
// Load the state.
278278
r.timer.Reached("loading kernel")
279-
if err := l.k.LoadFrom(ctx, r.stateFile, r.asyncMFLoader == nil, nil, oldInetStack, time.NewCalibratedClocks(), &vfs.CompleteRestoreOptions{}, l.saveRestoreNet); err != nil {
279+
if err := l.k.LoadFrom(ctx, r.stateFile, r.asyncMFLoader, nil, oldInetStack, time.NewCalibratedClocks(), &vfs.CompleteRestoreOptions{}, l.saveRestoreNet); err != nil {
280280
return fmt.Errorf("failed to load kernel: %w", err)
281281
}
282282
r.timer.Reached("kernel loaded")

0 commit comments

Comments
 (0)