[syserror] Add conversions to linuxerr with temporary Equals method.

Add Equals method to compare syserror and unix.Errno errors to linuxerr errors.
This will facilitate removal of syserror definitions in a followup, and
finding needed conversions from unix.Errno to linuxerr.

PiperOrigin-RevId: 380909667
This commit is contained in:
Zach Koopmans
2021-06-22 15:53:32 -07:00
committed by gVisor bot
parent 01bcd55c3a
commit e1dc1c78e7
106 changed files with 376 additions and 198 deletions
+1
View File
@@ -9,6 +9,7 @@ go_library(
deps = [
"//pkg/abi/linux/errno",
"//pkg/errors",
"@org_golang_x_sys//unix:go_default_library",
],
)
+20
View File
@@ -20,6 +20,7 @@ package linuxerr
import (
"fmt"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/abi/linux/errno"
"gvisor.dev/gvisor/pkg/errors"
)
@@ -325,3 +326,22 @@ func ErrorFromErrno(e errno.Errno) *errors.Error {
}
panic(fmt.Sprintf("invalid error requested with errno: %d", e))
}
// Equals compars a linuxerr to a given error
// TODO(b/34162363): Remove when syserror is removed.
func Equals(e *errors.Error, err error) bool {
if err == nil {
return e == NOERROR || e == nil
}
if e == nil {
return err == NOERROR || err == unix.Errno(0)
}
switch err.(type) {
case *errors.Error:
return e == err
case unix.Errno, error:
return unix.Errno(e.Errno()) == err
}
return false
}
+61
View File
@@ -16,6 +16,8 @@ package syserror_test
import (
"errors"
"io"
"io/fs"
"syscall"
"testing"
@@ -243,3 +245,62 @@ func TestSyscallErrnoToErrors(t *testing.T) {
})
}
}
// TestEqualsMethod tests that the Equals method correctly compares syerror,
// unix.Errno and linuxerr.
// TODO (b/34162363): Remove this.
func TestEqualsMethod(t *testing.T) {
for _, tc := range []struct {
name string
linuxErr []*gErrors.Error
err []error
equal bool
}{
{
name: "compare nil",
linuxErr: []*gErrors.Error{nil, linuxerr.NOERROR},
err: []error{nil, linuxerr.NOERROR, unix.Errno(0)},
equal: true,
},
{
name: "linuxerr nil error not",
linuxErr: []*gErrors.Error{nil, linuxerr.NOERROR},
err: []error{unix.Errno(1), linuxerr.EPERM, syserror.EACCES},
equal: false,
},
{
name: "linuxerr not nil error nil",
linuxErr: []*gErrors.Error{linuxerr.ENOENT},
err: []error{nil, unix.Errno(0), linuxerr.NOERROR},
equal: false,
},
{
name: "equal errors",
linuxErr: []*gErrors.Error{linuxerr.ESRCH},
err: []error{linuxerr.ESRCH, syserror.ESRCH, unix.Errno(linuxerr.ESRCH.Errno())},
equal: true,
},
{
name: "unequal errors",
linuxErr: []*gErrors.Error{linuxerr.ENOENT},
err: []error{linuxerr.ESRCH, syserror.ESRCH, unix.Errno(linuxerr.ESRCH.Errno())},
equal: false,
},
{
name: "other error",
linuxErr: []*gErrors.Error{nil, linuxerr.NOERROR, linuxerr.E2BIG, linuxerr.EINVAL},
err: []error{fs.ErrInvalid, io.EOF},
equal: false,
},
} {
t.Run(tc.name, func(t *testing.T) {
for _, le := range tc.linuxErr {
for _, e := range tc.err {
if linuxerr.Equals(le, e) != tc.equal {
t.Fatalf("Expected %t from Equals method for linuxerr: %s %T and error: %s %T", tc.equal, le, le, e, e)
}
}
}
})
}
}
+2
View File
@@ -48,6 +48,7 @@ go_library(
"//pkg/abi/linux",
"//pkg/amutex",
"//pkg/context",
"//pkg/errors/linuxerr",
"//pkg/hostarch",
"//pkg/log",
"//pkg/p9",
@@ -110,6 +111,7 @@ go_test(
deps = [
":fs",
"//pkg/context",
"//pkg/errors/linuxerr",
"//pkg/sentry/fs/fsutil",
"//pkg/sentry/fs/ramfs",
"//pkg/sentry/fs/tmpfs",
+2 -1
View File
@@ -20,6 +20,7 @@ import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/memmap"
@@ -410,7 +411,7 @@ func copyAttributesLocked(ctx context.Context, upper *Inode, lower *Inode) error
return err
}
lowerXattr, err := lower.ListXattr(ctx, linux.XATTR_SIZE_MAX)
if err != nil && err != syserror.EOPNOTSUPP {
if err != nil && !linuxerr.Equals(linuxerr.EOPNOTSUPP, err) {
return err
}
+2 -1
View File
@@ -22,6 +22,7 @@ import (
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/refs"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/socket/unix/transport"
@@ -1439,7 +1440,7 @@ func Rename(ctx context.Context, root *Dirent, oldParent *Dirent, oldName string
// replaced is the dirent that is being overwritten by rename.
replaced, err := newParent.walk(ctx, root, newName, false /* may unlock */)
if err != nil {
if err != syserror.ENOENT {
if !linuxerr.Equals(linuxerr.ENOENT, err) {
return err
}
+1
View File
@@ -13,6 +13,7 @@ go_library(
visibility = ["//pkg/sentry:internal"],
deps = [
"//pkg/context",
"//pkg/errors/linuxerr",
"//pkg/fd",
"//pkg/fdnotifier",
"//pkg/log",
+2 -1
View File
@@ -20,6 +20,7 @@ import (
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/fd"
"gvisor.dev/gvisor/pkg/fdnotifier"
"gvisor.dev/gvisor/pkg/log"
@@ -158,7 +159,7 @@ func (p *pipeOperations) Write(ctx context.Context, file *fs.File, src usermem.I
// isBlockError unwraps os errors and checks if they are caused by EAGAIN or
// EWOULDBLOCK. This is so they can be transformed into syserror.ErrWouldBlock.
func isBlockError(err error) bool {
if err == syserror.EAGAIN || err == syserror.EWOULDBLOCK {
if linuxerr.Equals(linuxerr.EAGAIN, err) || linuxerr.Equals(linuxerr.EWOULDBLOCK, err) {
return true
}
if pe, ok := err.(*os.PathError); ok {
+1
View File
@@ -26,6 +26,7 @@ go_library(
deps = [
"//pkg/abi/linux",
"//pkg/context",
"//pkg/errors/linuxerr",
"//pkg/fd",
"//pkg/hostarch",
"//pkg/log",
+3 -2
View File
@@ -18,6 +18,7 @@ import (
"fmt"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/p9"
"gvisor.dev/gvisor/pkg/sentry/device"
@@ -66,7 +67,7 @@ func (i *inodeOperations) Lookup(ctx context.Context, dir *fs.Inode, name string
// Get a p9.File for name.
qids, newFile, mask, p9attr, err := i.fileState.file.walkGetAttr(ctx, []string{name})
if err != nil {
if err == syserror.ENOENT {
if linuxerr.Equals(linuxerr.ENOENT, err) {
if cp.cacheNegativeDirents() {
// Return a negative Dirent. It will stay cached until something
// is created over it.
@@ -298,7 +299,7 @@ func (i *inodeOperations) CreateFifo(ctx context.Context, dir *fs.Inode, name st
// N.B. FIFOs use major/minor numbers 0.
if _, err := i.fileState.file.mknod(ctx, name, mode, 0, 0, p9.UID(owner.UID), p9.GID(owner.GID)); err != nil {
if i.session().overrides == nil || err != syserror.EPERM {
if i.session().overrides == nil || !linuxerr.Equals(linuxerr.EPERM, err) {
return err
}
// If gofer doesn't support mknod, check if we can create an internal fifo.
+1
View File
@@ -28,6 +28,7 @@ go_library(
deps = [
"//pkg/abi/linux",
"//pkg/context",
"//pkg/errors/linuxerr",
"//pkg/fd",
"//pkg/fdnotifier",
"//pkg/iovec",
+2 -1
View File
@@ -21,6 +21,7 @@ import (
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/fd"
"gvisor.dev/gvisor/pkg/fdnotifier"
"gvisor.dev/gvisor/pkg/refs"
@@ -213,7 +214,7 @@ func (c *ConnectedEndpoint) Send(ctx context.Context, data [][]byte, controlMess
// block (and only for stream sockets).
err = syserror.EAGAIN
}
if n > 0 && err != syserror.EAGAIN {
if n > 0 && !linuxerr.Equals(linuxerr.EAGAIN, err) {
// The caller may need to block to send more data, but
// otherwise there isn't anything that can be done about an
// error with a partial write.
+2 -1
View File
@@ -17,6 +17,7 @@ package host
import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/marshal/primitive"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fs"
@@ -191,7 +192,7 @@ func (t *TTYFileOperations) Ioctl(ctx context.Context, _ *fs.File, io usermem.IO
if err := t.checkChange(ctx, linux.SIGTTOU); err != nil {
// drivers/tty/tty_io.c:tiocspgrp() converts -EIO from
// tty_check_change() to -ENOTTY.
if err == syserror.EIO {
if linuxerr.Equals(linuxerr.EIO, err) {
return 0, syserror.ENOTTY
}
return 0, err
+2 -2
View File
@@ -19,12 +19,12 @@ import (
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/device"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time"
"gvisor.dev/gvisor/pkg/syserror"
)
func nodeType(s *unix.Stat_t) fs.InodeType {
@@ -98,7 +98,7 @@ type dirInfo struct {
// isBlockError unwraps os errors and checks if they are caused by EAGAIN or
// EWOULDBLOCK. This is so they can be transformed into syserror.ErrWouldBlock.
func isBlockError(err error) bool {
if err == syserror.EAGAIN || err == syserror.EWOULDBLOCK {
if linuxerr.Equals(linuxerr.EAGAIN, err) || linuxerr.Equals(linuxerr.EWOULDBLOCK, err) {
return true
}
if pe, ok := err.(*os.PathError); ok {
+4 -3
View File
@@ -19,6 +19,7 @@ import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/socket/unix/transport"
"gvisor.dev/gvisor/pkg/syserror"
@@ -71,7 +72,7 @@ func overlayLookup(ctx context.Context, parent *overlayEntry, inode *Inode, name
// A file could have been created over a whiteout, so we need to
// check if something exists in the upper file system first.
child, err := parent.upper.Lookup(ctx, name)
if err != nil && err != syserror.ENOENT {
if err != nil && !linuxerr.Equals(linuxerr.ENOENT, err) {
// We encountered an error that an overlay cannot handle,
// we must propagate it to the caller.
parent.copyMu.RUnlock()
@@ -125,7 +126,7 @@ func overlayLookup(ctx context.Context, parent *overlayEntry, inode *Inode, name
// Check the lower file system.
child, err := parent.lower.Lookup(ctx, name)
// Same song and dance as above.
if err != nil && err != syserror.ENOENT {
if err != nil && !linuxerr.Equals(linuxerr.ENOENT, err) {
// Don't leak resources.
if upperInode != nil {
upperInode.DecRef(ctx)
@@ -396,7 +397,7 @@ func overlayRename(ctx context.Context, o *overlayEntry, oldParent *Dirent, rena
// newName has been removed out from under us. That's fine;
// filesystems where that can happen must handle stale
// 'replaced'.
if err != nil && err != syserror.ENOENT {
if err != nil && !linuxerr.Equals(linuxerr.ENOENT, err) {
return err
}
if err == nil {
+3 -2
View File
@@ -18,6 +18,7 @@ import (
"testing"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/sentry/fs"
"gvisor.dev/gvisor/pkg/sentry/fs/fsutil"
"gvisor.dev/gvisor/pkg/sentry/fs/ramfs"
@@ -191,11 +192,11 @@ func TestLookup(t *testing.T) {
} {
t.Run(test.desc, func(t *testing.T) {
dirent, err := test.dir.Lookup(ctx, test.name)
if test.found && (err == syserror.ENOENT || dirent.IsNegative()) {
if test.found && (linuxerr.Equals(linuxerr.ENOENT, err) || dirent.IsNegative()) {
t.Fatalf("lookup %q expected to find positive dirent, got dirent %v err %v", test.name, dirent, err)
}
if !test.found {
if err != syserror.ENOENT && !dirent.IsNegative() {
if !linuxerr.Equals(linuxerr.ENOENT, err) && !dirent.IsNegative() {
t.Errorf("lookup %q expected to return ENOENT or negative dirent, got dirent %v err %v", test.name, dirent, err)
}
// Nothing more to check.
+1
View File
@@ -30,6 +30,7 @@ go_library(
deps = [
"//pkg/abi/linux",
"//pkg/context",
"//pkg/errors/linuxerr",
"//pkg/hostarch",
"//pkg/log",
"//pkg/sentry/fs",
+2 -2
View File
@@ -23,6 +23,7 @@ import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/fs"
@@ -34,7 +35,6 @@ import (
"gvisor.dev/gvisor/pkg/sentry/socket"
"gvisor.dev/gvisor/pkg/sentry/socket/unix"
"gvisor.dev/gvisor/pkg/sentry/socket/unix/transport"
"gvisor.dev/gvisor/pkg/syserror"
"gvisor.dev/gvisor/pkg/tcpip/header"
)
@@ -291,7 +291,7 @@ func (n *netSnmp) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]s
continue
}
if err := n.s.Statistics(stat, line.prefix); err != nil {
if err == syserror.EOPNOTSUPP {
if linuxerr.Equals(linuxerr.EOPNOTSUPP, err) {
log.Infof("Failed to retrieve %s of /proc/net/snmp: %v", line.prefix, err)
} else {
log.Warningf("Failed to retrieve %s of /proc/net/snmp: %v", line.prefix, err)
+3 -2
View File
@@ -19,6 +19,7 @@ import (
"sync/atomic"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/errors/linuxerr"
"gvisor.dev/gvisor/pkg/syserror"
)
@@ -139,7 +140,7 @@ func Splice(ctx context.Context, dst *File, src *File, opts SpliceOpts) (int64,
// Attempt to do a WriteTo; this is likely the most efficient.
n, err := src.FileOperations.WriteTo(ctx, src, w, opts.Length, opts.Dup)
if n == 0 && err == syserror.ENOSYS && !opts.Dup {
if n == 0 && linuxerr.Equals(linuxerr.ENOSYS, err) && !opts.Dup {
// Attempt as a ReadFrom. If a WriteTo, a ReadFrom may also be
// more efficient than a copy if buffers are cached or readily
// available. (It's unlikely that they can actually be donated).
@@ -151,7 +152,7 @@ func Splice(ctx context.Context, dst *File, src *File, opts SpliceOpts) (int64,
// if we block at some point, we could lose data. If the source is
// not a pipe then reading is not destructive; if the destination
// is a regular file, then it is guaranteed not to block writing.
if n == 0 && err == syserror.ENOSYS && !opts.Dup && (!dstPipe || !srcPipe) {
if n == 0 && linuxerr.Equals(linuxerr.ENOSYS, err) && !opts.Dup && (!dstPipe || !srcPipe) {
// Fallback to an in-kernel copy.
n, err = io.Copy(w, &io.LimitedReader{
R: r,
+1
View File
@@ -12,6 +12,7 @@ go_library(
deps = [
"//pkg/abi/linux",
"//pkg/context",
"//pkg/errors/linuxerr",
"//pkg/fspath",
"//pkg/log",
"//pkg/sentry/fs",

Some files were not shown because too many files have changed in this diff Show More