diff options
author | Jamie Liu <jamieliu@google.com> | 2019-03-14 08:11:36 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2019-03-14 08:12:48 -0700 |
commit | 8f4634997bd97810a85a70b71f000378d9db2e55 (patch) | |
tree | 903096f91ee8f201fa622296e0f04cf7c7cd9013 /pkg/sentry/kernel | |
parent | fb9919881c7dc98eaf97cad2a70d187bd78f1566 (diff) |
Decouple filemem from platform and move it to pgalloc.MemoryFile.
This is in preparation for improved page cache reclaim, which requires
greater integration between the page cache and page allocator.
PiperOrigin-RevId: 238444706
Change-Id: Id24141b3678d96c7d7dc24baddd9be555bffafe4
Diffstat (limited to 'pkg/sentry/kernel')
-rw-r--r-- | pkg/sentry/kernel/BUILD | 3 | ||||
-rw-r--r-- | pkg/sentry/kernel/contexttest/BUILD | 1 | ||||
-rw-r--r-- | pkg/sentry/kernel/contexttest/contexttest.go | 2 | ||||
-rw-r--r-- | pkg/sentry/kernel/kernel.go | 57 | ||||
-rw-r--r-- | pkg/sentry/kernel/memevent/memory_events.go | 2 | ||||
-rw-r--r-- | pkg/sentry/kernel/shm/BUILD | 1 | ||||
-rw-r--r-- | pkg/sentry/kernel/shm/shm.go | 19 | ||||
-rw-r--r-- | pkg/sentry/kernel/task.go | 5 | ||||
-rw-r--r-- | pkg/sentry/kernel/task_context.go | 2 | ||||
-rw-r--r-- | pkg/sentry/kernel/timekeeper.go | 5 | ||||
-rw-r--r-- | pkg/sentry/kernel/timekeeper_test.go | 8 | ||||
-rw-r--r-- | pkg/sentry/kernel/vdso.go | 17 |
12 files changed, 73 insertions, 49 deletions
diff --git a/pkg/sentry/kernel/BUILD b/pkg/sentry/kernel/BUILD index d9bbfb556..4d34bc733 100644 --- a/pkg/sentry/kernel/BUILD +++ b/pkg/sentry/kernel/BUILD @@ -173,6 +173,7 @@ go_library( "//pkg/sentry/loader", "//pkg/sentry/memmap", "//pkg/sentry/mm", + "//pkg/sentry/pgalloc", "//pkg/sentry/platform", "//pkg/sentry/safemem", "//pkg/sentry/socket/netlink/port", @@ -212,7 +213,7 @@ go_test( "//pkg/sentry/kernel/kdefs", "//pkg/sentry/kernel/sched", "//pkg/sentry/limits", - "//pkg/sentry/platform", + "//pkg/sentry/pgalloc", "//pkg/sentry/time", "//pkg/sentry/usage", "//pkg/sentry/usermem", diff --git a/pkg/sentry/kernel/contexttest/BUILD b/pkg/sentry/kernel/contexttest/BUILD index 5769a3b28..bfb2a0b73 100644 --- a/pkg/sentry/kernel/contexttest/BUILD +++ b/pkg/sentry/kernel/contexttest/BUILD @@ -12,6 +12,7 @@ go_library( "//pkg/sentry/context", "//pkg/sentry/context/contexttest", "//pkg/sentry/kernel", + "//pkg/sentry/pgalloc", "//pkg/sentry/platform", ], ) diff --git a/pkg/sentry/kernel/contexttest/contexttest.go b/pkg/sentry/kernel/contexttest/contexttest.go index 9eb18e7e8..eb56a6a07 100644 --- a/pkg/sentry/kernel/contexttest/contexttest.go +++ b/pkg/sentry/kernel/contexttest/contexttest.go @@ -22,6 +22,7 @@ import ( "gvisor.googlesource.com/gvisor/pkg/sentry/context" "gvisor.googlesource.com/gvisor/pkg/sentry/context/contexttest" "gvisor.googlesource.com/gvisor/pkg/sentry/kernel" + "gvisor.googlesource.com/gvisor/pkg/sentry/pgalloc" "gvisor.googlesource.com/gvisor/pkg/sentry/platform" ) @@ -33,6 +34,7 @@ func Context(tb testing.TB) context.Context { k := &kernel.Kernel{ Platform: platform.FromContext(ctx), } + k.SetMemoryFile(pgalloc.MemoryFileFromContext(ctx)) ctx.(*contexttest.TestContext).RegisterValue(kernel.CtxKernel, k) return ctx } diff --git a/pkg/sentry/kernel/kernel.go b/pkg/sentry/kernel/kernel.go index c6afae2e6..3533fd8f7 100644 --- a/pkg/sentry/kernel/kernel.go +++ b/pkg/sentry/kernel/kernel.go @@ -58,6 +58,7 @@ import ( "gvisor.googlesource.com/gvisor/pkg/sentry/limits" "gvisor.googlesource.com/gvisor/pkg/sentry/loader" "gvisor.googlesource.com/gvisor/pkg/sentry/mm" + "gvisor.googlesource.com/gvisor/pkg/sentry/pgalloc" "gvisor.googlesource.com/gvisor/pkg/sentry/platform" "gvisor.googlesource.com/gvisor/pkg/sentry/socket/netlink/port" sentrytime "gvisor.googlesource.com/gvisor/pkg/sentry/time" @@ -89,12 +90,14 @@ type Kernel struct { // All of the following fields are immutable unless otherwise specified. - // Platform is the platform that is used to execute tasks in the - // created Kernel. It is embedded so that Kernel can directly serve as - // Platform in mm logic and also serve as platform.MemoryProvider in - // filemem S/R logic. + // Platform is the platform that is used to execute tasks in the created + // Kernel. See comment on pgalloc.MemoryFileProvider for why Platform is + // embedded anonymously (the same issue applies). platform.Platform `state:"nosave"` + // mf provides application memory. + mf *pgalloc.MemoryFile `state:"nosave"` + // See InitKernelArgs for the meaning of these fields. featureSet *cpuid.FeatureSet timekeeper *Timekeeper @@ -229,7 +232,8 @@ type InitKernelArgs struct { // Init initialize the Kernel with no tasks. // -// Callers must manually set Kernel.Platform before caling Init. +// Callers must manually set Kernel.Platform and call Kernel.SetMemoryFile +// before calling Init. func (k *Kernel) Init(args InitKernelArgs) error { if args.FeatureSet == nil { return fmt.Errorf("FeatureSet is nil") @@ -332,15 +336,9 @@ func (k *Kernel) SaveTo(w io.Writer) error { log.Infof("Kernel save stats: %s", &stats) log.Infof("Kernel save took [%s].", time.Since(kernelStart)) - // Save the memory state. - // - // FIXME: In the future, this should not be dispatched via - // an abstract memory type. This should be dispatched to a single - // memory implementation that belongs to the kernel. (There is - // currently a single implementation anyways, it just needs to be - // "unabstracted" and reparented appropriately.) + // Save the memory file's state. memoryStart := time.Now() - if err := k.Platform.Memory().SaveTo(w); err != nil { + if err := k.mf.SaveTo(w); err != nil { return err } log.Infof("Memory save took [%s].", time.Since(memoryStart)) @@ -418,13 +416,9 @@ func (ts *TaskSet) unregisterEpollWaiters() { } // LoadFrom returns a new Kernel loaded from args. -func (k *Kernel) LoadFrom(r io.Reader, p platform.Platform, net inet.Stack) error { +func (k *Kernel) LoadFrom(r io.Reader, net inet.Stack) error { loadStart := time.Now() - if p == nil { - return fmt.Errorf("Platform is nil") - } - k.Platform = p k.networkStack = net initAppCores := k.applicationCores @@ -438,11 +432,9 @@ func (k *Kernel) LoadFrom(r io.Reader, p platform.Platform, net inet.Stack) erro log.Infof("Kernel load stats: %s", &stats) log.Infof("Kernel load took [%s].", time.Since(kernelStart)) - // Load the memory state. - // - // See the note in SaveTo. + // Load the memory file's state. memoryStart := time.Now() - if err := k.Platform.Memory().LoadFrom(r); err != nil { + if err := k.mf.LoadFrom(r); err != nil { return err } log.Infof("Memory load took [%s].", time.Since(memoryStart)) @@ -597,6 +589,10 @@ func (ctx *createProcessContext) Value(key interface{}) interface{} { return ctx.k.RealtimeClock() case limits.CtxLimits: return ctx.args.Limits + case pgalloc.CtxMemoryFile: + return ctx.k.mf + case pgalloc.CtxMemoryFileProvider: + return ctx.k case platform.CtxPlatform: return ctx.k case uniqueid.CtxGlobalUniqueID: @@ -1018,6 +1014,17 @@ func (k *Kernel) NowMonotonic() int64 { return now } +// SetMemoryFile sets Kernel.mf. SetMemoryFile must be called before Init or +// LoadFrom. +func (k *Kernel) SetMemoryFile(mf *pgalloc.MemoryFile) { + k.mf = mf +} + +// MemoryFile implements pgalloc.MemoryFileProvider.MemoryFile. +func (k *Kernel) MemoryFile() *pgalloc.MemoryFile { + return k.mf +} + // SupervisorContext returns a Context with maximum privileges in k. It should // only be used by goroutines outside the control of the emulated kernel // defined by e. @@ -1083,7 +1090,7 @@ func (k *Kernel) ListSockets(family int) []*refs.WeakRef { socks := []*refs.WeakRef{} if table, ok := k.socketTable[family]; ok { socks = make([]*refs.WeakRef, 0, len(table)) - for s, _ := range table { + for s := range table { socks = append(socks, s) } } @@ -1123,6 +1130,10 @@ func (ctx supervisorContext) Value(key interface{}) interface{} { case limits.CtxLimits: // No limits apply. return limits.NewLimitSet() + case pgalloc.CtxMemoryFile: + return ctx.k.mf + case pgalloc.CtxMemoryFileProvider: + return ctx.k case platform.CtxPlatform: return ctx.k case uniqueid.CtxGlobalUniqueID: diff --git a/pkg/sentry/kernel/memevent/memory_events.go b/pkg/sentry/kernel/memevent/memory_events.go index b6283c5d1..d09d6debf 100644 --- a/pkg/sentry/kernel/memevent/memory_events.go +++ b/pkg/sentry/kernel/memevent/memory_events.go @@ -95,7 +95,7 @@ func (m *MemoryEvents) run() { } func (m *MemoryEvents) emit() { - totalPlatform, err := m.k.Platform.Memory().TotalUsage() + totalPlatform, err := m.k.MemoryFile().TotalUsage() if err != nil { log.Warningf("Failed to fetch memory usage for memory events: %v", err) return diff --git a/pkg/sentry/kernel/shm/BUILD b/pkg/sentry/kernel/shm/BUILD index f45770eef..bc2089872 100644 --- a/pkg/sentry/kernel/shm/BUILD +++ b/pkg/sentry/kernel/shm/BUILD @@ -20,6 +20,7 @@ go_library( "//pkg/sentry/kernel/auth", "//pkg/sentry/kernel/time", "//pkg/sentry/memmap", + "//pkg/sentry/pgalloc", "//pkg/sentry/platform", "//pkg/sentry/usage", "//pkg/sentry/usermem", diff --git a/pkg/sentry/kernel/shm/shm.go b/pkg/sentry/kernel/shm/shm.go index 96414d060..4525aabf4 100644 --- a/pkg/sentry/kernel/shm/shm.go +++ b/pkg/sentry/kernel/shm/shm.go @@ -45,6 +45,7 @@ import ( "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/auth" ktime "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/time" "gvisor.googlesource.com/gvisor/pkg/sentry/memmap" + "gvisor.googlesource.com/gvisor/pkg/sentry/pgalloc" "gvisor.googlesource.com/gvisor/pkg/sentry/platform" "gvisor.googlesource.com/gvisor/pkg/sentry/usage" "gvisor.googlesource.com/gvisor/pkg/sentry/usermem" @@ -199,19 +200,19 @@ func (r *Registry) FindOrCreate(ctx context.Context, pid int32, key Key, size ui // // Precondition: Caller must hold r.mu. func (r *Registry) newShm(ctx context.Context, pid int32, key Key, creator fs.FileOwner, perms fs.FilePermissions, size uint64) (*Shm, error) { - p := platform.FromContext(ctx) - if p == nil { - panic(fmt.Sprintf("context.Context %T lacks non-nil value for key %T", ctx, platform.CtxPlatform)) + mfp := pgalloc.MemoryFileProviderFromContext(ctx) + if mfp == nil { + panic(fmt.Sprintf("context.Context %T lacks non-nil value for key %T", ctx, pgalloc.CtxMemoryFileProvider)) } effectiveSize := uint64(usermem.Addr(size).MustRoundUp()) - fr, err := p.Memory().Allocate(effectiveSize, usage.Anonymous) + fr, err := mfp.MemoryFile().Allocate(effectiveSize, usage.Anonymous) if err != nil { return nil, err } shm := &Shm{ - p: p, + mfp: mfp, registry: r, creator: creator, size: size, @@ -312,7 +313,7 @@ type Shm struct { // destruction. refs.AtomicRefCount - p platform.Platform + mfp pgalloc.MemoryFileProvider // registry points to the shm registry containing this segment. Immutable. registry *Registry @@ -333,7 +334,7 @@ type Shm struct { // Invariant: effectiveSize must be a multiple of usermem.PageSize. effectiveSize uint64 - // fr is the offset into platform.Memory() that backs this contents of this + // fr is the offset into mfp.MemoryFile() that backs this contents of this // segment. Immutable. fr platform.FileRange @@ -452,7 +453,7 @@ func (s *Shm) Translate(ctx context.Context, required, optional memmap.MappableR return []memmap.Translation{ { Source: source, - File: s.p.Memory(), + File: s.mfp.MemoryFile(), Offset: s.fr.Start + source.Start, }, }, err @@ -599,7 +600,7 @@ func (s *Shm) Set(ctx context.Context, ds *linux.ShmidDS) error { } func (s *Shm) destroy() { - s.p.Memory().DecRef(s.fr) + s.mfp.MemoryFile().DecRef(s.fr) s.registry.remove(s) } diff --git a/pkg/sentry/kernel/task.go b/pkg/sentry/kernel/task.go index 702e40cce..e9f133c0b 100644 --- a/pkg/sentry/kernel/task.go +++ b/pkg/sentry/kernel/task.go @@ -29,6 +29,7 @@ import ( "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/sched" ktime "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/time" "gvisor.googlesource.com/gvisor/pkg/sentry/limits" + "gvisor.googlesource.com/gvisor/pkg/sentry/pgalloc" "gvisor.googlesource.com/gvisor/pkg/sentry/platform" "gvisor.googlesource.com/gvisor/pkg/sentry/unimpl" "gvisor.googlesource.com/gvisor/pkg/sentry/uniqueid" @@ -587,6 +588,10 @@ func (t *Task) Value(key interface{}) interface{} { return t.k.RealtimeClock() case limits.CtxLimits: return t.tg.limits + case pgalloc.CtxMemoryFile: + return t.k.mf + case pgalloc.CtxMemoryFileProvider: + return t.k case platform.CtxPlatform: return t.k case uniqueid.CtxGlobalUniqueID: diff --git a/pkg/sentry/kernel/task_context.go b/pkg/sentry/kernel/task_context.go index ee3e49d17..d1c82f2aa 100644 --- a/pkg/sentry/kernel/task_context.go +++ b/pkg/sentry/kernel/task_context.go @@ -144,7 +144,7 @@ func (t *Task) Stack() *arch.Stack { // * fs: Binary FeatureSet func (k *Kernel) LoadTaskImage(ctx context.Context, mounts *fs.MountNamespace, root, wd *fs.Dirent, maxTraversals *uint, filename string, argv, envv []string, fs *cpuid.FeatureSet) (*TaskContext, *syserr.Error) { // Prepare a new user address space to load into. - m := mm.NewMemoryManager(k) + m := mm.NewMemoryManager(k, k) defer m.DecUsers(ctx) os, ac, name, err := loader.Load(ctx, m, mounts, root, wd, maxTraversals, fs, filename, argv, envv, k.extraAuxv, k.vdso) diff --git a/pkg/sentry/kernel/timekeeper.go b/pkg/sentry/kernel/timekeeper.go index 6bff80f13..d7bd85e78 100644 --- a/pkg/sentry/kernel/timekeeper.go +++ b/pkg/sentry/kernel/timekeeper.go @@ -21,6 +21,7 @@ import ( "gvisor.googlesource.com/gvisor/pkg/log" ktime "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/time" + "gvisor.googlesource.com/gvisor/pkg/sentry/pgalloc" "gvisor.googlesource.com/gvisor/pkg/sentry/platform" sentrytime "gvisor.googlesource.com/gvisor/pkg/sentry/time" ) @@ -85,9 +86,9 @@ type Timekeeper struct { // NewTimekeeper does not take ownership of paramPage. // // SetClocks must be called on the returned Timekeeper before it is usable. -func NewTimekeeper(platform platform.Platform, paramPage platform.FileRange) (*Timekeeper, error) { +func NewTimekeeper(mfp pgalloc.MemoryFileProvider, paramPage platform.FileRange) (*Timekeeper, error) { return &Timekeeper{ - params: NewVDSOParamPage(platform, paramPage), + params: NewVDSOParamPage(mfp, paramPage), }, nil } diff --git a/pkg/sentry/kernel/timekeeper_test.go b/pkg/sentry/kernel/timekeeper_test.go index 71674c21c..6084bcb18 100644 --- a/pkg/sentry/kernel/timekeeper_test.go +++ b/pkg/sentry/kernel/timekeeper_test.go @@ -18,7 +18,7 @@ import ( "testing" "gvisor.googlesource.com/gvisor/pkg/sentry/context/contexttest" - "gvisor.googlesource.com/gvisor/pkg/sentry/platform" + "gvisor.googlesource.com/gvisor/pkg/sentry/pgalloc" sentrytime "gvisor.googlesource.com/gvisor/pkg/sentry/time" "gvisor.googlesource.com/gvisor/pkg/sentry/usage" "gvisor.googlesource.com/gvisor/pkg/sentry/usermem" @@ -53,13 +53,13 @@ func (c *mockClocks) GetTime(id sentrytime.ClockID) (int64, error) { // SetClocks called. func stateTestClocklessTimekeeper(tb testing.TB) *Timekeeper { ctx := contexttest.Context(tb) - p := platform.FromContext(ctx) - fr, err := p.Memory().Allocate(usermem.PageSize, usage.Anonymous) + mfp := pgalloc.MemoryFileProviderFromContext(ctx) + fr, err := mfp.MemoryFile().Allocate(usermem.PageSize, usage.Anonymous) if err != nil { tb.Fatalf("failed to allocate memory: %v", err) } return &Timekeeper{ - params: NewVDSOParamPage(p, fr), + params: NewVDSOParamPage(mfp, fr), } } diff --git a/pkg/sentry/kernel/vdso.go b/pkg/sentry/kernel/vdso.go index 0ec858a4a..3a35f1d00 100644 --- a/pkg/sentry/kernel/vdso.go +++ b/pkg/sentry/kernel/vdso.go @@ -18,6 +18,7 @@ import ( "fmt" "gvisor.googlesource.com/gvisor/pkg/binary" + "gvisor.googlesource.com/gvisor/pkg/sentry/pgalloc" "gvisor.googlesource.com/gvisor/pkg/sentry/platform" "gvisor.googlesource.com/gvisor/pkg/sentry/safemem" "gvisor.googlesource.com/gvisor/pkg/sentry/usermem" @@ -55,9 +56,9 @@ type vdsoParams struct { // // +stateify savable type VDSOParamPage struct { - // The parameter page is fr, allocated from platform.Memory(). - platform platform.Platform - fr platform.FileRange + // The parameter page is fr, allocated from mfp.MemoryFile(). + mfp pgalloc.MemoryFileProvider + fr platform.FileRange // seq is the current sequence count written to the page. // @@ -73,20 +74,20 @@ type VDSOParamPage struct { // // Preconditions: // -// * fr is a single page allocated from platform.Memory(). VDSOParamPage does +// * fr is a single page allocated from mfp.MemoryFile(). VDSOParamPage does // not take ownership of fr; it must remain allocated for the lifetime of the // VDSOParamPage. // // * VDSOParamPage must be the only writer to fr. // -// * platform.Memory().MapInternal(fr) must return a single safemem.Block. -func NewVDSOParamPage(platform platform.Platform, fr platform.FileRange) *VDSOParamPage { - return &VDSOParamPage{platform: platform, fr: fr} +// * mfp.MemoryFile().MapInternal(fr) must return a single safemem.Block. +func NewVDSOParamPage(mfp pgalloc.MemoryFileProvider, fr platform.FileRange) *VDSOParamPage { + return &VDSOParamPage{mfp: mfp, fr: fr} } // access returns a mapping of the param page. func (v *VDSOParamPage) access() (safemem.Block, error) { - bs, err := v.platform.Memory().MapInternal(v.fr, usermem.ReadWrite) + bs, err := v.mfp.MemoryFile().MapInternal(v.fr, usermem.ReadWrite) if err != nil { return safemem.Block{}, err } |