Skip to content

Commit 8229bcb

Browse files
committed
Merge pull request #16346 from DARSHANR007:issue-16208/gofer-preparesave-stat
PiperOrigin-RevId: 1007824590
2 parents 05e46bd + fced933 commit 8229bcb

13 files changed

Lines changed: 66 additions & 19 deletions

File tree

‎pkg/sentry/control/controlapi/state.go‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ type SaveOpts struct {
7676

7777
// RunscVersion is the runsc binary version.
7878
RunscVersion string `json:"runsc_version"`
79+
80+
// ValidateMetadata indicates whether filesystem implementations backed by
81+
// remote filesystems should refresh metadata during save so that restore
82+
// can validate file sizes and/or modification timestamps.
83+
ValidateMetadata bool `json:"validate_metadata"`
7984
}
8085

8186
// SaveRestoreExecOpts contains options for executing a binary

‎pkg/sentry/control/state.go‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ func ConvertToStateSaveOpts(o *controlapi.SaveOpts) (*state.SaveOpts, error) {
7575
Resume: o.Resume,
7676
CudaCheckpointPath: o.CudaCheckpointPath,
7777
CudaCheckpointSequential: o.CudaCheckpointSequential,
78+
ValidateMetadata: o.ValidateMetadata,
7879
}
7980
if err := setSaveOpts(o, saveOpts); err != nil {
8081
saveOpts.Close()

‎pkg/sentry/fsimpl/fuse/host_connection_test.go‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"gvisor.dev/gvisor/pkg/marshal/primitive"
2727
"gvisor.dev/gvisor/pkg/sentry/kernel"
2828
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
29+
"gvisor.dev/gvisor/pkg/sentry/vfs"
2930
"gvisor.dev/gvisor/pkg/state"
3031
)
3132

@@ -418,7 +419,7 @@ func TestHostConnectionAbortedOnSave(t *testing.T) {
418419
id2, fut2 := registerOutstandingRequest(conn, creds)
419420

420421
fs := &filesystem{conn: conn}
421-
if err := fs.PrepareSave(s.Ctx); err != nil {
422+
if err := fs.PrepareSave(s.Ctx, vfs.PrepareSaveOptions{}); err != nil {
422423
t.Fatalf("PrepareSave: %v", err)
423424
}
424425
for id, fut := range map[linux.FUSEOpID]*futureResponse{id1: fut1, id2: fut2} {

‎pkg/sentry/fsimpl/fuse/save_restore.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func (lc *lostHostConn) release(ctx context.Context) {
6969
func (*lostHostConn) interrupt(*futureResponse) {}
7070

7171
// PrepareSave implements vfs.FilesystemImplSaveRestoreExtension.PrepareSave.
72-
func (fs *filesystem) PrepareSave(ctx context.Context) error {
72+
func (fs *filesystem) PrepareSave(ctx context.Context, _ vfs.PrepareSaveOptions) error {
7373
if fs.conn.hostTransport {
7474
// Connections to FUSE servers outside the sandbox can't be
7575
// preserved, since the host FD isn't saved. Abort the connection, as

‎pkg/sentry/fsimpl/gofer/directfs_inode.go‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,12 @@ func (fs *filesystem) newDirectfsDentry(controlFD int) (*dentry, error) {
148148
// This also avoids a correctness issue when a directory is bind-mounted on the host:
149149
// different paths (e.g., /mnt/ and /mnt/a/b/c if /mnt/a/b/c is a bind mount of /mnt/)
150150
// can return the same device ID and inode number from a stat call.
151+
var cacheHit bool
151152
temp.d.inode = fs.getOrCreateInode(inoKey /* dontCache = */, isDir,
152-
func() { _ = unix.Close(controlFD) },
153+
func() {
154+
cacheHit = true
155+
_ = unix.Close(controlFD)
156+
},
153157
func() *inode {
154158
temp.i = directfsInode{
155159
inode: inode{
@@ -213,6 +217,12 @@ func (fs *filesystem) newDirectfsDentry(controlFD int) (*dentry, error) {
213217
}
214218
return inode
215219
})
220+
if cacheHit && !temp.d.inode.cachedMetadataAuthoritative() {
221+
i := temp.d.inode.impl.(*directfsInode)
222+
i.metadataMu.Lock()
223+
i.updateMetadataFromStatxLocked(&stat)
224+
i.metadataMu.Unlock()
225+
}
216226

217227
temp.d.init()
218228
// If this dentry adopted a cached inode that already carries a bound-socket

‎pkg/sentry/fsimpl/gofer/lisafs_inode.go‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,12 @@ func (fs *filesystem) newLisafsDentry(ctx context.Context, ino *lisafs.Inode) (*
129129
// This also avoids a correctness issue when a directory is bind-mounted on the host:
130130
// different paths (e.g., /mnt/ and /mnt/a/b/c if /mnt/a/b/c is a bind mount of /mnt/)
131131
// can return the same device ID and inode number from a stat call.
132+
var cacheHit bool
132133
temp.d.inode = fs.getOrCreateInode(inoKey /* dontCache = */, isDir,
133-
func() { fs.client.CloseFD(ctx, ino.ControlFD, false /* flush */) },
134+
func() {
135+
cacheHit = true
136+
fs.client.CloseFD(ctx, ino.ControlFD, false /* flush */)
137+
},
134138
func() *inode {
135139
temp.i = lisafsInode{
136140
inode: inode{
@@ -194,6 +198,12 @@ func (fs *filesystem) newLisafsDentry(ctx context.Context, ino *lisafs.Inode) (*
194198
}
195199
return inode
196200
})
201+
if cacheHit && !temp.d.inode.cachedMetadataAuthoritative() {
202+
i := temp.d.inode.impl.(*lisafsInode)
203+
i.metadataMu.Lock()
204+
i.updateMetadataFromStatxLocked(&ino.Stat)
205+
i.metadataMu.Unlock()
206+
}
197207

198208
temp.d.init()
199209
// If this dentry adopted a cached inode that already carries a bound-socket

‎pkg/sentry/fsimpl/gofer/save_restore.go‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ type savedDentryRW struct {
4545
}
4646

4747
// PrepareSave implements vfs.FilesystemImplSaveRestoreExtension.PrepareSave.
48-
func (fs *filesystem) PrepareSave(ctx context.Context) error {
48+
func (fs *filesystem) PrepareSave(ctx context.Context, opts vfs.PrepareSaveOptions) error {
4949
if len(fs.iopts.UniqueID.Path) == 0 {
5050
return fmt.Errorf("gofer.filesystem with no UniqueID cannot be saved")
5151
}
@@ -85,7 +85,7 @@ func (fs *filesystem) PrepareSave(ctx context.Context) error {
8585
return err
8686
}
8787

88-
return fs.root.prepareSaveRecursive(ctx)
88+
return fs.root.prepareSaveRecursive(ctx, opts)
8989
}
9090

9191
// Preconditions:
@@ -177,8 +177,8 @@ func (d *dentry) prepareSaveDeletedRegularFile(ctx context.Context) error {
177177
return nil
178178
}
179179

180-
func (d *dentry) prepareSaveRecursive(ctx context.Context) error {
181-
if d.inode.isRegularFile() && !d.inode.cachedMetadataAuthoritative() {
180+
func (d *dentry) prepareSaveRecursive(ctx context.Context, opts vfs.PrepareSaveOptions) error {
181+
if opts.ValidateMetadata && d.inode.isRegularFile() && !d.inode.cachedMetadataAuthoritative() {
182182
// Get updated metadata for d in case we need to perform metadata
183183
// validation during restore.
184184
if err := d.inode.updateMetadata(ctx); err != nil {
@@ -201,7 +201,7 @@ func (d *dentry) prepareSaveRecursive(ctx context.Context) error {
201201
delete(d.children, childName)
202202
continue
203203
}
204-
if err := child.prepareSaveRecursive(ctx); err != nil {
204+
if err := child.prepareSaveRecursive(ctx, opts); err != nil {
205205
return err
206206
}
207207
}

‎pkg/sentry/fsimpl/sys/save_restore.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626
var _ vfs.FilesystemImplSaveRestoreExtension = (*filesystem)(nil)
2727

2828
// PrepareSave implements vfs.FilesystemImplSaveRestoreExtension.PrepareSave.
29-
func (fs *filesystem) PrepareSave(ctx context.Context) error {
29+
func (fs *filesystem) PrepareSave(ctx context.Context, _ vfs.PrepareSaveOptions) error {
3030
return nil
3131
}
3232

‎pkg/sentry/fsimpl/tmpfs/save_restore.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func (i *inode) loadDefaultACL(_ goContext.Context, defaultACL *vfs.PosixACL) {
8282
}
8383

8484
// PrepareSave implements vfs.FilesystemImplSaveRestoreExtension.PrepareSave.
85-
func (fs *filesystem) PrepareSave(ctx context.Context) error {
85+
func (fs *filesystem) PrepareSave(ctx context.Context, _ vfs.PrepareSaveOptions) error {
8686
resourceID := fs.mf.ResourceID()
8787
if !resourceID.Ok() {
8888
return nil

‎pkg/sentry/kernel/kernel.go‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,7 @@ func savePrivateMFs(ctx context.Context, w io.Writer, mfsToSave map[checkpoint.R
804804
// +checklocksexclude:k.extMu
805805
// +checklocksexclude:k.runningTasksMu
806806
// +checklocksexclude:k.tasks.mu
807-
func (k *Kernel) SaveTo(ctx context.Context, stateFile, pagesMetadata io.WriteCloser, pagesFile stateio.AsyncWriter, appMFExcludeCommittedZeroPages, resume bool, fsOpts *FSSaveOpts) error {
807+
func (k *Kernel) SaveTo(ctx context.Context, stateFile, pagesMetadata io.WriteCloser, pagesFile stateio.AsyncWriter, appMFExcludeCommittedZeroPages, resume bool, fsOpts *FSSaveOpts, vfsOpts vfs.PrepareSaveOptions) error {
808808
// The bypass is part of the saved task state, so it is armed before the
809809
// state is written and covers both resuming after the save and restoring.
810810
k.armSeccompRestartSyscallBypasses()
@@ -831,14 +831,14 @@ func (k *Kernel) SaveTo(ctx context.Context, stateFile, pagesMetadata io.WriteCl
831831
defer fsCleanup.Clean()
832832

833833
return k.quiescePausedAnd(ctx, func() error {
834-
return k.saveToLocked(ctx, stateFile, pagesMetadata, pagesFile, appMFExcludeCommittedZeroPages, resume, fsOpts, &stateFileCleanup, &pagesCleanup, &fsCleanup)
834+
return k.saveToLocked(ctx, stateFile, pagesMetadata, pagesFile, appMFExcludeCommittedZeroPages, resume, fsOpts, vfsOpts, &stateFileCleanup, &pagesCleanup, &fsCleanup)
835835
})
836836
}
837837

838838
// saveToLocked saves the kernel state while the kernel is paused and quiesced.
839839
//
840840
// Preconditions: The kernel must be paused and quiesced.
841-
func (k *Kernel) saveToLocked(ctx context.Context, stateFile, pagesMetadata io.WriteCloser, pagesFile stateio.AsyncWriter, appMFExcludeCommittedZeroPages, resume bool, fsOpts *FSSaveOpts, stateFileCleanup, pagesCleanup, fsCleanup *cleanup.Cleanup) error {
841+
func (k *Kernel) saveToLocked(ctx context.Context, stateFile, pagesMetadata io.WriteCloser, pagesFile stateio.AsyncWriter, appMFExcludeCommittedZeroPages, resume bool, fsOpts *FSSaveOpts, vfsOpts vfs.PrepareSaveOptions, stateFileCleanup, pagesCleanup, fsCleanup *cleanup.Cleanup) error {
842842
saveStart := time.Now()
843843

844844
// Discard unsavable mappings, such as those for host file descriptors.
@@ -852,7 +852,7 @@ func (k *Kernel) saveToLocked(ctx context.Context, stateFile, pagesMetadata io.W
852852
// Prepare filesystems for saving. This must be done after
853853
// invalidateUnsavableMappings(), since dropping memory mappings may
854854
// affect filesystem state (e.g. page cache reference counts).
855-
if err := k.vfs.PrepareSave(vfsCtx); err != nil {
855+
if err := k.vfs.PrepareSave(vfsCtx, vfsOpts); err != nil {
856856
return err
857857
}
858858
// Mark all to-be-saved MemoryFiles as savable to inform kernel save below.

0 commit comments

Comments
 (0)