Skip to content

Commit 8aa3332

Browse files
nixprimegvisor-bot
authored andcommitted
pgalloc: one async page loader per pages file
This resolves the "future work" described in MemoryFile.LoadFrom(). PiperOrigin-RevId: 681737060
1 parent 2c49d9f commit 8aa3332

File tree

4 files changed

+542
-420
lines changed

4 files changed

+542
-420
lines changed

pkg/sentry/kernel/kernel_restore.go

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ package kernel
1616

1717
import (
1818
"bufio"
19-
"errors"
2019
"fmt"
2120
"io"
2221

@@ -262,9 +261,8 @@ type AsyncMFLoader struct {
262261
metadataWg sync.WaitGroup
263262
metadataErr error
264263

265-
loadWg sync.WaitGroup
266-
loadErrsMu sync.Mutex
267-
loadErrs []error
264+
loadWg sync.WaitGroup
265+
loadErr error
268266
}
269267

270268
// NewAsyncMFLoader creates a new AsyncMFLoader. It takes ownership of
@@ -301,22 +299,16 @@ func (mfl *AsyncMFLoader) backgroundGoroutine(pagesMetadataFD, pagesFileFD *fd.F
301299
// or compressio.NewSimpleReader().
302300
pagesMetadata := bufio.NewReader(pagesMetadataFD)
303301

302+
mfl.loadWg.Add(1)
303+
apfl := pgalloc.StartAsyncPagesFileLoad(int32(pagesFileFD.FD()), func(err error) {
304+
defer mfl.loadWg.Done()
305+
mfl.loadErr = err
306+
}, timeline)
307+
cu.Add(apfl.MemoryFilesDone)
308+
304309
opts := pgalloc.LoadOpts{
305-
PagesFile: pagesFileFD,
306-
OnAsyncPageLoadStart: func(mf *pgalloc.MemoryFile) {
307-
mfl.loadWg.Add(1)
308-
log.Infof("Starting async page load for %p", mf)
309-
},
310-
OnAsyncPageLoadDone: func(mf *pgalloc.MemoryFile, err error) {
311-
defer mfl.loadWg.Done()
312-
if err != nil {
313-
log.Warningf("Async page load error for %p: %v", mf, err)
314-
mfl.loadErrsMu.Lock()
315-
mfl.loadErrs = append(mfl.loadErrs, fmt.Errorf("%p: async page load: %w", mf, err))
316-
mfl.loadErrsMu.Unlock()
317-
}
318-
},
319-
Timeline: timeline,
310+
PagesFile: apfl,
311+
Timeline: timeline,
320312
}
321313

322314
timeline.Reached("loading mainMF")
@@ -347,9 +339,9 @@ func (mfl *AsyncMFLoader) backgroundGoroutine(pagesMetadataFD, pagesFileFD *fd.F
347339

348340
// Wait for page loads to complete and report errors.
349341
mfl.loadWg.Wait()
350-
if loadErr := errors.Join(mfl.loadErrs...); loadErr != nil {
342+
if mfl.loadErr != nil {
351343
timeline.Invalidate("page load failed")
352-
log.Warningf("Failed to load MemoryFile pages: %v", loadErr)
344+
log.Warningf("Failed to load MemoryFile pages: %v", mfl.loadErr)
353345
return
354346
}
355347
log.Infof("All MemoryFile pages have been loaded.")
@@ -381,5 +373,5 @@ func (mfl *AsyncMFLoader) Wait() error {
381373
return err
382374
}
383375
mfl.loadWg.Wait()
384-
return errors.Join(mfl.loadErrs...)
376+
return mfl.loadErr
385377
}

pkg/sentry/pgalloc/BUILD

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,17 @@ package(
88
)
99

1010
declare_mutex(
11-
name = "apl_shared_mutex",
12-
out = "apl_shared_mutex.go",
11+
name = "amfls_mutex",
12+
out = "amfls_mutex.go",
1313
package = "pgalloc",
14-
prefix = "aplShared",
14+
prefix = "amfls",
15+
)
16+
17+
declare_mutex(
18+
name = "apfl_mutex",
19+
out = "apfl_mutex.go",
20+
package = "pgalloc",
21+
prefix = "apfl",
1522
)
1623

1724
declare_mutex(
@@ -21,6 +28,18 @@ declare_mutex(
2128
prefix = "memoryFile",
2229
)
2330

31+
go_template_instance(
32+
name = "amfl_list",
33+
out = "amfl_list.go",
34+
package = "pgalloc",
35+
prefix = "asyncMemoryFileLoad",
36+
template = "//pkg/ilist:generic_list",
37+
types = {
38+
"Element": "*asyncMemoryFileLoad",
39+
"Linker": "*asyncMemoryFileLoad",
40+
},
41+
)
42+
2443
go_template_instance(
2544
name = "apl_unloaded_set",
2645
out = "apl_unloaded_set.go",
@@ -128,7 +147,9 @@ go_template_instance(
128147
go_library(
129148
name = "pgalloc",
130149
srcs = [
131-
"apl_shared_mutex.go",
150+
"amfl_list.go",
151+
"amfls_mutex.go",
152+
"apfl_mutex.go",
132153
"apl_unloaded_set.go",
133154
"context.go",
134155
"debug.go",
@@ -150,7 +171,6 @@ go_library(
150171
"//pkg/bitmap",
151172
"//pkg/context",
152173
"//pkg/errors/linuxerr",
153-
"//pkg/fd",
154174
"//pkg/gohacks",
155175
"//pkg/goid",
156176
"//pkg/hostarch",

pkg/sentry/pgalloc/pgalloc.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414

1515
// Package pgalloc contains the page allocator subsystem, which provides
1616
// allocatable memory that may be mapped into application address spaces.
17+
//
18+
// Lock order:
19+
//
20+
// AsyncPagesFileLoad.amflsMu
21+
// MemoryFile.mu
22+
// AsyncPagesFileLoad.mu
1723
package pgalloc
1824

1925
import (
@@ -190,7 +196,7 @@ type MemoryFile struct {
190196

191197
// If asyncPageLoad is non-nil, it tracks the state of in-progress or
192198
// failed async page loading.
193-
asyncPageLoad atomic.Pointer[aplShared]
199+
asyncPageLoad atomic.Pointer[asyncMemoryFileLoad]
194200

195201
// file is the backing file. The file pointer is immutable.
196202
file *os.File
@@ -1435,8 +1441,8 @@ func (f *MemoryFile) MapInternal(fr memmap.FileRange, at hostarch.AccessType) (s
14351441
return safemem.BlockSeq{}, linuxerr.EACCES
14361442
}
14371443

1438-
if apl := f.asyncPageLoad.Load(); apl != nil {
1439-
if err := apl.awaitLoad(f, fr); err != nil {
1444+
if amfl := f.asyncPageLoad.Load(); amfl != nil {
1445+
if err := amfl.awaitLoad(fr); err != nil {
14401446
return safemem.BlockSeq{}, err
14411447
}
14421448
}
@@ -1799,8 +1805,8 @@ func (f *MemoryFile) File() *os.File {
17991805

18001806
// DataFD implements memmap.File.DataFD.
18011807
func (f *MemoryFile) DataFD(fr memmap.FileRange) (int, error) {
1802-
if apl := f.asyncPageLoad.Load(); apl != nil {
1803-
if err := apl.awaitLoad(f, fr); err != nil {
1808+
if amfl := f.asyncPageLoad.Load(); amfl != nil {
1809+
if err := amfl.awaitLoad(fr); err != nil {
18041810
return -1, err
18051811
}
18061812
}

0 commit comments

Comments
 (0)