c语言 - 为什么 Linux 不能写入超过 2147479552 个字节?



man 2 write中,NOTES部分包含以下注释:

在Linux上,write(和类似的系统调用(最多传输0x7ffff000(2147479552(个字节,返回实际传输的字节数。(这在32位和64位系统上都是正确的。(

  1. 为什么
  2. DESCRIPTION路径包含以下语句:

根据POSIX.1,如果计数大于SSIZE_MAX,则结果为实现定义的

SSIZE_MAX0x7ffff000大得多。为什么这张纸条在那里?

更新:谢谢你的回答!如果有人感兴趣(为了更好的SEO来帮助开发者(,所有有限制的功能都是:

  • read
  • write
  • sendfile

要找到这个,只需全文搜索手册:

% man -wK "0x7ffff000"
/usr/share/man/man2/write.2.gz
/usr/share/man/man2/read.2.gz
/usr/share/man/man2/sendfile.2.gz
/usr/share/man/man2/sendfile.2.gz

为什么在这里

我不认为这一定有充分的理由——我认为这基本上是一件历史文物。让我用一些数字考古学来解释。

在当前的Linux中,此限制由MAX_RW_COUNT:控制

ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
[...]
if (count > MAX_RW_COUNT)
count =  MAX_RW_COUNT;

该常量定义为整数值最大值和页面掩码的AND。这大致等于最大整数大小减去一页的大小。

#define MAX_RW_COUNT (INT_MAX & PAGE_MASK)

这就是0x7ffff000的来源——您的平台有4096字节宽的页面,即212,因此它是底部12位未设置的最大整数值。

最后一次改变这一点的提交是e28cc71572da3,忽略了只会移动事物的提交。

Author: Linus Torvalds <torvalds@g5.osdl.org>
Date:   Wed Jan 4 16:20:40 2006 -0800
Relax the rw_verify_area() error checking.

In particular, allow over-large read- or write-requests to be downgraded
to a more reasonable range, rather than considering them outright errors.

We want to protect lower layers from (the sadly all too common) overflow
conditions, but prefer to do so by chopping the requests up, rather than
just refusing them outright.

因此,这给了我们一个改变的原因:为了防止整数溢出,写入的大小被限制在接近最大整数的大小。周围的大多数逻辑似乎已经更改为使用longs或size_t,但检查仍然存在。

在此更改之前,给它一个大于INT_MAX的缓冲区将导致EINVAL错误:

if (unlikely(count > INT_MAX))
goto Einval;

至于为什么设置这个限制,它存在于2.6.12之前,2.6.12是第一个放入git的版本。我会让比我更有耐心的人来解决这个问题

这是否符合POSIX

戴上我的标准律师帽,我认为这实际上是符合POSIX的。是的,POSIX确实说大于SSIZE_MAX的写入是实现定义的行为,并且这并不大于该限制。然而,我认为标准中还有另外两句话很重要:

write((函数应尝试将buf指向的缓冲区中的nbyte字节写入与打开的文件描述符filtes关联的文件
[…]
成功完成后,write((和pwrite((将返回实际写入与filtes相关联的文件的字节数。该数字不得大于nbyte。否则,将返回-1,并设置errno以指示错误。

标准明确允许部分写入。出于这个原因,所有调用write((的代码都需要将对write(((的调用封装在一个循环中,该循环会重试短写操作。

应该提高限额吗

无视历史包袱和标准,今天有理由提高这一限制吗?

我认为答案是否定的。write((缓冲区的最佳大小是在尽量避免内核和用户空间之间过度的上下文切换和确保数据尽可能适合缓存之间进行权衡。

coreutils程序(提供cat、cp等(使用128KiB的缓冲区大小。硬件的最佳尺寸可能稍大或稍小。但2GB的缓冲区不太可能更快。

最新更新