diff options
author | Zhaozhong Ni <nzz@google.com> | 2018-05-08 11:36:11 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-05-08 11:36:59 -0700 |
commit | 174161013de22be6a42b02ee06611a9de9e20b18 (patch) | |
tree | b910f76ea3ba8b14a29df2d28010fd0af1db18bb /pkg/sentry/fs/fs.go | |
parent | 3ac3ea1d6afea0b128112e6a46b8bf47b4b0e02a (diff) |
Capture restore file system corruption errors in exit error.
PiperOrigin-RevId: 195850822
Change-Id: I4d7bdd8fe129c5ed461b73e1d7458be2cf5680c2
Diffstat (limited to 'pkg/sentry/fs/fs.go')
-rw-r--r-- | pkg/sentry/fs/fs.go | 63 |
1 files changed, 60 insertions, 3 deletions
diff --git a/pkg/sentry/fs/fs.go b/pkg/sentry/fs/fs.go index f54f767d3..6ec9ff446 100644 --- a/pkg/sentry/fs/fs.go +++ b/pkg/sentry/fs/fs.go @@ -55,11 +55,19 @@ package fs import ( "sync" + + "gvisor.googlesource.com/gvisor/pkg/log" ) -// work is a sync.WaitGroup that can be used to queue asynchronous operations -// via Do. Callers can use Barrier to ensure no operations are outstanding. -var work sync.WaitGroup +var ( + // work is a sync.WaitGroup that can be used to queue asynchronous + // operations via Do. Callers can use Barrier to ensure no operations + // are outstanding. + work sync.WaitGroup + + // asyncError is used to store up to one asynchronous execution error. + asyncError = make(chan error, 1) +) // AsyncBarrier waits for all outstanding asynchronous work to complete. func AsyncBarrier() { @@ -75,6 +83,43 @@ func Async(f func()) { }() } +// AsyncErrorBarrier waits for all outstanding asynchronous work to complete, or +// the first async error to arrive. Other unfinished async executions will +// continue in the background. Other past and future async errors are ignored. +func AsyncErrorBarrier() error { + wait := make(chan struct{}, 1) + go func() { // S/R-SAFE: Does not touch persistent state. + work.Wait() + wait <- struct{}{} + }() + select { + case <-wait: + select { + case err := <-asyncError: + return err + default: + return nil + } + case err := <-asyncError: + return err + } +} + +// CatchError tries to capture the potential async error returned by the +// function. At most one async error will be captured globally so excessive +// errors will be dropped. +func CatchError(f func() error) func() { + return func() { + if err := f(); err != nil { + select { + case asyncError <- err: + default: + log.Warningf("excessive async error dropped: %v", err) + } + } + } +} + // ErrSaveRejection indicates a failed save due to unsupported file system state // such as dangling open fd, etc. type ErrSaveRejection struct { @@ -86,3 +131,15 @@ type ErrSaveRejection struct { func (e ErrSaveRejection) Error() string { return "save rejected due to unsupported file system state: " + e.Err.Error() } + +// 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 save rejection error. +func (e ErrCorruption) Error() string { + return "restore failed due to external file system state in corruption: " + e.Err.Error() +} |