|
Given a chain of operations, if an operation has unsupported opcode, the result is unexpected.
Using the code in this repo (cargo run), the following behaviour was observed on Linux 6.18:
| IO_LINK |
SKIP_SUCCESS |
op1 |
op2 |
cqe op1 |
cqe op2 |
| op1 |
nop |
close(badf) |
0 |
EBADF |
ok |
| op1 |
op1 |
nop |
close(badf) |
no cqe |
EBADF |
ok |
| op1 |
nop |
unsupported |
ECANCELED |
EINVAL |
why is op1 canceled? |
| op1 |
op1 |
nop |
unsupported |
ECANCELED |
no cqe |
why is op1 canceled? why is there no cqe for op2? |
The experiment submits two operations, linked with IO_LINK, then polls the completion queue:
- IO_LINK: if it was set on an operation
- SKIP_SUCCESS: if it was set on an operation
- op1/op2: The first and second operation in the chain
- cqe op1/op2: The completion queue result
Confusion 1
If the second operation is unsupported (e.g: socket, followed by bind, on an older kernel),
op1 is cancelled. man says:
IOSQE_IO_LINK
When this flag is specified, the SQE forms a link with the next SQE in the
submission ring. That next SQE will not be started before the previous request
completes. [...] A chain of SQEs will be broken if any request in that chain
ends in error. [...] If a chain of SQE links is broken, the remaining unstarted
part of the chain will be terminated and completed with -ECANCELED as the error
code.
That next SQE will not be started before the previous request completes. By the time the second
operation starts adn fails, the first operation should have been completed. Yet, it gets canceled. Why?
Confusion 2
If the second operation is unsupported (e.g: socket, followed by bind, on an older kernel),
and SKIP_SUCCESS is also set, op1 gets cancelled, and there'll be no cqe for op2. Why?
|