summaryrefslogtreecommitdiffhomepage
path: root/pkg/errors
diff options
context:
space:
mode:
authorZach Koopmans <zkoopmans@google.com>2021-06-16 14:06:01 -0700
committergVisor bot <gvisor-bot@google.com>2021-06-16 14:08:52 -0700
commit63b4f6e296a8f131ec969a685f0e31663be58385 (patch)
tree2bf10bff66a654b1bca5d27598a142fc68ca9430 /pkg/errors
parent47149b7c4275ddd4404d86eddab6feab4f059ed3 (diff)
[syserror] Refactor linuxerr and error package.
Move Error struct to pkg/errors package for use in multiple places. Move linuxerr static definitions under pkg/errors/linuxerr. Add a lookup list for quick lookup of *errors.Error by errno. This is useful when converting syserror errors and unix.Errno/syscall.Errrno values to *errors.Error. Update benchmarks routines to include conversions. The below benchmarks show *errors.Error usage to be comparable to using unix.Errno. BenchmarkAssignUnix BenchmarkAssignUnix-32 787875022 1.284 ns/op BenchmarkAssignLinuxerr BenchmarkAssignLinuxerr-32 1000000000 1.209 ns/op BenchmarkAssignSyserror BenchmarkAssignSyserror-32 759269229 1.429 ns/op BenchmarkCompareUnix BenchmarkCompareUnix-32 1000000000 1.310 ns/op BenchmarkCompareLinuxerr BenchmarkCompareLinuxerr-32 1000000000 1.241 ns/op BenchmarkCompareSyserror BenchmarkCompareSyserror-32 147196165 8.248 ns/op BenchmarkSwitchUnix BenchmarkSwitchUnix-32 373233556 3.664 ns/op BenchmarkSwitchLinuxerr BenchmarkSwitchLinuxerr-32 476323929 3.294 ns/op BenchmarkSwitchSyserror BenchmarkSwitchSyserror-32 39293408 29.62 ns/op BenchmarkReturnUnix BenchmarkReturnUnix-32 1000000000 0.5042 ns/op BenchmarkReturnLinuxerr BenchmarkReturnLinuxerr-32 1000000000 0.8152 ns/op BenchmarkConvertUnixLinuxerr BenchmarkConvertUnixLinuxerr-32 739948875 1.547 ns/op BenchmarkConvertUnixLinuxerrZero BenchmarkConvertUnixLinuxerrZero-32 977733974 1.489 ns/op PiperOrigin-RevId: 379806801
Diffstat (limited to 'pkg/errors')
-rw-r--r--pkg/errors/BUILD10
-rw-r--r--pkg/errors/errors.go40
-rw-r--r--pkg/errors/linuxerr/BUILD25
-rw-r--r--pkg/errors/linuxerr/linuxerr.go326
-rw-r--r--pkg/errors/linuxerr/linuxerr_test.go245
5 files changed, 646 insertions, 0 deletions
diff --git a/pkg/errors/BUILD b/pkg/errors/BUILD
new file mode 100644
index 000000000..36ea5da0c
--- /dev/null
+++ b/pkg/errors/BUILD
@@ -0,0 +1,10 @@
+load("//tools:defs.bzl", "go_library")
+
+package(licenses = ["notice"])
+
+go_library(
+ name = "errors",
+ srcs = ["errors.go"],
+ visibility = ["//:sandbox"],
+ deps = ["//pkg/abi/linux/errno"],
+)
diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go
new file mode 100644
index 000000000..7984a770e
--- /dev/null
+++ b/pkg/errors/errors.go
@@ -0,0 +1,40 @@
+// Copyright 2021 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package errors holds the standardized error definition for gVisor.
+package errors
+
+import (
+ "gvisor.dev/gvisor/pkg/abi/linux/errno"
+)
+
+// Error represents a syscall errno with a descriptive message.
+type Error struct {
+ errno errno.Errno
+ message string
+}
+
+// New creates a new *Error.
+func New(err errno.Errno, message string) *Error {
+ return &Error{
+ errno: err,
+ message: message,
+ }
+}
+
+// Error implements error.Error.
+func (e *Error) Error() string { return e.message }
+
+// Errno returns the underlying errno.Errno value.
+func (e *Error) Errno() errno.Errno { return e.errno }
diff --git a/pkg/errors/linuxerr/BUILD b/pkg/errors/linuxerr/BUILD
new file mode 100644
index 000000000..8afc9688c
--- /dev/null
+++ b/pkg/errors/linuxerr/BUILD
@@ -0,0 +1,25 @@
+load("//tools:defs.bzl", "go_library", "go_test")
+
+package(licenses = ["notice"])
+
+go_library(
+ name = "linuxerr",
+ srcs = ["linuxerr.go"],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//pkg/abi/linux/errno",
+ "//pkg/errors",
+ ],
+)
+
+go_test(
+ name = "linuxerr_test",
+ srcs = ["linuxerr_test.go"],
+ deps = [
+ ":linuxerr",
+ "//pkg/abi/linux/errno",
+ "//pkg/errors",
+ "//pkg/syserror",
+ "@org_golang_x_sys//unix:go_default_library",
+ ],
+)
diff --git a/pkg/errors/linuxerr/linuxerr.go b/pkg/errors/linuxerr/linuxerr.go
new file mode 100644
index 000000000..23d9f9f75
--- /dev/null
+++ b/pkg/errors/linuxerr/linuxerr.go
@@ -0,0 +1,326 @@
+// Copyright 2021 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"),;
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package linuxerr contains syscall error codes exported as an error interface
+// pointers. This allows for fast comparison and return operations comperable
+// to unix.Errno constants.
+package linuxerr
+
+import (
+ "fmt"
+
+ "gvisor.dev/gvisor/pkg/abi/linux/errno"
+ "gvisor.dev/gvisor/pkg/errors"
+)
+
+const maxErrno uint32 = errno.EHWPOISON + 1
+
+var (
+ EPERM = errors.New(errno.EPERM, "operation not permitted")
+ ENOENT = errors.New(errno.ENOENT, "no such file or directory")
+ ESRCH = errors.New(errno.ESRCH, "no such process")
+ EINTR = errors.New(errno.EINTR, "interrupted system call")
+ EIO = errors.New(errno.EIO, "I/O error")
+ ENXIO = errors.New(errno.ENXIO, "no such device or address")
+ E2BIG = errors.New(errno.E2BIG, "argument list too long")
+ ENOEXEC = errors.New(errno.ENOEXEC, "exec format error")
+ EBADF = errors.New(errno.EBADF, "bad file number")
+ ECHILD = errors.New(errno.ECHILD, "no child processes")
+ EAGAIN = errors.New(errno.EAGAIN, "try again")
+ ENOMEM = errors.New(errno.ENOMEM, "out of memory")
+ EACCES = errors.New(errno.EACCES, "permission denied")
+ EFAULT = errors.New(errno.EFAULT, "bad address")
+ ENOTBLK = errors.New(errno.ENOTBLK, "block device required")
+ EBUSY = errors.New(errno.EBUSY, "device or resource busy")
+ EEXIST = errors.New(errno.EEXIST, "file exists")
+ EXDEV = errors.New(errno.EXDEV, "cross-device link")
+ ENODEV = errors.New(errno.ENODEV, "no such device")
+ ENOTDIR = errors.New(errno.ENOTDIR, "not a directory")
+ EISDIR = errors.New(errno.EISDIR, "is a directory")
+ EINVAL = errors.New(errno.EINVAL, "invalid argument")
+ ENFILE = errors.New(errno.ENFILE, "file table overflow")
+ EMFILE = errors.New(errno.EMFILE, "too many open files")
+ ENOTTY = errors.New(errno.ENOTTY, "not a typewriter")
+ ETXTBSY = errors.New(errno.ETXTBSY, "text file busy")
+ EFBIG = errors.New(errno.EFBIG, "file too large")
+ ENOSPC = errors.New(errno.ENOSPC, "no space left on device")
+ ESPIPE = errors.New(errno.ESPIPE, "illegal seek")
+ EROFS = errors.New(errno.EROFS, "read-only file system")
+ EMLINK = errors.New(errno.EMLINK, "too many links")
+ EPIPE = errors.New(errno.EPIPE, "broken pipe")
+ EDOM = errors.New(errno.EDOM, "math argument out of domain of func")
+ ERANGE = errors.New(errno.ERANGE, "math result not representable")
+
+ // Errno values from include/uapi/asm-generic/errno.h.
+ EDEADLK = errors.New(errno.EDEADLK, "resource deadlock would occur")
+ ENAMETOOLONG = errors.New(errno.ENAMETOOLONG, "file name too long")
+ ENOLCK = errors.New(errno.ENOLCK, "no record locks available")
+ ENOSYS = errors.New(errno.ENOSYS, "invalid system call number")
+ ENOTEMPTY = errors.New(errno.ENOTEMPTY, "directory not empty")
+ ELOOP = errors.New(errno.ELOOP, "too many symbolic links encountered")
+ ENOMSG = errors.New(errno.ENOMSG, "no message of desired type")
+ EIDRM = errors.New(errno.EIDRM, "identifier removed")
+ ECHRNG = errors.New(errno.ECHRNG, "channel number out of range")
+ EL2NSYNC = errors.New(errno.EL2NSYNC, "level 2 not synchronized")
+ EL3HLT = errors.New(errno.EL3HLT, "level 3 halted")
+ EL3RST = errors.New(errno.EL3RST, "level 3 reset")
+ ELNRNG = errors.New(errno.ELNRNG, "link number out of range")
+ EUNATCH = errors.New(errno.EUNATCH, "protocol driver not attached")
+ ENOCSI = errors.New(errno.ENOCSI, "no CSI structure available")
+ EL2HLT = errors.New(errno.EL2HLT, "level 2 halted")
+ EBADE = errors.New(errno.EBADE, "invalid exchange")
+ EBADR = errors.New(errno.EBADR, "invalid request descriptor")
+ EXFULL = errors.New(errno.EXFULL, "exchange full")
+ ENOANO = errors.New(errno.ENOANO, "no anode")
+ EBADRQC = errors.New(errno.EBADRQC, "invalid request code")
+ EBADSLT = errors.New(errno.EBADSLT, "invalid slot")
+ EBFONT = errors.New(errno.EBFONT, "bad font file format")
+ ENOSTR = errors.New(errno.ENOSTR, "device not a stream")
+ ENODATA = errors.New(errno.ENODATA, "no data available")
+ ETIME = errors.New(errno.ETIME, "timer expired")
+ ENOSR = errors.New(errno.ENOSR, "out of streams resources")
+ ENOPKG = errors.New(errno.ENOPKG, "package not installed")
+ EREMOTE = errors.New(errno.EREMOTE, "object is remote")
+ ENOLINK = errors.New(errno.ENOLINK, "link has been severed")
+ EADV = errors.New(errno.EADV, "advertise error")
+ ESRMNT = errors.New(errno.ESRMNT, "srmount error")
+ ECOMM = errors.New(errno.ECOMM, "communication error on send")
+ EPROTO = errors.New(errno.EPROTO, "protocol error")
+ EMULTIHOP = errors.New(errno.EMULTIHOP, "multihop attempted")
+ EDOTDOT = errors.New(errno.EDOTDOT, "RFS specific error")
+ EBADMSG = errors.New(errno.EBADMSG, "not a data message")
+ EOVERFLOW = errors.New(errno.EOVERFLOW, "value too large for defined data type")
+ ENOTUNIQ = errors.New(errno.ENOTUNIQ, "name not unique on network")
+ EBADFD = errors.New(errno.EBADFD, "file descriptor in bad state")
+ EREMCHG = errors.New(errno.EREMCHG, "remote address changed")
+ ELIBACC = errors.New(errno.ELIBACC, "can not access a needed shared library")
+ ELIBBAD = errors.New(errno.ELIBBAD, "accessing a corrupted shared library")
+ ELIBSCN = errors.New(errno.ELIBSCN, ".lib section in a.out corrupted")
+ ELIBMAX = errors.New(errno.ELIBMAX, "attempting to link in too many shared libraries")
+ ELIBEXEC = errors.New(errno.ELIBEXEC, "cannot exec a shared library directly")
+ EILSEQ = errors.New(errno.EILSEQ, "illegal byte sequence")
+ ERESTART = errors.New(errno.ERESTART, "interrupted system call should be restarted")
+ ESTRPIPE = errors.New(errno.ESTRPIPE, "streams pipe error")
+ EUSERS = errors.New(errno.EUSERS, "too many users")
+ ENOTSOCK = errors.New(errno.ENOTSOCK, "socket operation on non-socket")
+ EDESTADDRREQ = errors.New(errno.EDESTADDRREQ, "destination address required")
+ EMSGSIZE = errors.New(errno.EMSGSIZE, "message too long")
+ EPROTOTYPE = errors.New(errno.EPROTOTYPE, "protocol wrong type for socket")
+ ENOPROTOOPT = errors.New(errno.ENOPROTOOPT, "protocol not available")
+ EPROTONOSUPPORT = errors.New(errno.EPROTONOSUPPORT, "protocol not supported")
+ ESOCKTNOSUPPORT = errors.New(errno.ESOCKTNOSUPPORT, "socket type not supported")
+ EOPNOTSUPP = errors.New(errno.EOPNOTSUPP, "operation not supported on transport endpoint")
+ EPFNOSUPPORT = errors.New(errno.EPFNOSUPPORT, "protocol family not supported")
+ EAFNOSUPPORT = errors.New(errno.EAFNOSUPPORT, "address family not supported by protocol")
+ EADDRINUSE = errors.New(errno.EADDRINUSE, "address already in use")
+ EADDRNOTAVAIL = errors.New(errno.EADDRNOTAVAIL, "cannot assign requested address")
+ ENETDOWN = errors.New(errno.ENETDOWN, "network is down")
+ ENETUNREACH = errors.New(errno.ENETUNREACH, "network is unreachable")
+ ENETRESET = errors.New(errno.ENETRESET, "network dropped connection because of reset")
+ ECONNABORTED = errors.New(errno.ECONNABORTED, "software caused connection abort")
+ ECONNRESET = errors.New(errno.ECONNRESET, "connection reset by peer")
+ ENOBUFS = errors.New(errno.ENOBUFS, "no buffer space available")
+ EISCONN = errors.New(errno.EISCONN, "transport endpoint is already connected")
+ ENOTCONN = errors.New(errno.ENOTCONN, "transport endpoint is not connected")
+ ESHUTDOWN = errors.New(errno.ESHUTDOWN, "cannot send after transport endpoint shutdown")
+ ETOOMANYREFS = errors.New(errno.ETOOMANYREFS, "too many references: cannot splice")
+ ETIMEDOUT = errors.New(errno.ETIMEDOUT, "connection timed out")
+ ECONNREFUSED = errors.New(errno.ECONNREFUSED, "connection refused")
+ EHOSTDOWN = errors.New(errno.EHOSTDOWN, "host is down")
+ EHOSTUNREACH = errors.New(errno.EHOSTUNREACH, "no route to host")
+ EALREADY = errors.New(errno.EALREADY, "operation already in progress")
+ EINPROGRESS = errors.New(errno.EINPROGRESS, "operation now in progress")
+ ESTALE = errors.New(errno.ESTALE, "stale file handle")
+ EUCLEAN = errors.New(errno.EUCLEAN, "structure needs cleaning")
+ ENOTNAM = errors.New(errno.ENOTNAM, "not a XENIX named type file")
+ ENAVAIL = errors.New(errno.ENAVAIL, "no XENIX semaphores available")
+ EISNAM = errors.New(errno.EISNAM, "is a named type file")
+ EREMOTEIO = errors.New(errno.EREMOTEIO, "remote I/O error")
+ EDQUOT = errors.New(errno.EDQUOT, "quota exceeded")
+ ENOMEDIUM = errors.New(errno.ENOMEDIUM, "no medium found")
+ EMEDIUMTYPE = errors.New(errno.EMEDIUMTYPE, "wrong medium type")
+ ECANCELED = errors.New(errno.ECANCELED, "operation Canceled")
+ ENOKEY = errors.New(errno.ENOKEY, "required key not available")
+ EKEYEXPIRED = errors.New(errno.EKEYEXPIRED, "key has expired")
+ EKEYREVOKED = errors.New(errno.EKEYREVOKED, "key has been revoked")
+ EKEYREJECTED = errors.New(errno.EKEYREJECTED, "key was rejected by service")
+ EOWNERDEAD = errors.New(errno.EOWNERDEAD, "owner died")
+ ENOTRECOVERABLE = errors.New(errno.ENOTRECOVERABLE, "state not recoverable")
+ ERFKILL = errors.New(errno.ERFKILL, "operation not possible due to RF-kill")
+ EHWPOISON = errors.New(errno.EHWPOISON, "memory page has hardware error")
+
+ // Errors equivalent to other errors.
+ EWOULDBLOCK = EAGAIN
+ EDEADLOCK = EDEADLK
+ ENONET = ENOENT
+)
+
+// A nil *errors.Error denotes no error and is placed at the 0 index of
+// errorSlice. Thus, any other empty index should not be nil or a valid error.
+// This marks that index as an invalid error so any comparison to nil or a
+// valid linuxerr fails.
+var errNotValidError = errors.New(errno.Errno(maxErrno), "not a valid error")
+
+// The following errorSlice holds errors by errno for fast translation between
+// errnos (especially uint32(sycall.Errno)) and *Error.
+var errorSlice = []*errors.Error{
+ // Errno values from include/uapi/asm-generic/errno-base.h.
+ errno.NOERRNO: nil,
+ errno.EPERM: EPERM,
+ errno.ENOENT: ENOENT,
+ errno.ESRCH: ESRCH,
+ errno.EINTR: EINTR,
+ errno.EIO: EIO,
+ errno.ENXIO: ENXIO,
+ errno.E2BIG: E2BIG,
+ errno.ENOEXEC: ENOEXEC,
+ errno.EBADF: EBADF,
+ errno.ECHILD: ECHILD,
+ errno.EAGAIN: EAGAIN,
+ errno.ENOMEM: ENOMEM,
+ errno.EACCES: EACCES,
+ errno.EFAULT: EFAULT,
+ errno.ENOTBLK: ENOTBLK,
+ errno.EBUSY: EBUSY,
+ errno.EEXIST: EEXIST,
+ errno.EXDEV: EXDEV,
+ errno.ENODEV: ENODEV,
+ errno.ENOTDIR: ENOTDIR,
+ errno.EISDIR: EISDIR,
+ errno.EINVAL: EINVAL,
+ errno.ENFILE: ENFILE,
+ errno.EMFILE: EMFILE,
+ errno.ENOTTY: ENOTTY,
+ errno.ETXTBSY: ETXTBSY,
+ errno.EFBIG: EFBIG,
+ errno.ENOSPC: ENOSPC,
+ errno.ESPIPE: ESPIPE,
+ errno.EROFS: EROFS,
+ errno.EMLINK: EMLINK,
+ errno.EPIPE: EPIPE,
+ errno.EDOM: EDOM,
+ errno.ERANGE: ERANGE,
+
+ // Errno values from include/uapi/asm-generic/errno.h.
+ errno.EDEADLK: EDEADLK,
+ errno.ENAMETOOLONG: ENAMETOOLONG,
+ errno.ENOLCK: ENOLCK,
+ errno.ENOSYS: ENOSYS,
+ errno.ENOTEMPTY: ENOTEMPTY,
+ errno.ELOOP: ELOOP,
+ errno.ELOOP + 1: errNotValidError, // No valid errno between ELOOP and ENOMSG.
+ errno.ENOMSG: ENOMSG,
+ errno.EIDRM: EIDRM,
+ errno.ECHRNG: ECHRNG,
+ errno.EL2NSYNC: EL2NSYNC,
+ errno.EL3HLT: EL3HLT,
+ errno.EL3RST: EL3RST,
+ errno.ELNRNG: ELNRNG,
+ errno.EUNATCH: EUNATCH,
+ errno.ENOCSI: ENOCSI,
+ errno.EL2HLT: EL2HLT,
+ errno.EBADE: EBADE,
+ errno.EBADR: EBADR,
+ errno.EXFULL: EXFULL,
+ errno.ENOANO: ENOANO,
+ errno.EBADRQC: EBADRQC,
+ errno.EBADSLT: EBADSLT,
+ errno.EBADSLT + 1: errNotValidError, // No valid errno between EBADSLT and ENOPKG.
+ errno.EBFONT: EBFONT,
+ errno.ENOSTR: ENOSTR,
+ errno.ENODATA: ENODATA,
+ errno.ETIME: ETIME,
+ errno.ENOSR: ENOSR,
+ errno.ENOSR + 1: errNotValidError, // No valid errno betweeen ENOSR and ENOPKG.
+ errno.ENOPKG: ENOPKG,
+ errno.EREMOTE: EREMOTE,
+ errno.ENOLINK: ENOLINK,
+ errno.EADV: EADV,
+ errno.ESRMNT: ESRMNT,
+ errno.ECOMM: ECOMM,
+ errno.EPROTO: EPROTO,
+ errno.EMULTIHOP: EMULTIHOP,
+ errno.EDOTDOT: EDOTDOT,
+ errno.EBADMSG: EBADMSG,
+ errno.EOVERFLOW: EOVERFLOW,
+ errno.ENOTUNIQ: ENOTUNIQ,
+ errno.EBADFD: EBADFD,
+ errno.EREMCHG: EREMCHG,
+ errno.ELIBACC: ELIBACC,
+ errno.ELIBBAD: ELIBBAD,
+ errno.ELIBSCN: ELIBSCN,
+ errno.ELIBMAX: ELIBMAX,
+ errno.ELIBEXEC: ELIBEXEC,
+ errno.EILSEQ: EILSEQ,
+ errno.ERESTART: ERESTART,
+ errno.ESTRPIPE: ESTRPIPE,
+ errno.EUSERS: EUSERS,
+ errno.ENOTSOCK: ENOTSOCK,
+ errno.EDESTADDRREQ: EDESTADDRREQ,
+ errno.EMSGSIZE: EMSGSIZE,
+ errno.EPROTOTYPE: EPROTOTYPE,
+ errno.ENOPROTOOPT: ENOPROTOOPT,
+ errno.EPROTONOSUPPORT: EPROTONOSUPPORT,
+ errno.ESOCKTNOSUPPORT: ESOCKTNOSUPPORT,
+ errno.EOPNOTSUPP: EOPNOTSUPP,
+ errno.EPFNOSUPPORT: EPFNOSUPPORT,
+ errno.EAFNOSUPPORT: EAFNOSUPPORT,
+ errno.EADDRINUSE: EADDRINUSE,
+ errno.EADDRNOTAVAIL: EADDRNOTAVAIL,
+ errno.ENETDOWN: ENETDOWN,
+ errno.ENETUNREACH: ENETUNREACH,
+ errno.ENETRESET: ENETRESET,
+ errno.ECONNABORTED: ECONNABORTED,
+ errno.ECONNRESET: ECONNRESET,
+ errno.ENOBUFS: ENOBUFS,
+ errno.EISCONN: EISCONN,
+ errno.ENOTCONN: ENOTCONN,
+ errno.ESHUTDOWN: ESHUTDOWN,
+ errno.ETOOMANYREFS: ETOOMANYREFS,
+ errno.ETIMEDOUT: ETIMEDOUT,
+ errno.ECONNREFUSED: ECONNREFUSED,
+ errno.EHOSTDOWN: EHOSTDOWN,
+ errno.EHOSTUNREACH: EHOSTUNREACH,
+ errno.EALREADY: EALREADY,
+ errno.EINPROGRESS: EINPROGRESS,
+ errno.ESTALE: ESTALE,
+ errno.EUCLEAN: EUCLEAN,
+ errno.ENOTNAM: ENOTNAM,
+ errno.ENAVAIL: ENAVAIL,
+ errno.EISNAM: EISNAM,
+ errno.EREMOTEIO: EREMOTEIO,
+ errno.EDQUOT: EDQUOT,
+ errno.ENOMEDIUM: ENOMEDIUM,
+ errno.EMEDIUMTYPE: EMEDIUMTYPE,
+ errno.ECANCELED: ECANCELED,
+ errno.ENOKEY: ENOKEY,
+ errno.EKEYEXPIRED: EKEYEXPIRED,
+ errno.EKEYREVOKED: EKEYREVOKED,
+ errno.EKEYREJECTED: EKEYREJECTED,
+ errno.EOWNERDEAD: EOWNERDEAD,
+ errno.ENOTRECOVERABLE: ENOTRECOVERABLE,
+ errno.ERFKILL: ERFKILL,
+ errno.EHWPOISON: EHWPOISON,
+}
+
+// ErrorFromErrno gets an error from the list and panics if an invalid entry is requested.
+func ErrorFromErrno(e errno.Errno) *errors.Error {
+ err := errorSlice[e]
+ // Done this way because a single comparison in benchmarks is 2-3 faster
+ // than something like ( if err == nil && err > 0 ).
+ if err != errNotValidError {
+ return err
+ }
+ panic(fmt.Sprintf("invalid error requested with errno: %d", e))
+}
diff --git a/pkg/errors/linuxerr/linuxerr_test.go b/pkg/errors/linuxerr/linuxerr_test.go
new file mode 100644
index 000000000..a81dd9560
--- /dev/null
+++ b/pkg/errors/linuxerr/linuxerr_test.go
@@ -0,0 +1,245 @@
+// Copyright 2018 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package syserror_test
+
+import (
+ "errors"
+ "syscall"
+ "testing"
+
+ "golang.org/x/sys/unix"
+ "gvisor.dev/gvisor/pkg/abi/linux/errno"
+ gErrors "gvisor.dev/gvisor/pkg/errors"
+ "gvisor.dev/gvisor/pkg/errors/linuxerr"
+ "gvisor.dev/gvisor/pkg/syserror"
+)
+
+var globalError error
+
+func BenchmarkAssignUnix(b *testing.B) {
+ for i := b.N; i > 0; i-- {
+ globalError = unix.EINVAL
+ }
+}
+
+func BenchmarkAssignLinuxerr(b *testing.B) {
+ for i := b.N; i > 0; i-- {
+ globalError = linuxerr.EINVAL
+ }
+}
+
+func BenchmarkAssignSyserror(b *testing.B) {
+ for i := b.N; i > 0; i-- {
+ globalError = syserror.EINVAL
+ }
+}
+
+func BenchmarkCompareUnix(b *testing.B) {
+ globalError = unix.EAGAIN
+ j := 0
+ for i := b.N; i > 0; i-- {
+ if globalError == unix.EINVAL {
+ j++
+ }
+ }
+}
+
+func BenchmarkCompareLinuxerr(b *testing.B) {
+ globalError = linuxerr.E2BIG
+ j := 0
+ for i := b.N; i > 0; i-- {
+ if globalError == linuxerr.EINVAL {
+ j++
+ }
+ }
+}
+
+func BenchmarkCompareSyserror(b *testing.B) {
+ globalError = syserror.EAGAIN
+ j := 0
+ for i := b.N; i > 0; i-- {
+ if globalError == syserror.EINVAL {
+ j++
+ }
+ }
+}
+
+func BenchmarkSwitchUnix(b *testing.B) {
+ globalError = unix.EPERM
+ j := 0
+ for i := b.N; i > 0; i-- {
+ switch globalError {
+ case unix.EINVAL:
+ j++
+ case unix.EINTR:
+ j += 2
+ case unix.EAGAIN:
+ j += 3
+ }
+ }
+}
+
+func BenchmarkSwitchLinuxerr(b *testing.B) {
+ globalError = linuxerr.EPERM
+ j := 0
+ for i := b.N; i > 0; i-- {
+ switch globalError {
+ case linuxerr.EINVAL:
+ j++
+ case linuxerr.EINTR:
+ j += 2
+ case linuxerr.EAGAIN:
+ j += 3
+ }
+ }
+}
+
+func BenchmarkSwitchSyserror(b *testing.B) {
+ globalError = syserror.EPERM
+ j := 0
+ for i := b.N; i > 0; i-- {
+ switch globalError {
+ case syserror.EINVAL:
+ j++
+ case syserror.EINTR:
+ j += 2
+ case syserror.EAGAIN:
+ j += 3
+ }
+ }
+}
+
+func BenchmarkReturnUnix(b *testing.B) {
+ var localError error
+ f := func() error {
+ return unix.EINVAL
+ }
+ for i := b.N; i > 0; i-- {
+ localError = f()
+ }
+ if localError != nil {
+ return
+ }
+}
+
+func BenchmarkReturnLinuxerr(b *testing.B) {
+ var localError error
+ f := func() error {
+ return linuxerr.EINVAL
+ }
+ for i := b.N; i > 0; i-- {
+ localError = f()
+ }
+ if localError != nil {
+ return
+ }
+}
+
+func BenchmarkConvertUnixLinuxerr(b *testing.B) {
+ var localError error
+ for i := b.N; i > 0; i-- {
+ localError = linuxerr.ErrorFromErrno(errno.Errno(unix.EINVAL))
+ }
+ if localError != nil {
+ return
+ }
+}
+
+func BenchmarkConvertUnixLinuxerrZero(b *testing.B) {
+ var localError error
+ for i := b.N; i > 0; i-- {
+ localError = linuxerr.ErrorFromErrno(errno.Errno(0))
+ }
+ if localError != nil {
+ return
+ }
+}
+
+type translationTestTable struct {
+ fn string
+ errIn error
+ syscallErrorIn unix.Errno
+ expectedBool bool
+ expectedTranslation unix.Errno
+}
+
+func TestErrorTranslation(t *testing.T) {
+ myError := errors.New("My test error")
+ myError2 := errors.New("Another test error")
+ testTable := []translationTestTable{
+ {"TranslateError", myError, 0, false, 0},
+ {"TranslateError", myError2, 0, false, 0},
+ {"AddErrorTranslation", myError, unix.EAGAIN, true, 0},
+ {"AddErrorTranslation", myError, unix.EAGAIN, false, 0},
+ {"AddErrorTranslation", myError, unix.EPERM, false, 0},
+ {"TranslateError", myError, 0, true, unix.EAGAIN},
+ {"TranslateError", myError2, 0, false, 0},
+ {"AddErrorTranslation", myError2, unix.EPERM, true, 0},
+ {"AddErrorTranslation", myError2, unix.EPERM, false, 0},
+ {"AddErrorTranslation", myError2, unix.EAGAIN, false, 0},
+ {"TranslateError", myError, 0, true, unix.EAGAIN},
+ {"TranslateError", myError2, 0, true, unix.EPERM},
+ }
+ for _, tt := range testTable {
+ switch tt.fn {
+ case "TranslateError":
+ err, ok := syserror.TranslateError(tt.errIn)
+ if ok != tt.expectedBool {
+ t.Fatalf("%v(%v) => %v expected %v", tt.fn, tt.errIn, ok, tt.expectedBool)
+ } else if err != tt.expectedTranslation {
+ t.Fatalf("%v(%v) (error) => %v expected %v", tt.fn, tt.errIn, err, tt.expectedTranslation)
+ }
+ case "AddErrorTranslation":
+ ok := syserror.AddErrorTranslation(tt.errIn, tt.syscallErrorIn)
+ if ok != tt.expectedBool {
+ t.Fatalf("%v(%v) => %v expected %v", tt.fn, tt.errIn, ok, tt.expectedBool)
+ }
+ default:
+ t.Fatalf("Unknown function %v", tt.fn)
+ }
+ }
+}
+
+func TestSyscallErrnoToErrors(t *testing.T) {
+ for _, tc := range []struct {
+ errno syscall.Errno
+ err *gErrors.Error
+ }{
+ {errno: syscall.EACCES, err: linuxerr.EACCES},
+ {errno: syscall.EAGAIN, err: linuxerr.EAGAIN},
+ {errno: syscall.EBADF, err: linuxerr.EBADF},
+ {errno: syscall.EBUSY, err: linuxerr.EBUSY},
+ {errno: syscall.EDOM, err: linuxerr.EDOM},
+ {errno: syscall.EEXIST, err: linuxerr.EEXIST},
+ {errno: syscall.EFAULT, err: linuxerr.EFAULT},
+ {errno: syscall.EFBIG, err: linuxerr.EFBIG},
+ {errno: syscall.EINTR, err: linuxerr.EINTR},
+ {errno: syscall.EINVAL, err: linuxerr.EINVAL},
+ {errno: syscall.EIO, err: linuxerr.EIO},
+ {errno: syscall.ENOTDIR, err: linuxerr.ENOTDIR},
+ {errno: syscall.ENOTTY, err: linuxerr.ENOTTY},
+ {errno: syscall.EPERM, err: linuxerr.EPERM},
+ {errno: syscall.EPIPE, err: linuxerr.EPIPE},
+ {errno: syscall.ESPIPE, err: linuxerr.ESPIPE},
+ {errno: syscall.EWOULDBLOCK, err: linuxerr.EAGAIN},
+ } {
+ t.Run(tc.errno.Error(), func(t *testing.T) {
+ e := linuxerr.ErrorFromErrno(errno.Errno(tc.errno))
+ if e != tc.err {
+ t.Fatalf("Mismatch errors: want: %+v (%d) got: %+v %d", tc.err, tc.err.Errno(), e, e.Errno())
+ }
+ })
+ }
+}