没有POSIX标准支持直接IO。
截至2023年1月,至少存在两种不同的API和行为。Linux、FreeBSD和显然IBM的AIX使用O_DIRECT
标志来执行open()
,而Oracle的Solaris则在已打开的文件描述符上使用directio()
函数。
Linux对POSIX open()
函数中O_DIRECT
标志的使用在Linux open()
手册页中有记录:
O_DIRECT
(自Linux 2.4.10起)
尝试最小化对此文件进行I/O的缓存效应。通常情况下,这会降低性能,但在特殊情况下非常有用,例如应用程序自己进行缓存https://en.wikipedia.org/wiki/QFSwhen时。文件I/O直接完成到/从用户空间缓冲区。单独使用O_DIRECT
标志会努力实现数据同步传输,但不提供O_SYNC
标志的保证,即数据和必要元数据将被传输。为保证同步I/O,必须除了使用O_DIRECT
外还需使用O_SYNC。有关详细讨论,请参见下面的NOTES。
Linux没有明确指定直接IO如何与同一文件上打开的其他描述符交互,或者使用mmap()
映射文件时会发生什么;也没有对直接IO读取或写入操作的对齐或大小限制。根据我的经验,这些都是特定于文件系统的,并且随着时间的推移而改进/变得不那么受限制,但大多数Linux文件系统需要页面对齐的IO缓冲区,而许多(多数?所有?)(曾经?现在仍然?)需要页面大小的读取或写入。
FreeBSD遵循Linux模型:通过将 O_DIRECT
标志传递给 open()
:
O_DIRECT
可用于最小化或消除读写的缓存效应。 系统将尝试避免缓存您读取或写入的数据。 如果它无法避免缓存数据,则会将数据对缓存的影响最小化。 不慎使用此标志会严重降低性能。
OpenBSD不支持直接IO。在OpenBSD的open()
或OpenBSD的'fcntl()`手册中都没有提到直接IO。
IBM的AIX 似乎支持Linux类型的O_DIRECT
标志来执行open()
, 但实际发布的IBM AIX手册似乎并不普遍可用。
SGI的Irix也支持Linux风格的O_DIRECT
标志来执行open()
:
O_DIRECT
若设定,则所有在此文件描述符上进行的读写操作都将直接执行到/从用户程序缓冲区,前提是满足适当的大小和对齐要求。有关如何确定对齐约束条件的信息,请参见fcntl(2)
手册中的F_SETFL
和F_DIOINFO
命令。
O_DIRECT
是 Silicon Graphics 扩展,仅受支持于本地 EFS 和 XFS 文件系统以及远程 BDS 文件系统。
值得注意的是,在 Linux 上的 XFS 文件系统起源于 SGI 的 Irix。
Solaris 使用了完全不同的接口。Solaris 使用 特定的directio()
函数,以在每个文件上设置直接 IO:
描述
directio()函数提供了对系统关于应用程序在访问与打开文件描述符fildes相关联的数据时预期行为的建议。系统使用这些信息来优化对文件数据的访问。尽管这可能会影响其他操作的性能,但directio()函数对数据的语义没有影响。
建议参数是针对每个文件保留的;调用directio()的最后一个调用者为使用与fildes相关联的文件的所有应用程序设置建议。
建议的值在中定义。
DIRECTIO_OFF
当应用程序访问文件数据时,应用程序获得默认的系统行为。
当应用程序从文件中读取数据时,数据首先被缓存在系统内存中,然后复制到应用程序的缓冲区(参见read(2))。如果系统检测到应用程序正在顺序读取文件,则系统将异步地从文件中“预读”到系统内存中,以便数据立即可用于下一个read(2)操作。
当应用程序将数据写入文件时,数据首先被缓存在系统内存中,并在稍后的时间写入设备(参见write(2))。当可能时,系统通过将数据缓存在内存页中来增加write(2)操作的性能。数据被复制到系统内存,并且write(2)操作立即返回给应用程序。数据稍后会异步写入设备。当可能时,缓存的数据被“聚集”到大块中,并以单个写操作写入设备。
DIRECTIO_OFF的系统行为可能会随时更改。
DIRECTIO_ON
系统表现得好像应用程序在不久的将来不会重用文件数据。换句话说,文件数据不会缓存在系统的内存页中。
当使用read(2)和write(2)操作访问数据时,尽可能地在应用程序的内存和设备之间直接读取或写入数据。当无法进行这样的传输时,系统会切换回默认行为,但只对该操作有效。一般情况下,当应用程序的缓冲区对齐在两字节(short)边界上,文件的偏移量在设备扇区边界上,并且操作的大小是设备扇区的倍数时,传输是可能的。
在与fildes相关联的文件映射(参见mmap(2))时,此建议将被忽略。
DIRECTIO_ON的系统行为可能会随时更改。
请注意,在Solaris上的行为也是不同的:如果任何进程通过直接IO启用了文件,那么访问该文件的
所有进程都将通过直接IO进行访问(Solaris 10+对直接IO没有对齐或大小限制,因此在直接IO和“正常”IO之间切换不会破坏任何东西*)。如果一个文件通过
mmap()
映射,那么该文件的直接IO将被完全禁用。
* - 这并不是完全正确的 - 如果您正在使用SAMFS或QFS文件系统以共享模式,并从文件系统的活动元数据控制器(其中文件系统必须通过Solaris forcedirectio
挂载选项进行挂载,以便在群集中的一个系统上通过直接IO完成所有访问),如果您使用directio(fd, DIRECTIO_OFF)
禁用文件的直接IO,则会损坏文件系统。如果您在QFS元数据控制器上进行数据库恢复,Oracle自己的顶级RAC数据库就会这样做,您将最终得到一个损坏的文件系统。