Skip to content

Commit 78a667c

Browse files
committed
erofs: add checkpoint/restore support
Updates #8956 Signed-off-by: Tiwei Bie <[email protected]>
1 parent 396d0be commit 78a667c

File tree

4 files changed

+86
-1
lines changed

4 files changed

+86
-1
lines changed

pkg/erofs/erofs.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,25 @@ func OpenImage(src *os.File) (*Image, error) {
223223
return i, nil
224224
}
225225

226+
// UpdateImage updates the underlying image file. This is typically used in checkpoint/restore.
227+
//
228+
// On success, the ownership of src is transferred to Image.
229+
//
230+
// Preconditions:
231+
// - i.src == nil.
232+
// - i.bytes == nil.
233+
func (i *Image) UpdateImage(src *os.File) error {
234+
newImage, err := OpenImage(src)
235+
if err != nil {
236+
return err
237+
}
238+
if newImage.sb != i.sb {
239+
return fmt.Errorf("superblock mismatch detected, got %+v, expected %+v", newImage.sb, i.sb)
240+
}
241+
*i = *newImage
242+
return nil
243+
}
244+
226245
// Close closes the image.
227246
func (i *Image) Close() {
228247
unix.Munmap(i.bytes)

pkg/sentry/fsimpl/erofs/erofs.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"gvisor.dev/gvisor/pkg/erofs"
2929
"gvisor.dev/gvisor/pkg/errors/linuxerr"
3030
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
31+
"gvisor.dev/gvisor/pkg/sentry/memmap"
3132
"gvisor.dev/gvisor/pkg/sentry/vfs"
3233
)
3334

@@ -51,6 +52,7 @@ type filesystem struct {
5152

5253
// Immutable options.
5354
mopts string
55+
iopts InternalFilesystemOptions
5456

5557
// devMinor is the filesystem's minor device number. devMinor is immutable.
5658
devMinor uint32
@@ -70,6 +72,16 @@ type filesystem struct {
7072
inodeBuckets []inodeBucket
7173
}
7274

75+
// InternalFilesystemOptions may be passed as
76+
// vfs.GetFilesystemOptions.InternalData to FilesystemType.GetFilesystem.
77+
//
78+
// +stateify savable
79+
type InternalFilesystemOptions struct {
80+
// If UniqueID is non-empty, it is an opaque string used to reassociate the
81+
// filesystem with a new image FD during restoration from checkpoint.
82+
UniqueID string
83+
}
84+
7385
// Name implements vfs.FilesystemType.Name.
7486
func (FilesystemType) Name() string {
7587
return Name
@@ -98,13 +110,20 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
98110
}
99111
cu.Add(func() { image.Close() })
100112

113+
iopts, ok := opts.InternalData.(InternalFilesystemOptions)
114+
if opts.InternalData != nil && !ok {
115+
ctx.Warningf("erofs.FilesystemType.GetFilesystem: GetFilesystemOptions.InternalData has type %T, wanted erofs.InternalFilesystemOptions", opts.InternalData)
116+
return nil, nil, linuxerr.EINVAL
117+
}
118+
101119
devMinor, err := vfsObj.GetAnonBlockDevMinor()
102120
if err != nil {
103121
return nil, nil, err
104122
}
105123

106124
fs := &filesystem{
107125
mopts: opts.Data,
126+
iopts: iopts,
108127
image: image,
109128
devMinor: devMinor,
110129
mf: imageMemmapFile{image: image},
@@ -243,6 +262,14 @@ type inode struct {
243262
// +checklocks:dirMu
244263
dirents []vfs.Dirent `state:"nosave"`
245264

265+
// mapsMu protects mappings.
266+
mapsMu sync.Mutex `state:"nosave"`
267+
268+
// mappings tracks the mappings of the file into memmap.MappingSpaces
269+
// if this inode represents a regular file.
270+
// +checklocks:mapsMu
271+
mappings memmap.MappingSet
272+
246273
// locks supports POSIX and BSD style locks.
247274
locks vfs.FileLocks
248275

pkg/sentry/fsimpl/erofs/regular_file.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,15 +131,22 @@ func (fd *regularFileFD) ConfigureMMap(ctx context.Context, opts *memmap.MMapOpt
131131

132132
// AddMapping implements memmap.Mappable.AddMapping.
133133
func (i *inode) AddMapping(ctx context.Context, ms memmap.MappingSpace, ar hostarch.AddrRange, offset uint64, writable bool) error {
134+
i.mapsMu.Lock()
135+
i.mappings.AddMapping(ms, ar, offset, writable)
136+
i.mapsMu.Unlock()
134137
return nil
135138
}
136139

137140
// RemoveMapping implements memmap.Mappable.RemoveMapping.
138141
func (i *inode) RemoveMapping(ctx context.Context, ms memmap.MappingSpace, ar hostarch.AddrRange, offset uint64, writable bool) {
142+
i.mapsMu.Lock()
143+
i.mappings.RemoveMapping(ms, ar, offset, writable)
144+
i.mapsMu.Unlock()
139145
}
140146

141147
// CopyMapping implements memmap.Mappable.CopyMapping.
142148
func (i *inode) CopyMapping(ctx context.Context, ms memmap.MappingSpace, srcAR, dstAR hostarch.AddrRange, offset uint64, writable bool) error {
149+
i.AddMapping(ctx, ms, dstAR, offset, writable)
143150
return nil
144151
}
145152

@@ -175,6 +182,9 @@ func (i *inode) Translate(ctx context.Context, required, optional memmap.Mappabl
175182

176183
// InvalidateUnsavable implements memmap.Mappable.InvalidateUnsavable.
177184
func (i *inode) InvalidateUnsavable(ctx context.Context) error {
185+
i.mapsMu.Lock()
186+
i.mappings.InvalidateAll(memmap.InvalidateOpts{})
187+
i.mapsMu.Unlock()
178188
return nil
179189
}
180190

pkg/sentry/fsimpl/erofs/save_restore.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,36 @@
1414

1515
package erofs
1616

17-
// TODO: support checkpoint/restore.
17+
import (
18+
"fmt"
19+
"os"
20+
21+
"gvisor.dev/gvisor/pkg/context"
22+
"gvisor.dev/gvisor/pkg/sentry/vfs"
23+
)
24+
25+
// Compile-time assertion that filesystem implements vfs.FilesystemImplSaveRestoreExtension.
26+
var _ = vfs.FilesystemImplSaveRestoreExtension((*filesystem)(nil))
27+
28+
// PreprareSave implements vfs.FilesystemImplSaveRestoreExtension.PrepareSave.
29+
func (fs *filesystem) PrepareSave(ctx context.Context) error {
30+
return nil
31+
}
32+
33+
// CompleteRestore implements
34+
// vfs.FilesystemImplSaveRestoreExtension.CompleteRestore.
35+
func (fs *filesystem) CompleteRestore(ctx context.Context, opts vfs.CompleteRestoreOptions) error {
36+
fdmapv := ctx.Value(vfs.CtxRestoreFilesystemFDMap)
37+
if fdmapv == nil {
38+
return fmt.Errorf("no image FD map available")
39+
}
40+
fdmap := fdmapv.(map[string]int)
41+
fd, ok := fdmap[fs.iopts.UniqueID]
42+
if !ok {
43+
return fmt.Errorf("no image FD available for filesystem with unique ID %q", fs.iopts.UniqueID)
44+
}
45+
return fs.image.UpdateImage(os.NewFile(uintptr(fd), "EROFS image file"))
46+
}
1847

1948
// saveParent is called by stateify.
2049
func (d *dentry) saveParent() *dentry {

0 commit comments

Comments
 (0)