go-fuse
go-fuse copied to clipboard
Errors from `(fs.DirStream).Next` of non-empty stream are obscured as `EIO`
If any call to (fs.DirStream).Next
other than the first one returns an error, users reading the directory entries see an EIO
instead of the returned error.
Here is a gist that illustrates the issue: https://gist.github.com/jcharum/c25d228e62e0338d2620dfa20f04e1d1 . The failing output looks like:
❯ go test
2022/08/19 21:14:13 writer: Write/Writev failed, err: 22=invalid argument. opcode: READDIRPLUS
2022/08/19 21:14:13 writer: Write/Writev failed, err: 22=invalid argument. opcode: READDIRPLUS
2022/08/19 21:14:13 writer: Write/Writev failed, err: 22=invalid argument. opcode: READDIRPLUS
2022/08/19 21:14:13 writer: Write/Writev failed, err: 22=invalid argument. opcode: READDIRPLUS
2022/08/19 21:14:13 writer: Write/Writev failed, err: 22=invalid argument. opcode: READDIRPLUS
2022/08/19 21:14:13 writer: Write/Writev failed, err: 22=invalid argument. opcode: READDIRPLUS
2022/08/19 21:14:13 writer: Write/Writev failed, err: 22=invalid argument. opcode: READDIRPLUS
2022/08/19 21:14:13 writer: Write/Writev failed, err: 22=invalid argument. opcode: READDIRPLUS
2022/08/19 21:14:13 writer: Write/Writev failed, err: 22=invalid argument. opcode: READDIRPLUS
--- FAIL: TestNextError (0.02s)
--- FAIL: TestNextError/errAt_1 (0.00s)
streamerr_test.go:70: error is not "operation not permitted": "readdirent /tmp/streamerr-TestNextError1269835921: input/output error"
--- FAIL: TestNextError/errAt_2 (0.00s)
streamerr_test.go:70: error is not "operation not permitted": "readdirent /tmp/streamerr-TestNextError1958719290: input/output error"
--- FAIL: TestNextError/errAt_3 (0.00s)
streamerr_test.go:70: error is not "operation not permitted": "readdirent /tmp/streamerr-TestNextError1750548731: input/output error"
--- FAIL: TestNextError/errAt_4 (0.00s)
streamerr_test.go:70: error is not "operation not permitted": "readdirent /tmp/streamerr-TestNextError4079832694: input/output error"
--- FAIL: TestNextError/errAt_5 (0.00s)
streamerr_test.go:70: error is not "operation not permitted": "readdirent /tmp/streamerr-TestNextError749431903: input/output error"
--- FAIL: TestNextError/errAt_6 (0.00s)
streamerr_test.go:70: error is not "operation not permitted": "readdirent /tmp/streamerr-TestNextError1728283887: input/output error"
--- FAIL: TestNextError/errAt_7 (0.00s)
streamerr_test.go:70: error is not "operation not permitted": "readdirent /tmp/streamerr-TestNextError4240042809: input/output error"
--- FAIL: TestNextError/errAt_8 (0.00s)
streamerr_test.go:70: error is not "operation not permitted": "readdirent /tmp/streamerr-TestNextError3503040526: input/output error"
--- FAIL: TestNextError/errAt_9 (0.00s)
streamerr_test.go:70: error is not "operation not permitted": "readdirent /tmp/streamerr-TestNextError364701475: input/output error"
FAIL
exit status 1
FAIL streamerr 0.025s
If the first call to Next
returns an error, say EPERM
, that error is (wrapped and) returned to the caller of Readdir
. If a subsequent call (after a successful call to Next
) returns EPERM
, the caller of Readdir
sees a (wrapped) EIO
instead.
I think this happens because the Writev
to the server with the READDIRPLUS
error response has unexpected data, the successful entries so far, as they remain part of the message even on error: https://github.com/hanwen/go-fuse/blob/0aaef6dde4b62dd0f21d545c5001d9e5ece0c87e/fs/bridge.go#L1001-L1013 .
If this is expected behavior, could it be documented somewhere (or maybe it is, and I didn't find it)? If not, maybe the solution is to clear the DirEntryList
when we encounter an error?