diff --git a/pkg/sentry/mm/address_space.go b/pkg/sentry/mm/address_space.go index 496bd4ca28..df30235f5f 100644 --- a/pkg/sentry/mm/address_space.go +++ b/pkg/sentry/mm/address_space.go @@ -20,6 +20,7 @@ import ( "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/hostarch" "gvisor.dev/gvisor/pkg/sentry/memmap" + "gvisor.dev/gvisor/pkg/sentry/pgalloc" "gvisor.dev/gvisor/pkg/sentry/platform" ) @@ -175,6 +176,14 @@ func (mm *MemoryManager) mapASLocked(pseg pmaIterator, ar hostarch.AddrRange, pl // By default, map entire pmas at a time, under the assumption that there // is no cost to mapping more of a pma than necessary. mapAR := hostarch.AddrRange{0, ^hostarch.Addr(hostarch.PageSize - 1)} + setMapUnit := func(mapUnit uint64) { + mapMask := hostarch.Addr(mapUnit - 1) + mapAR.Start = ar.Start &^ mapMask + // If rounding ar.End up overflows, just keep the existing mapAR.End. + if end := (ar.End + mapMask) &^ mapMask; end >= ar.End { + mapAR.End = end + } + } if platformEffect != memmap.PlatformEffectDefault { // When explicitly committing, only map ar, since overmapping may incur // unexpected resource usage. When explicitly populating, do the same @@ -183,12 +192,13 @@ func (mm *MemoryManager) mapASLocked(pseg pmaIterator, ar hostarch.AddrRange, pl mapAR = ar } else if mapUnit := mm.p.MapUnit(); mapUnit != 0 { // Limit the range we map to ar, aligned to mapUnit. - mapMask := hostarch.Addr(mapUnit - 1) - mapAR.Start = ar.Start &^ mapMask - // If rounding ar.End up overflows, just keep the existing mapAR.End. - if end := (ar.End + mapMask) &^ mapMask; end >= ar.End { - mapAR.End = end - } + setMapUnit(mapUnit) + } else if mf, ok := pseg.ValuePtr().file.(*pgalloc.MemoryFile); ok && mf.IsAsyncLoading() { + // Impose an arbitrary mapUnit in order to avoid calling + // platform.AddressSpace.MapFile() => mf.DataFD() or mf.MapInternal() + // with unnecessarily large ranges, resulting in unnecessarily long + // waits. + setMapUnit(32 << 20) } if checkInvariants { if !mapAR.IsSupersetOf(ar) { diff --git a/pkg/sentry/pgalloc/save_restore.go b/pkg/sentry/pgalloc/save_restore.go index 0495aa602c..2a12db715f 100644 --- a/pkg/sentry/pgalloc/save_restore.go +++ b/pkg/sentry/pgalloc/save_restore.go @@ -494,6 +494,12 @@ var aplWaiterPool = sync.Pool{ }, } +// IsAsyncLoading returns true if async page loading is in progress or has +// failed permanently. +func (f *MemoryFile) IsAsyncLoading() bool { + return f.asyncPageLoad.Load() != nil +} + // AwaitLoadAll blocks until async page loading has completed. If async page // loading is not in progress, AwaitLoadAll returns immediately. func (f *MemoryFile) AwaitLoadAll() error {