Skip to content

Commit

Permalink
Add errno label to fuse ops metric
Browse files Browse the repository at this point in the history
Signed-off-by: Changxin Miao <[email protected]>
  • Loading branch information
polyrabbit committed Apr 8, 2024
1 parent 82cf613 commit 06947bd
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 43 deletions.
10 changes: 6 additions & 4 deletions pkg/vfs/accesslog.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ package vfs

import (
"fmt"
"strconv"
"sync"
"syscall"
"time"

"github.com/juicedata/juicefs/pkg/utils"
Expand All @@ -30,7 +32,7 @@ var (
Name: "fuse_ops_durations_histogram_seconds",
Help: "Operations latency distributions.",
Buckets: prometheus.ExponentialBuckets(0.0001, 1.5, 30),
}, []string{"method"})
}, []string{"method", "errno"})
)

type logReader struct {
Expand All @@ -48,9 +50,9 @@ func init() {
readers = make(map[uint64]*logReader)
}

func logit(ctx Context, method, format string, args ...interface{}) {
func logit(ctx Context, method string, err syscall.Errno, format string, args ...interface{}) {
used := ctx.Duration()
opsDurationsHistogram.WithLabelValues(method).Observe(used.Seconds())
opsDurationsHistogram.WithLabelValues(method, strconv.Itoa(int(err))).Observe(used.Seconds())
readerLock.RLock()
defer readerLock.RUnlock()
if len(readers) == 0 && used < time.Second*10 {
Expand All @@ -60,7 +62,7 @@ func logit(ctx Context, method, format string, args ...interface{}) {
cmd := fmt.Sprintf(method+" "+format, args...)
t := utils.Now()
ts := t.Format("2006.01.02 15:04:05.000000")
cmd += fmt.Sprintf(" <%.6f>", used.Seconds())
cmd += fmt.Sprintf(" - %s <%.6f>", strerr(err), used.Seconds())
if ctx.Pid() != 0 && used >= time.Second*10 {
logger.Infof("slow operation: %s", cmd)
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/vfs/accesslog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func TestAccessLog(t *testing.T) {
defer closeAccessLog(1)

ctx := NewLogContext(meta.NewContext(10, 1, []uint32{2}))
logit(ctx, "method", "test")
logit(ctx, "method", 0, "test")

n := readAccessLog(2, nil)
if n != 0 {
Expand All @@ -48,7 +48,7 @@ func TestAccessLog(t *testing.T) {

// read whole line, block for 1 second
n = readAccessLog(1, buf[10:])
if n != 61 {
if n != 66 {
t.Fatalf("partial read: %d", n)
}
logs := string(buf[:10+n])
Expand All @@ -61,7 +61,7 @@ func TestAccessLog(t *testing.T) {
if now.Sub(ts.Local()) > time.Millisecond*10 {
t.Fatalf("stale time: %s now: %s", ts, time.Now())
}
if logs[26:len(logs)-4] != " [uid:1,gid:2,pid:10] method test <0.0000" {
if logs[26:len(logs)-4] != " [uid:1,gid:2,pid:10] method test - OK <0.0000" {
t.Fatalf("unexpected log: %q", logs[26:])
}

Expand Down
56 changes: 28 additions & 28 deletions pkg/vfs/vfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ func (v *VFS) Lookup(ctx Context, parent Ino, name string) (entry *meta.Entry, e
}
}
defer func() {
logit(ctx, "lookup", "(%d,%s): %s%s", parent, name, strerr(err), (*Entry)(entry))
logit(ctx, "lookup", err, "(%d,%s):%s", parent, name, (*Entry)(entry))
}()
if len(name) > maxName {
err = syscall.ENAMETOOLONG
Expand All @@ -188,7 +188,7 @@ func (v *VFS) GetAttr(ctx Context, ino Ino, opened uint8) (entry *meta.Entry, er
entry = &meta.Entry{Inode: n.inode, Attr: n.attr}
return
}
defer func() { logit(ctx, "getattr", "(%d): %s%s", ino, strerr(err), (*Entry)(entry)) }()
defer func() { logit(ctx, "getattr", err, "(%d):%s", ino, (*Entry)(entry)) }()
var attr = &Attr{}
err = v.Meta.GetAttr(ctx, ino, attr)
if err == 0 {
Expand Down Expand Up @@ -219,7 +219,7 @@ func get_filetype(mode uint16) uint8 {

func (v *VFS) Mknod(ctx Context, parent Ino, name string, mode uint16, cumask uint16, rdev uint32) (entry *meta.Entry, err syscall.Errno) {
defer func() {
logit(ctx, "mknod", "(%d,%s,%s:0%04o,0x%08X): %s%s", parent, name, smode(mode), mode, rdev, strerr(err), (*Entry)(entry))
logit(ctx, "mknod", err, "(%d,%s,%s:0%04o,0x%08X):%s", parent, name, smode(mode), mode, rdev, (*Entry)(entry))
}()
if parent == rootID && IsSpecialName(name) {
err = syscall.EEXIST
Expand All @@ -246,7 +246,7 @@ func (v *VFS) Mknod(ctx Context, parent Ino, name string, mode uint16, cumask ui
}

func (v *VFS) Unlink(ctx Context, parent Ino, name string) (err syscall.Errno) {
defer func() { logit(ctx, "unlink", "(%d,%s): %s", parent, name, strerr(err)) }()
defer func() { logit(ctx, "unlink", err, "(%d,%s)", parent, name) }()
if parent == rootID && IsSpecialName(name) {
err = syscall.EPERM
return
Expand All @@ -264,7 +264,7 @@ func (v *VFS) Unlink(ctx Context, parent Ino, name string) (err syscall.Errno) {

func (v *VFS) Mkdir(ctx Context, parent Ino, name string, mode uint16, cumask uint16) (entry *meta.Entry, err syscall.Errno) {
defer func() {
logit(ctx, "mkdir", "(%d,%s,%s:0%04o): %s%s", parent, name, smode(mode), mode, strerr(err), (*Entry)(entry))
logit(ctx, "mkdir", err, "(%d,%s,%s:0%04o):%s", parent, name, smode(mode), mode, (*Entry)(entry))
}()
if parent == rootID && IsSpecialName(name) {
err = syscall.EEXIST
Expand All @@ -286,7 +286,7 @@ func (v *VFS) Mkdir(ctx Context, parent Ino, name string, mode uint16, cumask ui
}

func (v *VFS) Rmdir(ctx Context, parent Ino, name string) (err syscall.Errno) {
defer func() { logit(ctx, "rmdir", "(%d,%s): %s", parent, name, strerr(err)) }()
defer func() { logit(ctx, "rmdir", err, "(%d,%s)", parent, name) }()
if len(name) > maxName {
err = syscall.ENAMETOOLONG
return
Expand All @@ -300,7 +300,7 @@ func (v *VFS) Rmdir(ctx Context, parent Ino, name string) (err syscall.Errno) {

func (v *VFS) Symlink(ctx Context, path string, parent Ino, name string) (entry *meta.Entry, err syscall.Errno) {
defer func() {
logit(ctx, "symlink", "(%d,%s,%s): %s%s", parent, name, path, strerr(err), (*Entry)(entry))
logit(ctx, "symlink", err, "(%d,%s,%s):%s", parent, name, path, (*Entry)(entry))
}()
if parent == rootID && IsSpecialName(name) {
err = syscall.EEXIST
Expand All @@ -322,14 +322,14 @@ func (v *VFS) Symlink(ctx Context, path string, parent Ino, name string) (entry
}

func (v *VFS) Readlink(ctx Context, ino Ino) (path []byte, err syscall.Errno) {
defer func() { logit(ctx, "readlink", "(%d): %s (%s)", ino, strerr(err), string(path)) }()
defer func() { logit(ctx, "readlink", err, "(%d): (%s)", ino, string(path)) }()
err = v.Meta.ReadLink(ctx, ino, &path)
return
}

func (v *VFS) Rename(ctx Context, parent Ino, name string, newparent Ino, newname string, flags uint32) (err syscall.Errno) {
defer func() {
logit(ctx, "rename", "(%d,%s,%d,%s,%d): %s", parent, name, newparent, newname, flags, strerr(err))
logit(ctx, "rename", err, "(%d,%s,%d,%s,%d)", parent, name, newparent, newname, flags)
}()
if parent == rootID && IsSpecialName(name) {
err = syscall.EPERM
Expand Down Expand Up @@ -357,7 +357,7 @@ func (v *VFS) Rename(ctx Context, parent Ino, name string, newparent Ino, newnam

func (v *VFS) Link(ctx Context, ino Ino, newparent Ino, newname string) (entry *meta.Entry, err syscall.Errno) {
defer func() {
logit(ctx, "link", "(%d,%d,%s): %s%s", ino, newparent, newname, strerr(err), (*Entry)(entry))
logit(ctx, "link", err, "(%d,%d,%s):%s", ino, newparent, newname, (*Entry)(entry))
}()
if IsSpecialNode(ino) {
err = syscall.EPERM
Expand All @@ -382,7 +382,7 @@ func (v *VFS) Link(ctx Context, ino Ino, newparent Ino, newname string) (entry *
}

func (v *VFS) Opendir(ctx Context, ino Ino, flags uint32) (fh uint64, err syscall.Errno) {
defer func() { logit(ctx, "opendir", "(%d): %s [fh:%d]", ino, strerr(err), fh) }()
defer func() { logit(ctx, "opendir", err, "(%d) [fh:%d]", ino, fh) }()
if ctx.CheckPermission() {
var mmask uint8 = 0
switch flags & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) {
Expand Down Expand Up @@ -412,7 +412,7 @@ func (v *VFS) UpdateLength(inode Ino, attr *meta.Attr) {
}

func (v *VFS) Readdir(ctx Context, ino Ino, size uint32, off int, fh uint64, plus bool) (entries []*meta.Entry, readAt time.Time, err syscall.Errno) {
defer func() { logit(ctx, "readdir", "(%d,%d,%d): %s (%d)", ino, size, off, strerr(err), len(entries)) }()
defer func() { logit(ctx, "readdir", err, "(%d,%d,%d): (%d)", ino, size, off, len(entries)) }()
h := v.findHandle(ino, fh)
if h == nil {
err = syscall.EBADF
Expand Down Expand Up @@ -468,18 +468,18 @@ func (v *VFS) UpdateReaddirOffset(ctx Context, ino Ino, fh uint64, off int) {
}

func (v *VFS) Releasedir(ctx Context, ino Ino, fh uint64) int {
defer logit(ctx, "releasedir", 0, "(%d)", ino)
h := v.findHandle(ino, fh)
if h == nil {
return 0
}
v.ReleaseHandler(ino, fh)
logit(ctx, "releasedir", "(%d): OK", ino)
return 0
}

func (v *VFS) Create(ctx Context, parent Ino, name string, mode uint16, cumask uint16, flags uint32) (entry *meta.Entry, fh uint64, err syscall.Errno) {
defer func() {
logit(ctx, "create", "(%d,%s,%s:0%04o): %s%s [fh:%d]", parent, name, smode(mode), mode, strerr(err), (*Entry)(entry), fh)
logit(ctx, "create", err, "(%d,%s,%s:0%04o):%s [fh:%d]", parent, name, smode(mode), mode, (*Entry)(entry), fh)
}()
if parent == rootID && IsSpecialName(name) {
err = syscall.EEXIST
Expand Down Expand Up @@ -508,9 +508,9 @@ func (v *VFS) Create(ctx Context, parent Ino, name string, mode uint16, cumask u
func (v *VFS) Open(ctx Context, ino Ino, flags uint32) (entry *meta.Entry, fh uint64, err syscall.Errno) {
defer func() {
if entry != nil {
logit(ctx, "open", "(%d): %s [fh:%d]", ino, strerr(err), fh)
logit(ctx, "open", err, "(%d,%#x) [fh:%d]", ino, flags, fh)
} else {
logit(ctx, "open", "(%d): %s", ino, strerr(err))
logit(ctx, "open", err, "(%d,%#x)", ino, flags)
}
}()
var attr = &Attr{}
Expand Down Expand Up @@ -604,7 +604,7 @@ func (v *VFS) ReleaseHandler(ino Ino, fh uint64) {

func (v *VFS) Release(ctx Context, ino Ino, fh uint64) {
var err syscall.Errno
defer func() { logit(ctx, "release", "(%d,%d): %s", ino, fh, strerr(err)) }()
defer func() { logit(ctx, "release", err, "(%d,%d)", ino, fh) }()
if IsSpecialNode(ino) {
if ino == logInode {
closeAccessLog(fh)
Expand Down Expand Up @@ -677,7 +677,7 @@ func (v *VFS) Read(ctx Context, ino Ino, buf []byte, off uint64, fh uint64) (n i
}
n = readAccessLog(fh, buf)
} else {
defer func() { logit(ctx, "read", "(%d,%d,%d,%d): %s (%d)", ino, size, off, fh, strerr(err), n) }()
defer func() { logit(ctx, "read", err, "(%d,%d,%d,%d): %d", ino, size, off, fh, n) }()
h.Lock()
defer h.Unlock()
if off < h.off {
Expand All @@ -699,7 +699,7 @@ func (v *VFS) Read(ctx Context, ino Ino, buf []byte, off uint64, fh uint64) (n i

defer func() {
readSizeHistogram.Observe(float64(n))
logit(ctx, "read", "(%d,%d,%d): %s (%d)", ino, size, off, strerr(err), n)
logit(ctx, "read", err, "(%d,%d,%d): (%d)", ino, size, off, n)
}()
h := v.findHandle(ino, fh)
if h == nil {
Expand Down Expand Up @@ -759,7 +759,7 @@ func (v *VFS) Write(ctx Context, ino Ino, buf []byte, off, fh uint64) (err sysca
if ino == controlInode && runtime.GOOS == "darwin" {
fh = v.getControlHandle(ctx.Pid())
}
defer func() { logit(ctx, "write", "(%d,%d,%d,%d): %s", ino, size, off, fh, strerr(err)) }()
defer func() { logit(ctx, "write", err, "(%d,%d,%d,%d)", ino, size, off, fh) }()
h := v.findHandle(ino, fh)
if h == nil {
err = syscall.EBADF
Expand Down Expand Up @@ -819,7 +819,7 @@ func (v *VFS) Write(ctx Context, ino Ino, buf []byte, off, fh uint64) (err sysca
}

func (v *VFS) Fallocate(ctx Context, ino Ino, mode uint8, off, size int64, fh uint64) (err syscall.Errno) {
defer func() { logit(ctx, "fallocate", "(%d,%d,%d,%d): %s", ino, mode, off, size, strerr(err)) }()
defer func() { logit(ctx, "fallocate", err, "(%d,%d,%d,%d)", ino, mode, off, size) }()
if off < 0 || size <= 0 {
err = syscall.EINVAL
return
Expand Down Expand Up @@ -870,7 +870,7 @@ func (v *VFS) Fallocate(ctx Context, ino Ino, mode uint8, off, size int64, fh ui

func (v *VFS) CopyFileRange(ctx Context, nodeIn Ino, fhIn, offIn uint64, nodeOut Ino, fhOut, offOut, size uint64, flags uint32) (copied uint64, err syscall.Errno) {
defer func() {
logit(ctx, "copy_file_range", "(%d,%d,%d,%d,%d,%d): %s", nodeIn, offIn, nodeOut, offOut, size, flags, strerr(err))
logit(ctx, "copy_file_range", err, "(%d,%d,%d,%d,%d,%d)", nodeIn, offIn, nodeOut, offOut, size, flags)
}()
if IsSpecialNode(nodeIn) {
err = syscall.ENOTSUP
Expand Down Expand Up @@ -949,7 +949,7 @@ func (v *VFS) Flush(ctx Context, ino Ino, fh uint64, lockOwner uint64) (err sysc
fh = v.getControlHandle(ctx.Pid())
defer v.releaseControlHandle(ctx.Pid())
}
defer func() { logit(ctx, "flush", "(%d,%d,%016X): %s", ino, fh, lockOwner, strerr(err)) }()
defer func() { logit(ctx, "flush", err, "(%d,%d,%016X)", ino, fh, lockOwner) }()
h := v.findHandle(ino, fh)
if h == nil {
err = syscall.EBADF
Expand Down Expand Up @@ -990,7 +990,7 @@ func (v *VFS) Flush(ctx Context, ino Ino, fh uint64, lockOwner uint64) (err sysc
}

func (v *VFS) Fsync(ctx Context, ino Ino, datasync int, fh uint64) (err syscall.Errno) {
defer func() { logit(ctx, "fsync", "(%d,%d): %s", ino, datasync, strerr(err)) }()
defer func() { logit(ctx, "fsync", err, "(%d,%d)", ino, datasync) }()
if IsSpecialNode(ino) {
return
}
Expand Down Expand Up @@ -1020,7 +1020,7 @@ const (
)

func (v *VFS) SetXattr(ctx Context, ino Ino, name string, value []byte, flags uint32) (err syscall.Errno) {
defer func() { logit(ctx, "setxattr", "(%d,%s,%d,%d): %s", ino, name, len(value), flags, strerr(err)) }()
defer func() { logit(ctx, "setxattr", err, "(%d,%s,%d,%d)", ino, name, len(value), flags) }()
if IsSpecialNode(ino) {
err = syscall.EPERM
return
Expand Down Expand Up @@ -1066,7 +1066,7 @@ func (v *VFS) SetXattr(ctx Context, ino Ino, name string, value []byte, flags ui
}

func (v *VFS) GetXattr(ctx Context, ino Ino, name string, size uint32) (value []byte, err syscall.Errno) {
defer func() { logit(ctx, "getxattr", "(%d,%s,%d): %s (%d)", ino, name, size, strerr(err), len(value)) }()
defer func() { logit(ctx, "getxattr", err, "(%d,%s,%d): (%d)", ino, name, size, len(value)) }()
if IsSpecialNode(ino) {
err = meta.ENOATTR
return
Expand Down Expand Up @@ -1106,7 +1106,7 @@ func (v *VFS) GetXattr(ctx Context, ino Ino, name string, size uint32) (value []
}

func (v *VFS) ListXattr(ctx Context, ino Ino, size int) (data []byte, err syscall.Errno) {
defer func() { logit(ctx, "listxattr", "(%d,%d): %s (%d)", ino, size, strerr(err), len(data)) }()
defer func() { logit(ctx, "listxattr", err, "(%d,%d): (%d)", ino, size, len(data)) }()
if IsSpecialNode(ino) {
err = meta.ENOATTR
return
Expand All @@ -1119,7 +1119,7 @@ func (v *VFS) ListXattr(ctx Context, ino Ino, size int) (data []byte, err syscal
}

func (v *VFS) RemoveXattr(ctx Context, ino Ino, name string) (err syscall.Errno) {
defer func() { logit(ctx, "removexattr", "(%d,%s): %s", ino, name, strerr(err)) }()
defer func() { logit(ctx, "removexattr", err, "(%d,%s)", ino, name) }()
if IsSpecialNode(ino) {
err = syscall.EPERM
return
Expand Down
2 changes: 1 addition & 1 deletion pkg/vfs/vfs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ func TestInternalFile(t *testing.T) {
}
if n, e = v.Read(ctx, fe.Inode, buf, 0, fh); e != 0 {
t.Fatalf("read .accesslog: %s", e)
} else if !strings.Contains(string(buf[:n]), "open (9223372032559808513)") {
} else if !strings.Contains(string(buf[:n]), "open (9223372032559808513") {
t.Fatalf("invalid access log: %q", string(buf[:n]))
}
_ = v.Flush(ctx, fe.Inode, fh, 0)
Expand Down
14 changes: 7 additions & 7 deletions pkg/vfs/vfs_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (v *VFS) StatFS(ctx Context, ino Ino) (st *Statfs, err syscall.Errno) {
st.Avail = availspace
st.Files = iused + iavail
st.Favail = iavail
logit(ctx, "statfs", "(%d): OK (%d,%d,%d,%d)", ino, totalspace-availspace, availspace, iused, iavail)
logit(ctx, "statfs", err, "(%d): (%d,%d,%d,%d)", ino, totalspace-availspace, availspace, iused, iavail)
return
}

Expand All @@ -75,7 +75,7 @@ func accessTest(attr *Attr, mmode uint16, uid uint32, gid uint32) syscall.Errno
}

func (v *VFS) Access(ctx Context, ino Ino, mask int) (err syscall.Errno) {
defer func() { logit(ctx, "access", "(%d,0x%X): %s", ino, mask, strerr(err)) }()
defer func() { logit(ctx, "access", err, "(%d,0x%X)", ino, mask) }()
var mmask uint16
if mask&unix.R_OK != 0 {
mmask |= MODE_MASK_R
Expand Down Expand Up @@ -144,7 +144,7 @@ func setattrStr(set int, mode, uid, gid uint32, atime, mtime int64, size uint64)
func (v *VFS) SetAttr(ctx Context, ino Ino, set int, fh uint64, mode, uid, gid uint32, atime, mtime int64, atimensec, mtimensec uint32, size uint64) (entry *meta.Entry, err syscall.Errno) {
str := setattrStr(set, mode, uid, gid, atime, mtime, size)
defer func() {
logit(ctx, "setattr", "(%d[%d],0x%X,[%s]): %s%s", ino, fh, set, str, strerr(err), (*Entry)(entry))
logit(ctx, "setattr", err, "(%d[%d],0x%X,[%s]):%s", ino, fh, set, str, (*Entry)(entry))
}()
if IsSpecialNode(ino) {
n := getInternalNode(ino)
Expand Down Expand Up @@ -219,7 +219,7 @@ func (l lockType) String() string {

func (v *VFS) Getlk(ctx Context, ino Ino, fh uint64, owner uint64, start, len *uint64, typ *uint32, pid *uint32) (err syscall.Errno) {
defer func() {
logit(ctx, "getlk", "(%d,%d,%016X): %s (%d,%d,%s,%d)", ino, fh, owner, strerr(err), *start, *len, lockType(*typ), *pid)
logit(ctx, "getlk", err, "(%d,%d,%016X): (%d,%d,%s,%d)", ino, fh, owner, *start, *len, lockType(*typ), *pid)
}()
if lockType(*typ).String() == "X" {
return syscall.EINVAL
Expand All @@ -238,7 +238,7 @@ func (v *VFS) Getlk(ctx Context, ino Ino, fh uint64, owner uint64, start, len *u

func (v *VFS) Setlk(ctx Context, ino Ino, fh uint64, owner uint64, start, end uint64, typ uint32, pid uint32, block bool) (err syscall.Errno) {
defer func() {
logit(ctx, "setlk", "(%d,%d,%016X,%d,%d,%s,%t,%d): %s", ino, fh, owner, start, end, lockType(typ), block, pid, strerr(err))
logit(ctx, "setlk", err, "(%d,%d,%016X,%d,%d,%s,%t,%d)", ino, fh, owner, start, end, lockType(typ), block, pid)
}()
if lockType(typ).String() == "X" {
return syscall.EINVAL
Expand Down Expand Up @@ -271,7 +271,7 @@ func (v *VFS) Setlk(ctx Context, ino Ino, fh uint64, owner uint64, start, end ui

func (v *VFS) Flock(ctx Context, ino Ino, fh uint64, owner uint64, typ uint32, block bool) (err syscall.Errno) {
var name string
defer func() { logit(ctx, "flock", "(%d,%d,%016X,%s,%t): %s", ino, fh, owner, name, block, strerr(err)) }()
defer func() { logit(ctx, "flock", err, "(%d,%d,%016X,%s,%t)", ino, fh, owner, name, block) }()
switch typ {
case syscall.F_RDLCK:
name = "LOCKSH"
Expand Down Expand Up @@ -323,7 +323,7 @@ func (v *VFS) Ioctl(ctx Context, ino Ino, cmd uint32, arg uint64, bufIn, bufOut
FS_XFLAG_IMMUTABLE = 0x00000008
FS_XFLAG_APPEND = 0x00000010
)
defer func() { logit(ctx, "ioctl", "(%d,0x%X,0x%X,%v,%v): %s", ino, cmd, arg, bufIn, bufOut, strerr(err)) }()
defer func() { logit(ctx, "ioctl", err, "(%d,0x%X,0x%X,%v,%v)", ino, cmd, arg, bufIn, bufOut) }()
switch cmd {
default:
return syscall.ENOTTY
Expand Down

0 comments on commit 06947bd

Please sign in to comment.