mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Report correct error when restore fails
When file corruption is detected, report vfs.ErrCorruption to distinguish corruption error from other restore errors. Updates #1035 PiperOrigin-RevId: 404588445
This commit is contained in:
committed by
gVisor bot
parent
bdf4e41c86
commit
c23d67f3c0
@@ -277,18 +277,18 @@ func (d *dentry) restoreFile(ctx context.Context, file p9file, qid p9.QID, attrM
|
||||
if d.isRegularFile() {
|
||||
if opts.ValidateFileSizes {
|
||||
if !attrMask.Size {
|
||||
return fmt.Errorf("gofer.dentry(%q).restoreFile: file size validation failed: file size not available", genericDebugPathname(d))
|
||||
return vfs.ErrCorruption{fmt.Errorf("gofer.dentry(%q).restoreFile: file size validation failed: file size not available", genericDebugPathname(d))}
|
||||
}
|
||||
if d.size != attr.Size {
|
||||
return fmt.Errorf("gofer.dentry(%q).restoreFile: file size validation failed: size changed from %d to %d", genericDebugPathname(d), d.size, attr.Size)
|
||||
return vfs.ErrCorruption{fmt.Errorf("gofer.dentry(%q).restoreFile: file size validation failed: size changed from %d to %d", genericDebugPathname(d), d.size, attr.Size)}
|
||||
}
|
||||
}
|
||||
if opts.ValidateFileModificationTimestamps {
|
||||
if !attrMask.MTime {
|
||||
return fmt.Errorf("gofer.dentry(%q).restoreFile: mtime validation failed: mtime not available", genericDebugPathname(d))
|
||||
return vfs.ErrCorruption{fmt.Errorf("gofer.dentry(%q).restoreFile: mtime validation failed: mtime not available", genericDebugPathname(d))}
|
||||
}
|
||||
if want := dentryTimestampFromP9(attr.MTimeSeconds, attr.MTimeNanoSeconds); d.mtime != want {
|
||||
return fmt.Errorf("gofer.dentry(%q).restoreFile: mtime validation failed: mtime changed from %+v to %+v", genericDebugPathname(d), linux.NsecToStatxTimestamp(d.mtime), linux.NsecToStatxTimestamp(want))
|
||||
return vfs.ErrCorruption{fmt.Errorf("gofer.dentry(%q).restoreFile: mtime validation failed: mtime changed from %+v to %+v", genericDebugPathname(d), linux.NsecToStatxTimestamp(d.mtime), linux.NsecToStatxTimestamp(want))}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -326,18 +326,18 @@ func (d *dentry) restoreFileLisa(ctx context.Context, inode *lisafs.Inode, opts
|
||||
if d.isRegularFile() {
|
||||
if opts.ValidateFileSizes {
|
||||
if inode.Stat.Mask&linux.STATX_SIZE != 0 {
|
||||
return fmt.Errorf("gofer.dentry(%q).restoreFile: file size validation failed: file size not available", genericDebugPathname(d))
|
||||
return vfs.ErrCorruption{fmt.Errorf("gofer.dentry(%q).restoreFile: file size validation failed: file size not available", genericDebugPathname(d))}
|
||||
}
|
||||
if d.size != inode.Stat.Size {
|
||||
return fmt.Errorf("gofer.dentry(%q).restoreFile: file size validation failed: size changed from %d to %d", genericDebugPathname(d), d.size, inode.Stat.Size)
|
||||
return vfs.ErrCorruption{fmt.Errorf("gofer.dentry(%q).restoreFile: file size validation failed: size changed from %d to %d", genericDebugPathname(d), d.size, inode.Stat.Size)}
|
||||
}
|
||||
}
|
||||
if opts.ValidateFileModificationTimestamps {
|
||||
if inode.Stat.Mask&linux.STATX_MTIME != 0 {
|
||||
return fmt.Errorf("gofer.dentry(%q).restoreFile: mtime validation failed: mtime not available", genericDebugPathname(d))
|
||||
return vfs.ErrCorruption{fmt.Errorf("gofer.dentry(%q).restoreFile: mtime validation failed: mtime not available", genericDebugPathname(d))}
|
||||
}
|
||||
if want := dentryTimestampFromLisa(inode.Stat.Mtime); d.mtime != want {
|
||||
return fmt.Errorf("gofer.dentry(%q).restoreFile: mtime validation failed: mtime changed from %+v to %+v", genericDebugPathname(d), linux.NsecToStatxTimestamp(d.mtime), linux.NsecToStatxTimestamp(want))
|
||||
return vfs.ErrCorruption{fmt.Errorf("gofer.dentry(%q).restoreFile: mtime validation failed: mtime changed from %+v to %+v", genericDebugPathname(d), linux.NsecToStatxTimestamp(d.mtime), linux.NsecToStatxTimestamp(want))}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
package vfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
@@ -24,6 +23,18 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
// ErrCorruption indicates a failed restore due to external file system state in
|
||||
// corruption.
|
||||
type ErrCorruption struct {
|
||||
// Err is the wrapped error.
|
||||
Err error
|
||||
}
|
||||
|
||||
// Error returns a sensible description of the restore error.
|
||||
func (e ErrCorruption) Error() string {
|
||||
return "restore failed due to external file system state in corruption: " + e.Err.Error()
|
||||
}
|
||||
|
||||
// FilesystemImplSaveRestoreExtension is an optional extension to
|
||||
// FilesystemImpl.
|
||||
type FilesystemImplSaveRestoreExtension interface {
|
||||
@@ -37,38 +48,30 @@ type FilesystemImplSaveRestoreExtension interface {
|
||||
|
||||
// PrepareSave prepares all filesystems for serialization.
|
||||
func (vfs *VirtualFilesystem) PrepareSave(ctx context.Context) error {
|
||||
failures := 0
|
||||
for fs := range vfs.getFilesystems() {
|
||||
if ext, ok := fs.impl.(FilesystemImplSaveRestoreExtension); ok {
|
||||
if err := ext.PrepareSave(ctx); err != nil {
|
||||
ctx.Warningf("%T.PrepareSave failed: %v", fs.impl, err)
|
||||
failures++
|
||||
fs.DecRef(ctx)
|
||||
return err
|
||||
}
|
||||
}
|
||||
fs.DecRef(ctx)
|
||||
}
|
||||
if failures != 0 {
|
||||
return fmt.Errorf("%d filesystems failed to prepare for serialization", failures)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CompleteRestore completes restoration from checkpoint for all filesystems
|
||||
// after deserialization.
|
||||
func (vfs *VirtualFilesystem) CompleteRestore(ctx context.Context, opts *CompleteRestoreOptions) error {
|
||||
failures := 0
|
||||
for fs := range vfs.getFilesystems() {
|
||||
if ext, ok := fs.impl.(FilesystemImplSaveRestoreExtension); ok {
|
||||
if err := ext.CompleteRestore(ctx, *opts); err != nil {
|
||||
ctx.Warningf("%T.CompleteRestore failed: %v", fs.impl, err)
|
||||
failures++
|
||||
fs.DecRef(ctx)
|
||||
return err
|
||||
}
|
||||
}
|
||||
fs.DecRef(ctx)
|
||||
}
|
||||
if failures != 0 {
|
||||
return fmt.Errorf("%d filesystems failed to complete restore after deserialization", failures)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user