Two adjacent io_uring submission queue entries are normally independent requests. Setting IOSQE_IO_LINK on the first changes that relationship: the next request does not start before the linked request completes. Repeating the flag forms an ordered chain inside one submission batch.
The ordering property is narrower than global queue serialization. Requests outside the chain can still run independently, and separate chains can overlap. A link therefore expresses dependency between specific SQEs rather than imposing a barrier on the entire ring.
The flag points from one SQE to the next
IOSQE_IO_LINK belongs to the SQE that precedes the dependency edge:
struct io_uring_sqe *a = io_uring_get_sqe(&ring);
io_uring_prep_read(a, src_fd, buf, len, 0);
a->flags |= IOSQE_IO_LINK;
struct io_uring_sqe *b = io_uring_get_sqe(&ring);
io_uring_prep_write(b, dst_fd, buf, len, 0);The write cannot start before the read completes. Extending the chain requires setting the flag on b as well and placing another SQE after it. The first SQE without the link flag terminates the chain.
Chains do not cross submission boundaries. A trailing SQE marked IOSQE_IO_LINK cannot reserve a dependency edge for an SQE submitted later. The linked members must be present in the same submission.
Soft links couple ordering with completion status
A normal IOSQE_IO_LINK is commonly called a soft link. If a request breaks the chain, unstarted requests that remain in that chain complete with -ECANCELED.
The break condition is broader than a negative error code. Linux io_uring also treats an unexpected result as a chain-breaking result for soft links. A short read is a significant example: an operation may have transferred data successfully, yet a result shorter than the requested length can still stop the dependent chain.
That distinction matters for pipelines whose next operation assumes a full buffer. The chain encodes both sequencing and a completion condition chosen by the opcode semantics. It is not equivalent to submitting several asynchronous operations and merely asking the kernel to preserve their order.
Hard links preserve the dependency edge after completion results
IOSQE_IO_HARDLINK also links an SQE to its successor, but completion results do not sever the chain in the same manner:
struct io_uring_sqe *a = io_uring_get_sqe(&ring);
io_uring_prep_read(a, src_fd, buf, len, 0);
a->flags |= IOSQE_IO_HARDLINK;
struct io_uring_sqe *b = io_uring_get_sqe(&ring);
io_uring_prep_fsync(b, dst_fd, 0);The second request remains ordered after the first, while an error or unexpected completion result from the first does not by itself cancel the successor. This is useful when the ordering dependency remains valid even when an earlier operation reports failure.
A hard link is not an unconditional transaction primitive. Submission failure of the parent request can still sever the link, and each operation retains its own completion result. The API supplies ordering and chain-continuation semantics; it does not provide rollback or atomicity across unrelated kernel operations.
Linked chains do not serialize the whole ring
Suppose a submission contains two chains and one independent request:
A -> B -> C
D -> E
FWithin each chain, a successor waits for its predecessor. Nothing in the link relationship requires D to wait for C, or F to wait for either chain. The kernel can make progress on those independent units concurrently when their operations and execution context permit it.
This boundary separates IOSQE_IO_LINK from IOSQE_IO_DRAIN. A drain request constrains work relative to previously submitted and subsequently started SQEs, while a link constrains only the chain formed by adjacent entries. Treating both as generic ordering flags hides a material difference in scope.
Completion queues expose each operation separately
Linking does not merge requests into one completion record. Each SQE normally produces its own CQE, so applications still identify and process the result of each operation. When a soft chain breaks, the originating request carries its own result and unstarted successors report -ECANCELED.
Features such as IOSQE_CQE_SKIP_SUCCESS can alter whether successful operations generate CQEs, but that is a separate completion-reporting policy. The dependency chain itself remains a relation among submitted operations.
The resulting model is precise: links serialize only declared dependencies, soft links can propagate a failed or unexpected completion into cancellation of the remaining chain, and hard links retain ordering across completion results. None of those properties turns a chain into a global ring barrier or a multi-operation transaction.