Add option to skip stuck tasks waiting for address space
PiperOrigin-RevId: 297192390
This commit is contained in:
parent
430992a67a
commit
72e3f3a3ee
|
@ -247,6 +247,10 @@ type Kernel struct {
|
|||
|
||||
// VFS keeps the filesystem state used across the kernel.
|
||||
vfs vfs.VirtualFilesystem
|
||||
|
||||
// If set to true, report address space activation waits as if the task is in
|
||||
// external wait so that the watchdog doesn't report the task stuck.
|
||||
SleepForAddressSpaceActivation bool
|
||||
}
|
||||
|
||||
// InitKernelArgs holds arguments to Init.
|
||||
|
|
|
@ -140,7 +140,7 @@ func (k *Kernel) LoadTaskImage(ctx context.Context, args loader.LoadArgs) (*Task
|
|||
}
|
||||
|
||||
// Prepare a new user address space to load into.
|
||||
m := mm.NewMemoryManager(k, k)
|
||||
m := mm.NewMemoryManager(k, k, k.SleepForAddressSpaceActivation)
|
||||
defer m.DecUsers(ctx)
|
||||
args.MemoryManager = m
|
||||
|
||||
|
|
|
@ -220,7 +220,7 @@ func (r *runSyscallAfterExecStop) execute(t *Task) taskRunState {
|
|||
t.mu.Unlock()
|
||||
t.unstopVforkParent()
|
||||
// NOTE(b/30316266): All locks must be dropped prior to calling Activate.
|
||||
t.MemoryManager().Activate()
|
||||
t.MemoryManager().Activate(t)
|
||||
|
||||
t.ptraceExec(oldTID)
|
||||
return (*runSyscallExit)(nil)
|
||||
|
|
|
@ -30,7 +30,7 @@ var MAX_RW_COUNT = int(usermem.Addr(math.MaxInt32).RoundDown())
|
|||
// Activate ensures that the task has an active address space.
|
||||
func (t *Task) Activate() {
|
||||
if mm := t.MemoryManager(); mm != nil {
|
||||
if err := mm.Activate(); err != nil {
|
||||
if err := mm.Activate(t); err != nil {
|
||||
panic("unable to activate mm: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/platform"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
@ -38,7 +39,7 @@ func (mm *MemoryManager) AddressSpace() platform.AddressSpace {
|
|||
//
|
||||
// When this MemoryManager is no longer needed by a task, it should call
|
||||
// Deactivate to release the reference.
|
||||
func (mm *MemoryManager) Activate() error {
|
||||
func (mm *MemoryManager) Activate(ctx context.Context) error {
|
||||
// Fast path: the MemoryManager already has an active
|
||||
// platform.AddressSpace, and we just need to indicate that we need it too.
|
||||
for {
|
||||
|
@ -91,16 +92,20 @@ func (mm *MemoryManager) Activate() error {
|
|||
if as == nil {
|
||||
// AddressSpace is unavailable, we must wait.
|
||||
//
|
||||
// activeMu must not be held while waiting, as the user
|
||||
// of the address space we are waiting on may attempt
|
||||
// to take activeMu.
|
||||
//
|
||||
// Don't call UninterruptibleSleepStart to register the
|
||||
// wait to allow the watchdog stuck task to trigger in
|
||||
// case a process is starved waiting for the address
|
||||
// space.
|
||||
// activeMu must not be held while waiting, as the user of the address
|
||||
// space we are waiting on may attempt to take activeMu.
|
||||
mm.activeMu.Unlock()
|
||||
|
||||
sleep := mm.p.CooperativelySchedulesAddressSpace() && mm.sleepForActivation
|
||||
if sleep {
|
||||
// Mark this task sleeping while waiting for the address space to
|
||||
// prevent the watchdog from reporting it as a stuck task.
|
||||
ctx.UninterruptibleSleepStart(false)
|
||||
}
|
||||
<-c
|
||||
if sleep {
|
||||
ctx.UninterruptibleSleepFinish(false)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -28,16 +28,17 @@ import (
|
|||
)
|
||||
|
||||
// NewMemoryManager returns a new MemoryManager with no mappings and 1 user.
|
||||
func NewMemoryManager(p platform.Platform, mfp pgalloc.MemoryFileProvider) *MemoryManager {
|
||||
func NewMemoryManager(p platform.Platform, mfp pgalloc.MemoryFileProvider, sleepForActivation bool) *MemoryManager {
|
||||
return &MemoryManager{
|
||||
p: p,
|
||||
mfp: mfp,
|
||||
haveASIO: p.SupportsAddressSpaceIO(),
|
||||
privateRefs: &privateRefs{},
|
||||
users: 1,
|
||||
auxv: arch.Auxv{},
|
||||
dumpability: UserDumpable,
|
||||
aioManager: aioManager{contexts: make(map[uint64]*AIOContext)},
|
||||
p: p,
|
||||
mfp: mfp,
|
||||
haveASIO: p.SupportsAddressSpaceIO(),
|
||||
privateRefs: &privateRefs{},
|
||||
users: 1,
|
||||
auxv: arch.Auxv{},
|
||||
dumpability: UserDumpable,
|
||||
aioManager: aioManager{contexts: make(map[uint64]*AIOContext)},
|
||||
sleepForActivation: sleepForActivation,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,9 +80,10 @@ func (mm *MemoryManager) Fork(ctx context.Context) (*MemoryManager, error) {
|
|||
envv: mm.envv,
|
||||
auxv: append(arch.Auxv(nil), mm.auxv...),
|
||||
// IncRef'd below, once we know that there isn't an error.
|
||||
executable: mm.executable,
|
||||
dumpability: mm.dumpability,
|
||||
aioManager: aioManager{contexts: make(map[uint64]*AIOContext)},
|
||||
executable: mm.executable,
|
||||
dumpability: mm.dumpability,
|
||||
aioManager: aioManager{contexts: make(map[uint64]*AIOContext)},
|
||||
sleepForActivation: mm.sleepForActivation,
|
||||
}
|
||||
|
||||
// Copy vmas.
|
||||
|
|
|
@ -226,6 +226,11 @@ type MemoryManager struct {
|
|||
// aioManager keeps track of AIOContexts used for async IOs. AIOManager
|
||||
// must be cloned when CLONE_VM is used.
|
||||
aioManager aioManager
|
||||
|
||||
// sleepForActivation indicates whether the task should report to be sleeping
|
||||
// before trying to activate the address space. When set to true, delays in
|
||||
// activation are not reported as stuck tasks by the watchdog.
|
||||
sleepForActivation bool
|
||||
}
|
||||
|
||||
// vma represents a virtual memory area.
|
||||
|
|
|
@ -31,7 +31,7 @@ import (
|
|||
func testMemoryManager(ctx context.Context) *MemoryManager {
|
||||
p := platform.FromContext(ctx)
|
||||
mfp := pgalloc.MemoryFileProviderFromContext(ctx)
|
||||
mm := NewMemoryManager(p, mfp)
|
||||
mm := NewMemoryManager(p, mfp, false)
|
||||
mm.layout = arch.MmapLayout{
|
||||
MinAddr: p.MinUserAddress(),
|
||||
MaxAddr: p.MaxUserAddress(),
|
||||
|
|
Loading…
Reference in New Issue