preadv2 / pwritev2(2)
Scatter/gather I/O at an offset with per-call flags: RWF_NOWAIT, RWF_HIPRI, RWF_DSYNC, RWF_SYNC, RWF_APPEND.
- Since
- Linux 4.6check your kernel →
- glibc
- glibc 2.26
- System
- Linux
- Man page
- preadv2 / pwritev2(2)
Synopsis
#include <sys/uio.h>
ssize_t preadv2(int fd, const struct iovec *iov, int iovcnt,
off_t offset, int flags);
ssize_t pwritev2(int fd, const struct iovec *iov, int iovcnt,
off_t offset, int flags);Rod's take
preadv2/pwritev2 extend preadv/pwritev with a flags argument that applies to a single call. RWF_NOWAIT is the standout: it returns EAGAIN instead of blocking on a page cache miss, enabling a polling fast-path without io_uring. RWF_DSYNC/RWF_SYNC give per-call durability without setting O_DSYNC globally on the fd. RWF_HIPRI requests polled NVMe delivery but silently falls back on unsupported devices. Pass flags=0 and behavior is identical to preadv/pwritev.
Flags and arguments that matter
| Name | What it does |
|---|---|
| RWF_NOWAITLinux 4.14 | Return EAGAIN immediately if the operation would block (page cache miss, lock contention). Only effective on regular files and some block devices; returns EOPNOTSUPP on pipes/sockets. |
| RWF_HIPRI | Request polled I/O delivery instead of interrupt-driven completion. Reduces tail latency on NVMe devices with polled queues (/sys/block/.../queue/io_poll). Degrades silently to normal I/O on unsupported devices. Most effective with O_DIRECT. |
| RWF_DSYNC | Per-call O_DSYNC: data and enough metadata for recovery are written to stable storage before the call returns. Does not affect other writes on the same fd. |
| RWF_SYNC | Per-call O_SYNC: all data and all metadata are written to stable storage before return. Stricter than RWF_DSYNC. |
| RWF_APPENDLinux 4.16 | Atomic append regardless of fd flags: seek-to-end and write are atomic with respect to other O_APPEND/RWF_APPEND writers. The offset argument is ignored. |
Errors you will actually hit
| errno | Meaning |
|---|---|
| EAGAIN | RWF_NOWAIT set and the operation would block. |
| EOPNOTSUPP | RWF_NOWAIT used on a file type that does not support it (pipe, socket, etc.). |
| EINVAL | Unknown flag, or offset is -1 and the fd has no current position. |
Example
#include <sys/uio.h>
struct iovec iov = { .iov_base = buf, .iov_len = len };
/* non-blocking read: fast-path from page cache only */
ssize_t n = preadv2(fd, &iov, 1, offset, RWF_NOWAIT);
if (n < 0 && errno == EAGAIN) {
/* cache miss: queue blocking read or io_uring sqe */
}
/* single durable write without O_DSYNC on the fd */
n = pwritev2(fd, &iov, 1, offset, RWF_DSYNC);Trimmed from the full walkthrough in preadv2(2): per-call I/O flags without reopening the fd.
BSD equivalent
FreeBSD has preadv/pwritev (FreeBSD 6, 2005) but no preadv2/pwritev2 and no RWF_* flags. Per-call durability requires explicit fdatasync(2)/fsync(2). Polled I/O is handled at the GEOM/cam_iosched layer, not via fd flags.
The long version, from the console
Sources
Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.
