Update tmpfs to restore its MemoryFile using stateify tools.

PiperOrigin-RevId: 615233954
This commit is contained in:
Ayush Ranjan
2024-03-12 17:58:38 -07:00
committed by gVisor bot
parent d432952bbe
commit 3b314aad88
3 changed files with 35 additions and 56 deletions
+27 -20
View File
@@ -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
}
+8 -34
View File
@@ -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()
}
}