/
err.go
60 lines (53 loc) · 1.57 KB
/
err.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package fsnodefuse
import (
"fmt"
"runtime/debug"
"sync/atomic"
"syscall"
"github.com/grailbio/base/errors"
"github.com/grailbio/base/log"
"github.com/hanwen/go-fuse/v2/fs"
)
// numHandledPanics is the total number of panics handled by handlePanicErrno.
// It can be used in testing to verify whether we triggered panics when
// handling operations. It must be accessed atomically, i.e. using atomic.*
// functions.
var numHandledPanics uint32
// handlePanicErrno is a last resort to prevent panics from reaching go-fuse and breaking the FUSE mount.
// All go-fuse-facing APIs that return Errno should defer it.
func handlePanicErrno(errno *syscall.Errno) {
r := recover()
if r == nil {
return
}
atomic.AddUint32(&numHandledPanics, 1)
*errno = errToErrno(makePanicErr(r))
}
// handlePanicErr is like handlePanicErrno but for APIs that don't return Errno.
func handlePanicErr(dst *error) {
r := recover()
if r == nil {
return
}
*dst = makePanicErr(r)
}
func makePanicErr(recovered interface{}) error {
if err, ok := recovered.(error); ok {
return errors.E(err, fmt.Sprintf("recovered panic, stack:\n%v", string(debug.Stack())))
}
return errors.E(fmt.Sprintf("recovered panic: %v, stack:\n%v", recovered, string(debug.Stack())))
}
func errToErrno(err error) syscall.Errno {
if err == nil {
return fs.OK
}
e := errors.Recover(err)
kind := e.Kind
errno, ok := kind.Errno()
if ok {
log.Error.Printf("returning errno: %v for error: %v", errno, e)
return errno
}
log.Error.Printf("error with no good errno match: kind: %v, err: %v", kind, err)
return syscall.EIO
}