diff --git a/pkg/sentry/fsimpl/tmpfs/save_restore.go b/pkg/sentry/fsimpl/tmpfs/save_restore.go index 1642c27a9..391adc968 100644 --- a/pkg/sentry/fsimpl/tmpfs/save_restore.go +++ b/pkg/sentry/fsimpl/tmpfs/save_restore.go @@ -23,11 +23,29 @@ import ( "gvisor.dev/gvisor/pkg/sentry/vfs" ) -// afterLoad is called by stateify. -func (fs *filesystem) afterLoad(goContext.Context) { - if !fs.privateMF { - fs.mf = fs.mfp.MemoryFile() +// saveMf is called by stateify. +func (fs *filesystem) saveMf() string { + if !fs.mf.IsSavable() { + panic(fmt.Sprintf("Can't save tmpfs filesystem because its MemoryFile is not savable: %v", fs.mf)) } + return fs.mf.RestoreID() +} + +// loadMf is called by stateify. +func (fs *filesystem) loadMf(ctx goContext.Context, restoreID string) { + if restoreID == "" { + fs.mf = pgalloc.MemoryFileFromContext(ctx) + return + } + mfmap := pgalloc.MemoryFileMapFromContext(ctx) + if mfmap == nil { + panic("CtxMemoryFileMap was not provided") + } + mf, ok := mfmap[restoreID] + if !ok { + panic(fmt.Sprintf("Memory file for %q not found in CtxMemoryFileMap", restoreID)) + } + fs.mf = mf } // saveParent is called by stateify. @@ -42,34 +60,23 @@ func (d *dentry) loadParent(_ goContext.Context, parent *dentry) { // PrepareSave implements vfs.FilesystemImplSaveRestoreExtension.PrepareSave. func (fs *filesystem) PrepareSave(ctx context.Context) error { - if !fs.privateMF { + restoreID := fs.mf.RestoreID() + if restoreID == "" { return nil } mfmap := pgalloc.MemoryFileMapFromContext(ctx) if mfmap == nil { return fmt.Errorf("CtxMemoryFileMap was not provided") } - if _, ok := mfmap[fs.uniqueID.String()]; ok { - return fmt.Errorf("memory file for %q already exists in CtxMemoryFileMap", fs.uniqueID) + if _, ok := mfmap[restoreID]; ok { + return fmt.Errorf("memory file for %q already exists in CtxMemoryFileMap", restoreID) } - mfmap[fs.uniqueID.String()] = fs.mf + mfmap[restoreID] = fs.mf return nil } // CompleteRestore implements // vfs.FilesystemImplSaveRestoreExtension.CompleteRestore. func (fs *filesystem) CompleteRestore(ctx context.Context, opts vfs.CompleteRestoreOptions) error { - if !fs.privateMF { - return nil - } - mfmap := pgalloc.MemoryFileMapFromContext(ctx) - if mfmap == nil { - return fmt.Errorf("CtxMemoryFileMap was not provided") - } - mf, ok := mfmap[fs.uniqueID.String()] - if !ok { - return fmt.Errorf("memory file for %q not found in CtxMemoryFileMap", fs.uniqueID) - } - fs.mf = mf return nil } diff --git a/pkg/sentry/fsimpl/tmpfs/tmpfs.go b/pkg/sentry/fsimpl/tmpfs/tmpfs.go index d5359d7d6..f0996b7ec 100644 --- a/pkg/sentry/fsimpl/tmpfs/tmpfs.go +++ b/pkg/sentry/fsimpl/tmpfs/tmpfs.go @@ -63,20 +63,8 @@ type filesystem struct { vfsfs vfs.Filesystem // mf is used to allocate memory that stores regular file contents. mf is - // immutable, except it may to changed during restore. - mf *pgalloc.MemoryFile `state:"nosave"` - - // privateMF indicates whether mf is private to this tmpfs mount. If so, - // tmpfs takes ownership of mf. privateMF is immutable. - privateMF bool - - // uniqueID is an opaque string used to reassociate the filesystem with its - // private MemoryFile during checkpoint and restore. - uniqueID vfs.RestoreID - - // mfp is used to provide mf, when privateMF == false. This is required to - // re-provide mf on restore. mfp is immutable. - mfp pgalloc.MemoryFileProvider + // immutable, except it is changed during restore. + mf *pgalloc.MemoryFile `state:".(string)"` // clock is a realtime clock used to set timestamps in file operations. clock time.Clock @@ -156,10 +144,6 @@ type FilesystemOpts struct { // AllowXattrPrefix is a set of xattr namespace prefixes that this // tmpfs mount will allow. AllowXattrPrefix []string - - // If UniqueID is non-empty, it is an opaque string used to reassociate the - // filesystem with its private MemoryFile during checkpoint and restore. - UniqueID vfs.RestoreID } // Default size limit mount option. It is immutable after initialization. @@ -186,13 +170,10 @@ func getDefaultSizeLimit(disable bool) uint64 { // GetFilesystem implements vfs.FilesystemType.GetFilesystem. func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFilesystem, creds *auth.Credentials, _ string, opts vfs.GetFilesystemOptions) (*vfs.Filesystem, *vfs.Dentry, error) { - mfp := pgalloc.MemoryFileProviderFromContext(ctx) - if mfp == nil { - panic("MemoryFileProviderFromContext returned nil") + mf := pgalloc.MemoryFileFromContext(ctx) + if mf == nil { + panic("CtxMemoryFile returned nil") } - mf := mfp.MemoryFile() - privateMF := false - var uniqueID vfs.RestoreID rootFileType := uint16(linux.S_IFDIR) disableDefaultSizeLimit := false newFSType := vfs.FilesystemType(&fstype) @@ -218,17 +199,11 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt disableDefaultSizeLimit = tmpfsOpts.DisableDefaultSizeLimit if tmpfsOpts.MemoryFile != nil { mf = tmpfsOpts.MemoryFile - privateMF = true } - uniqueID = tmpfsOpts.UniqueID for _, xattr := range tmpfsOpts.AllowXattrPrefix { allowXattrPrefix[xattr] = struct{}{} } } - if privateMF && len(uniqueID.Path) == 0 { - ctx.Warningf("tmpfs.FilesystemType.GetFilesystem: privateMF requires uniqueID to be set") - return nil, nil, linuxerr.EINVAL - } mopts := vfs.GenericParseMountOptions(opts.Data) rootMode := linux.FileMode(0777) @@ -311,9 +286,6 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt } fs := filesystem{ mf: mf, - privateMF: privateMF, - uniqueID: uniqueID, - mfp: mfp, clock: clock, devMinor: devMinor, mopts: opts.Data, @@ -351,7 +323,9 @@ func (fs *filesystem) Release(ctx context.Context) { fs.root.releaseChildrenLocked(ctx) } fs.mu.Unlock() - if fs.privateMF { + if fs.mf.RestoreID() != "" { + // If RestoreID is set, then this is a private MemoryFile which needs to be + // destroyed since this tmpfs is the only user. fs.mf.Destroy() } } diff --git a/runsc/boot/vfs.go b/runsc/boot/vfs.go index a3e05dbb7..9e056024f 100644 --- a/runsc/boot/vfs.go +++ b/runsc/boot/vfs.go @@ -642,7 +642,6 @@ func (c *containerMounter) configureOverlay(ctx context.Context, conf *config.Co return nil, nil, fmt.Errorf("failed to create memory file for overlay: %v", err) } tmpfsOpts.MemoryFile = mf - tmpfsOpts.UniqueID = vfs.RestoreID{ContainerName: c.containerName, Path: dst} } upperOpts.GetFilesystemOptions.InternalData = tmpfsOpts upper, err := c.k.VFS().MountDisconnected(ctx, creds, "" /* source */, tmpfs.Name, &upperOpts) @@ -903,7 +902,6 @@ func getMountNameAndOptions(spec *specs.Spec, conf *config.Config, m *mountInfo, } internalData = tmpfs.FilesystemOpts{ MemoryFile: mf, - UniqueID: vfs.RestoreID{ContainerName: containerName, Path: m.mount.Destination}, // If a mount is being overlaid with tmpfs, it should not be limited by // the default tmpfs size limit. DisableDefaultSizeLimit: true,