O_DIRECT alignment is not one size: typically 4096 bytes on Linux 2.4, typically 512 bytes on Linux 2.6.0
Published 2026-10-13
Typically 4096 bytes on Linux 2.4, and typically 512 bytes on Linux 2.6.0, are the O_DIRECT alignment sizes open(2) prints, and neither is a measured disk rate. Linux man-pages 6.19 (page stamp 2026-02-08) says that on Linux 2.4 most filesystems based on block devices require the file offset and the length and memory address of all I/O segments to be multiples of the filesystem block size (typically 4096 bytes), and that in Linux 2.6.0 this was relaxed to the logical block size of the block device (typically 512 bytes). The same NOTES section says restrictions vary by filesystem and kernel version and might be absent entirely, that the Linux NFS client places no alignment restrictions, and that a misaligned direct I/O can fail with EINVAL or fall back to buffered I/O, so success does not prove the transfer stayed direct. Since Linux 6.1, statx(2) can report the file's own figures: stx_dio_mem_align and stx_dio_offset_align are alignments in bytes, and each is 0 if direct I/O is not supported on that file.
- Population
- Sentences in open(2) NOTES under O_DIRECT, the O_DIRECT flag description in open(2), and the STATX_DIOALIGN fields in statx(2). Not a set of disks, not a filesystem census, and not a kernel tree.
- Documents
- Linux man-pages 6.19, page stamp 2026-02-08, for both open(2) and statx(2). Each colophon says the HTML was obtained from man-pages-6.19.tar.gz fetched on 2026-09-09. Opened 13 October 2026.
- What typically means
- typically 4096 bytes is the manual's parenthetical for the filesystem block size. typically 512 bytes is the parenthetical for the logical block size of the block device. Neither is a measured transfer rate, and neither was read back with BLKSSZGET or blockdev --getss.
- What a row is
- One printed byte figure. The Linux NFS client, IRIX, FreeBSD 4.x, and the ext4, f2fs, and xfs support sentence have no byte size in the opened pages, so they are not rows.
Comparison
| Rule | Linux version (as printed) | Alignment (bytes, as printed) | Operands | How to read the figure | Source |
|---|---|---|---|---|---|
| Linux 2.4 filesystem block size, most filesystems based on block devices | 2.4 | typically 4096 | file offset, length, and memory address of all I/O segments | Parenthetical filesystem block size in open(2) NOTES. Not a measured disk rate. | open(2) |
| Linux 2.6.0 relaxation of that same requirement | 2.6.0 | typically 512 | file offset, length, and memory address; the multiple is the logical block size of the block device | Parenthetical logical block size. Not a measured disk rate, and not a conversion of the 4096-byte row. | open(2) |
| stx_dio_mem_align when direct I/O is not supported on the file | 6.1 | 0 | user memory buffers for O_DIRECT | 0 means direct I/O is not supported on this file. It does not mean any alignment is accepted. Linux 6.1 is when statx(2) says STATX_DIOALIGN can be requested. | statx(2) |
| stx_dio_offset_align when direct I/O is not supported on the file | 6.1 | 0 | file offsets and I/O segment lengths for O_DIRECT | 0 means not supported. The field is nonzero only when stx_dio_mem_align is nonzero, and vice versa. | statx(2) |
| stx_dio_read_offset_align if zero, field definition | 6.14 | 0 | file offsets and I/O segment lengths for direct I/O reads | If zero, stx_dio_offset_align applies for reads as well. Not the not-supported sentinel. A non-zero value must be smaller than or equal to stx_dio_offset_align and does not change stx_dio_mem_align. Linux 6.14 is the mask line for STATX_DIO_READ_ALIGN. Not a measured xfs value. | statx(2) |
Derived extract of byte figures the two manual pages print. Not a copy of either manual, not a benchmark, and not a logical-block-size reading. Canonical pages are the source column. typically 4096 and typically 512 are not converted and not divided. The three zeros are three sentences with two different meanings. The Linux NFS client is absent from the table because open(2) prints no byte size for it. Checks under the table are not source cells.
Checks on the printed figures
- Not divided and not converted
- 4096 and 512 stay on their own rows. This page does not divide 4096 by 512, does not call one figure eight of the other, and does not turn either parenthetical into MB/s or a throughput. Arithmetic of that kind is not a source sentence.
- Two meanings of 0, and NFS is neither
- On the Linux 6.1 rows, 0 means direct I/O is not supported on that file. On the Linux 6.14 row, 0 means the stx_dio_offset_align limit applies to reads as well. open(2) says the Linux NFS client places no alignment restrictions. That sentence prints no 0 and is not stored as 0 bytes.
- Versions that are not the alignment size
- O_DIRECT support was added in Linux 2.4.10, and older kernels simply ignore the flag. That sentence is not the Linux 2.4 alignment sentence, so 2.4.10 is not given typically 4096 bytes. statx(2) HISTORY says Linux 4.11, glibc 2.28 for statx itself. STATX_DIOALIGN is since Linux 6.1. In the Synchronized I/O section, before Linux 2.6.33 O_SYNC was implemented as the equivalent of O_DSYNC. That date stays in that section and is not attached to the 512-byte row.
- Other systems on the same NOTES
- open(2) says SGI IRIX has alignment restrictions similar to those of Linux 2.4, and that FreeBSD 4.x introduced a flag of the same name without alignment restrictions. IRIX is not given 4096 bytes. FreeBSD is not given 0 bytes. Neither is a row.
- Named filesystems are not a count
- statx(2) says STATX_DIOALIGN is supported on block devices since Linux 6.1, and on regular files by ext4, f2fs, and xfs since Linux 6.1. This page does not store a count of those names. No byte size is printed for them.
- Support wording left as printed
- The mask line says STATX_DIO_READ_ALIGN wants stx_dio_read_offset_align, since Linux 6.14, support varying by filesystem. A later sentence says STATX_DIO_READ_ALIGN (stx_dio_offset_align) is supported by xfs on regular files since Linux 6.14. The parenthetical names stx_dio_offset_align. This page does not rewrite it.
- Interface not opened
- open(2) names the XFS_IOC_DIOINFO operation in xfsctl(3) and says STATX_DIOALIGN should be used instead when it is available. xfsctl(3) was not opened. No ioctl field is a cell.
Method
The cells are copied from two manual pages opened on 13 October 2026: open(2) and statx(2), both Linux man-pages 6.19, page stamp 2026-02-08. Each HTML colophon says the page was obtained from the tarball man-pages-6.19.tar.gz fetched on 2026-09-09. Each table row is one printed byte figure: the Linux 2.4 and Linux 2.6.0 sentences in the O_DIRECT NOTES of open(2), and the zero cases in the statx(2) definitions of stx_dio_mem_align, stx_dio_offset_align, and stx_dio_read_offset_align. The Linux NFS sentence is not a row because it prints no byte size. No kernel was booted, statx was not called, and the ioctl BLKSSZGET and the command blockdev --getss were not run. Nothing in a cell is a quotient or a unit conversion. open(2) names XFS_IOC_DIOINFO in xfsctl(3); that page was not opened.
Limits
The population is the wording of those two manual pages, not a sample of files, filesystems, or disks. They were opened on 13 October 2026. Their page stamp is 2026-02-08 and each colophon names a tarball fetch on 2026-09-09. Not measured: a live stx_dio_mem_align, stx_dio_offset_align, or stx_dio_read_offset_align; a logical block size from BLKSSZGET or blockdev --getss; any throughput; whether a given filesystem returns EINVAL or falls back to buffered I/O; what the Linux NFS client returns from STATX_DIOALIGN; any field of XFS_IOC_DIOINFO. The sentences that print typically 4096 bytes and typically 512 bytes name no test machine and no benchmark date. Those sizes stay parenthetical examples. A 0 in the table is the manual's sentinel, not a value read from a file for this page.
What the signal catches, and what it misses
The fault is reading typically 4096 bytes, or typically 512 bytes, as the alignment of every O_DIRECT transfer. open(2) places typically 4096 bytes on Linux 2.4, for most filesystems based on block devices, as the filesystem block size that the file offset, the length, and the memory address of all I/O segments must be a multiple of. It places typically 512 bytes on the Linux 2.6.0 relaxation, as the logical block size of the block device. The same NOTES section says that in Linux alignment restrictions vary by filesystem and kernel version and might be absent entirely. It also says that if statx and a filesystem-specific query are unavailable, alignment can only be assumed from the filesystem, the individual file, the underlying storage device, and the kernel version. The Linux NFS client is the counterexample printed on that page: it places no alignment restrictions on O_DIRECT I/O. That sentence does not print a byte size. statx(2) uses 0 for a different fact, that direct I/O is not supported on the file.
The signal that catches a per-file rule, since Linux 6.1, is statx(2) with STATX_DIOALIGN. The mask requests stx_dio_mem_align and stx_dio_offset_align. stx_dio_mem_align is the alignment in bytes for user memory buffers. stx_dio_offset_align is the alignment in bytes for file offsets and I/O segment lengths. Each is nonzero only when the other is nonzero. statx(2) says the query is supported on block devices since Linux 6.1, and on regular files by ext4, f2fs, and xfs since Linux 6.1, with other regular-file support varying by filesystem. open(2) says the same flag is how O_DIRECT support and alignment restrictions for a file can be queried, and that support varies by filesystem. A logical block size from the ioctl BLKSSZGET, or from blockdev --getss, is the device figure open(2) names behind the 512-byte parenthetical. Those commands were not run here. Their result would not be stx_dio_offset_align, and it would not say that a filesystem's restriction is absent.
That query misses a transfer that succeeded and was not direct. open(2) says misaligned O_DIRECT I/Os can fail with EINVAL or fall back to buffered I/O, so a successful call does not prove the I/O stayed direct. A different EINVAL is open() failing because the filesystem does not implement O_DIRECT. Kernels older than the flag ignore it: support was added in Linux 2.4.10, and older Linux kernels simply ignore the flag. statx(2) says that, in general, the kernel does not reject mask bits other than the reserved one, and reports support in stx_mask. The reserved-flag EINVAL is STATX__RESERVED, value 0x80000000U. An unsupported STATX_DIOALIGN request is not described as that EINVAL, and a clear stx_mask bit is not an alignment of 4096 or 512. Since Linux 6.14 the read path can use another field. If stx_dio_read_offset_align is zero, the limit in stx_dio_offset_align applies for reads as well. If non-zero, it must be smaller than or equal to stx_dio_offset_align, and stx_dio_mem_align is not affected. The support sentence prints STATX_DIO_READ_ALIGN (stx_dio_offset_align) for xfs on regular files since Linux 6.14. The mask line names stx_dio_read_offset_align. Both sentences stay as printed.
Alignment does not catch a durability failure. In the O_DIRECT flag description, open(2) says the flag on its own makes an effort to transfer data synchronously, but does not give the guarantees of the O_SYNC flag that data and necessary metadata are transferred. To guarantee synchronous I/O, O_SYNC must be used in addition to O_DIRECT. Under NOTES, the NFS protocol does not pass the flag to the server, so O_DIRECT bypasses the page cache only on the client, and the server may still cache the I/O. The same paragraph says some servers may be configured to lie to clients about the I/O having reached stable storage. Those sentences are not a throughput, and they are not properties of the 4096-byte or 512-byte rows. The Synchronized I/O section's date for O_SYNC before Linux 2.6.33 is a different section and is not moved onto those rows.
Whether a later successful sync means the bytes are durable is a different question. See why a successful fsync retry can still be the wrong conclusion. Other measurements are on the analyses index.
Sources
- 01open(2) — Linux manual page, man-pages 6.19, page stamp 2026-02-08. O_DIRECT flag description and NOTES, including the Linux 2.4 and Linux 2.6.0 alignment sentences, NFS, and EINVAL or buffered fallback. HTML colophon: man-pages-6.19.tar.gz fetched 2026-09-09. · accessed 2026-10-13
- 02statx(2) — Linux manual page, man-pages 6.19, page stamp 2026-02-08. STATX_DIOALIGN, stx_dio_mem_align, stx_dio_offset_align, and stx_dio_read_offset_align. HTML colophon: man-pages-6.19.tar.gz fetched 2026-09-09. · accessed 2026-10-13