posix_fadvise 和 readahead 之间的区别

aru*_*hub 5 linux io system-calls linux-kernel portability

根据联机帮助页,readaheadLinux 特定:

符合

readahead() 系统调用是 Linux 特定的,应避免在便携式应用程序中使用它。

并且posix_fadvise是便携式的:

符合

POSIX.1-2001、POSIX.1-2008。请注意,在 POSIX.1-2001 TC1 中,len 参数的类型从 size_t 更改为 off_t。

但他们俩似乎都在做同样的事情。但是,除了冒着可移植性的风险之外,交换这两种功能还会产生什么后果呢?

Mar*_*ler 10

让我们看看这些系统调用导致执行的代码。

\n

引用mm/readahead.c这里:

\n
 611   \xe2\x94\x82 ssize_t ksys_readahead(int fd, loff_t offset, size_t count)\n 612   \xe2\x94\x82 {\n 613   \xe2\x94\x82     ssize_t ret;\n 614   \xe2\x94\x82     struct fd f;\n 615   \xe2\x94\x82\n 616   \xe2\x94\x82     ret = -EBADF;\n 617   \xe2\x94\x82     f = fdget(fd);\n 618   \xe2\x94\x82     if (!f.file || !(f.file->f_mode & FMODE_READ))\n 619   \xe2\x94\x82         goto out;\n 620   \xe2\x94\x82\n 621   \xe2\x94\x82     /*\n 622   \xe2\x94\x82      * The readahead() syscall is intended to run only on files\n 623   \xe2\x94\x82      * that can execute readahead. If readahead is not possible\n 624   \xe2\x94\x82      * on this file, then we must return -EINVAL.\n 625   \xe2\x94\x82      */\n 626   \xe2\x94\x82     ret = -EINVAL;\n 627   \xe2\x94\x82     if (!f.file->f_mapping || !f.file->f_mapping->a_ops ||\n 628   \xe2\x94\x82         !S_ISREG(file_inode(f.file)->i_mode))\n 629   \xe2\x94\x82         goto out;\n 630   \xe2\x94\x82\n 631   \xe2\x94\x82     ret = vfs_fadvise(f.file, offset, count, POSIX_FADV_WILLNEED);\n 632   \xe2\x94\x82 out:\n 633   \xe2\x94\x82     fdput(f);\n 634   \xe2\x94\x82     return ret;\n 635   \xe2\x94\x82 }\n
Run Code Online (Sandbox Code Playgroud)\n

注意第631行:这个东西调用vfs_fadvise(\xe2\x80\xa6, POSIX_FADV_WILLNEED)underground。

\n

比较一下mm/fadvise.c:

\n
 192   \xe2\x94\x82 int ksys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)\n 193   \xe2\x94\x82 {\n 194   \xe2\x94\x82     struct fd f = fdget(fd);\n 195   \xe2\x94\x82     int ret;\n 196   \xe2\x94\x82\n 197   \xe2\x94\x82     if (!f.file)\n 198   \xe2\x94\x82         return -EBADF;\n 199   \xe2\x94\x82\n 200   \xe2\x94\x82     ret = vfs_fadvise(f.file, offset, len, advice);\n 201   \xe2\x94\x82\n 202   \xe2\x94\x82     fdput(f);\n 203   \xe2\x94\x82     return ret;\n 204   \xe2\x94\x82 }\n
Run Code Online (Sandbox Code Playgroud)\n

该代码也只是调用相同的内容vfs_fadvise,因此使用在功能上posix_fadvise64(\xe2\x80\xa6, WILLNEED)是相同的。

\n

差异(可能)在于当您使用任一函数的文件不合适时报告的错误:readahead它本身检查文件是否可读、映射、是否实际上具有任何有用的寻址操作,如果不合适则返回EBADF或EINVAL。
\n fadvise64,后面的系统调用posix_fadvise,直接调用vfs_fadvise,以便在内部检查这些内容,并可能返回不同的错误。(我还没有检查它是否真的如此)。

\n

  • 错误报告的差异是真实存在的。`vfs_fadvise` 将(至少在通用实现中)因 FIFO 上的 ESPIPE 而失败,并且默默地对不可读的文件或因任何原因不支持预读的文件执行任何操作。 (5认同)