mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Merge pull request #9577 from btw616:erofs-checkpoint-restore-support
PiperOrigin-RevId: 576593626
This commit is contained in:
@@ -229,6 +229,11 @@ func (i *Image) Close() {
|
||||
i.src.Close()
|
||||
}
|
||||
|
||||
// SuperBlock returns a copy of the image's superblock.
|
||||
func (i *Image) SuperBlock() SuperBlock {
|
||||
return i.sb
|
||||
}
|
||||
|
||||
// BlockSize returns the block size of this image.
|
||||
func (i *Image) BlockSize() uint32 {
|
||||
return i.sb.BlockSize()
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/erofs"
|
||||
"gvisor.dev/gvisor/pkg/errors/linuxerr"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/memmap"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
)
|
||||
|
||||
@@ -51,6 +52,7 @@ type filesystem struct {
|
||||
|
||||
// Immutable options.
|
||||
mopts string
|
||||
iopts InternalFilesystemOptions
|
||||
|
||||
// devMinor is the filesystem's minor device number. devMinor is immutable.
|
||||
devMinor uint32
|
||||
@@ -70,6 +72,16 @@ type filesystem struct {
|
||||
inodeBuckets []inodeBucket
|
||||
}
|
||||
|
||||
// InternalFilesystemOptions may be passed as
|
||||
// vfs.GetFilesystemOptions.InternalData to FilesystemType.GetFilesystem.
|
||||
//
|
||||
// +stateify savable
|
||||
type InternalFilesystemOptions struct {
|
||||
// If UniqueID is non-empty, it is an opaque string used to reassociate the
|
||||
// filesystem with a new image FD during restoration from checkpoint.
|
||||
UniqueID string
|
||||
}
|
||||
|
||||
// Name implements vfs.FilesystemType.Name.
|
||||
func (FilesystemType) Name() string {
|
||||
return Name
|
||||
@@ -98,6 +110,12 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
||||
}
|
||||
cu.Add(func() { image.Close() })
|
||||
|
||||
iopts, ok := opts.InternalData.(InternalFilesystemOptions)
|
||||
if opts.InternalData != nil && !ok {
|
||||
ctx.Warningf("erofs.FilesystemType.GetFilesystem: GetFilesystemOptions.InternalData has type %T, wanted erofs.InternalFilesystemOptions", opts.InternalData)
|
||||
return nil, nil, linuxerr.EINVAL
|
||||
}
|
||||
|
||||
devMinor, err := vfsObj.GetAnonBlockDevMinor()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -105,6 +123,7 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
||||
|
||||
fs := &filesystem{
|
||||
mopts: opts.Data,
|
||||
iopts: iopts,
|
||||
image: image,
|
||||
devMinor: devMinor,
|
||||
mf: imageMemmapFile{image: image},
|
||||
@@ -243,6 +262,14 @@ type inode struct {
|
||||
// +checklocks:dirMu
|
||||
dirents []vfs.Dirent `state:"nosave"`
|
||||
|
||||
// mapsMu protects mappings.
|
||||
mapsMu sync.Mutex `state:"nosave"`
|
||||
|
||||
// mappings tracks the mappings of the file into memmap.MappingSpaces
|
||||
// if this inode represents a regular file.
|
||||
// +checklocks:mapsMu
|
||||
mappings memmap.MappingSet
|
||||
|
||||
// locks supports POSIX and BSD style locks.
|
||||
locks vfs.FileLocks
|
||||
|
||||
|
||||
@@ -131,15 +131,22 @@ func (fd *regularFileFD) ConfigureMMap(ctx context.Context, opts *memmap.MMapOpt
|
||||
|
||||
// AddMapping implements memmap.Mappable.AddMapping.
|
||||
func (i *inode) AddMapping(ctx context.Context, ms memmap.MappingSpace, ar hostarch.AddrRange, offset uint64, writable bool) error {
|
||||
i.mapsMu.Lock()
|
||||
i.mappings.AddMapping(ms, ar, offset, writable)
|
||||
i.mapsMu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveMapping implements memmap.Mappable.RemoveMapping.
|
||||
func (i *inode) RemoveMapping(ctx context.Context, ms memmap.MappingSpace, ar hostarch.AddrRange, offset uint64, writable bool) {
|
||||
i.mapsMu.Lock()
|
||||
i.mappings.RemoveMapping(ms, ar, offset, writable)
|
||||
i.mapsMu.Unlock()
|
||||
}
|
||||
|
||||
// CopyMapping implements memmap.Mappable.CopyMapping.
|
||||
func (i *inode) CopyMapping(ctx context.Context, ms memmap.MappingSpace, srcAR, dstAR hostarch.AddrRange, offset uint64, writable bool) error {
|
||||
i.AddMapping(ctx, ms, dstAR, offset, writable)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -175,6 +182,9 @@ func (i *inode) Translate(ctx context.Context, required, optional memmap.Mappabl
|
||||
|
||||
// InvalidateUnsavable implements memmap.Mappable.InvalidateUnsavable.
|
||||
func (i *inode) InvalidateUnsavable(ctx context.Context) error {
|
||||
i.mapsMu.Lock()
|
||||
i.mappings.InvalidateAll(memmap.InvalidateOpts{})
|
||||
i.mapsMu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,45 @@
|
||||
|
||||
package erofs
|
||||
|
||||
// TODO: support checkpoint/restore.
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/erofs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
)
|
||||
|
||||
// Compile-time assertion that filesystem implements vfs.FilesystemImplSaveRestoreExtension.
|
||||
var _ = vfs.FilesystemImplSaveRestoreExtension((*filesystem)(nil))
|
||||
|
||||
// PreprareSave implements vfs.FilesystemImplSaveRestoreExtension.PrepareSave.
|
||||
func (fs *filesystem) PrepareSave(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CompleteRestore implements
|
||||
// vfs.FilesystemImplSaveRestoreExtension.CompleteRestore.
|
||||
func (fs *filesystem) CompleteRestore(ctx context.Context, opts vfs.CompleteRestoreOptions) error {
|
||||
fdmapv := ctx.Value(vfs.CtxRestoreFilesystemFDMap)
|
||||
if fdmapv == nil {
|
||||
return fmt.Errorf("no image FD map available")
|
||||
}
|
||||
fdmap := fdmapv.(map[string]int)
|
||||
fd, ok := fdmap[fs.iopts.UniqueID]
|
||||
if !ok {
|
||||
return fmt.Errorf("no image FD available for filesystem with unique ID %q", fs.iopts.UniqueID)
|
||||
}
|
||||
newImage, err := erofs.OpenImage(os.NewFile(uintptr(fd), "EROFS image file"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if got, want := newImage.SuperBlock(), fs.image.SuperBlock(); got != want {
|
||||
return fmt.Errorf("superblock mismatch detected on restore, got %+v, expected %+v", got, want)
|
||||
}
|
||||
fs.image = newImage
|
||||
return nil
|
||||
}
|
||||
|
||||
// saveParent is called by stateify.
|
||||
func (d *dentry) saveParent() *dentry {
|
||||
|
||||
@@ -29,15 +29,6 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
)
|
||||
|
||||
type saveRestoreContextID int
|
||||
|
||||
const (
|
||||
// CtxRestoreServerFDMap is a Context.Value key for a map[string]int
|
||||
// mapping filesystem unique IDs (cf. InternalFilesystemOptions.UniqueID)
|
||||
// to host FDs.
|
||||
CtxRestoreServerFDMap saveRestoreContextID = iota
|
||||
)
|
||||
|
||||
// +stateify savable
|
||||
type savedDentryRW struct {
|
||||
read bool
|
||||
@@ -181,7 +172,7 @@ func (d *dentry) loadParent(parent *dentry) {
|
||||
// CompleteRestore implements
|
||||
// vfs.FilesystemImplSaveRestoreExtension.CompleteRestore.
|
||||
func (fs *filesystem) CompleteRestore(ctx context.Context, opts vfs.CompleteRestoreOptions) error {
|
||||
fdmapv := ctx.Value(CtxRestoreServerFDMap)
|
||||
fdmapv := ctx.Value(vfs.CtxRestoreFilesystemFDMap)
|
||||
if fdmapv == nil {
|
||||
return fmt.Errorf("no server FD map available")
|
||||
}
|
||||
|
||||
@@ -27,6 +27,11 @@ const (
|
||||
|
||||
// CtxRoot is a Context.Value key for a VFS root.
|
||||
CtxRoot
|
||||
|
||||
// CtxRestoreFilesystemFDMap is a Context.Value key for a map[string]int
|
||||
// mapping filesystem unique IDs (cf. gofer.InternalFilesystemOptions.UniqueID)
|
||||
// to host FDs.
|
||||
CtxRestoreFilesystemFDMap
|
||||
)
|
||||
|
||||
// MountNamespaceFromContext returns the MountNamespace used by ctx. If ctx is
|
||||
|
||||
+1
-1
@@ -1087,7 +1087,7 @@ func (c *containerMounter) configureRestore(ctx context.Context) (context.Contex
|
||||
fdmap[submount.mount.Destination] = submount.goferFD.Release()
|
||||
}
|
||||
}
|
||||
return context.WithValue(ctx, gofer.CtxRestoreServerFDMap, fdmap), nil
|
||||
return context.WithValue(ctx, vfs.CtxRestoreFilesystemFDMap, fdmap), nil
|
||||
}
|
||||
|
||||
func createDeviceFiles(ctx context.Context, creds *auth.Credentials, info *containerInfo, vfsObj *vfs.VirtualFilesystem, root vfs.VirtualDentry) error {
|
||||
|
||||
Reference in New Issue
Block a user