statvfs系统调用失败,错误值对于定义的数据types太大

我在我的服务器上安装了红帽企业Linux服务器版本6.6(2.6.32-504.el6.x86_64),并具有低于分区的层次结构。

Filesystem Size Used Avail Use% Mounted on /dev/sda2 7.9G 1.7G 5.9G 22% / tmpfs 5.4G 8.0K 5.4G 1% /dev/shm /dev/sda8 53G 1.4G 49G 3% /mysql/data /dev/sda6 7.9G 4.5G 3.1G 60% /usr/BWhttpd /dev/sda4 32G 989M 29G 4% /var /dev/sdb1 25T 37M 25T 1% /media1 /dev/sdc1 25T 37M 25T 1% /media2 /dev/sdd1 25T 37M 25T 1% /media3 /dev/sde1 22T 21T 1.1T 95% /media4 

我发出一个statvfs调用每个

/ mediax

分区但系统调用失败,错误Value too large for defined data type

我能够find系统调用返回错误EOVERFLOW但不知道struct statvfs哪个成员导致了这一点。

它是否必须对/ mediax分区的大小做任何事情。

注意:分区是xfs文件系统types。

正如man 2 statfs手册页所述:

最初的Linux statfs()和fstatfs()系统调用并没有考虑到极大的文件大小。 随后,Linux 2.6添加了使用新结构statfs64的新的statfs64()和fstatfs64()系统调用。 新的结构包含与原始statfs结构相同的字段,但各个字段的大小都会增加,以适应较大的文件大小。 glibc statfs()和fstatfs()包装函数透明地处理内核差异。

在你的情况下,出于某种原因,你正在使用非64位版本的系统调用。

Linux内核使用四个不同的系统调用(以及可选的兼容版本)实现fstat*fs*()stat*fs*()库调用: fstatfs()fstatfs64()statfs()statfs64() 。 所有这四个都在内核源码中的fs/statfs.c中定义,并使用内核函数vfs_statfs()将必要的信息收集到struct kstatfs结构中。

statfs()fstatfs()使用内核内部函数do_statfs_native() (在fs/statfs.c )将内核struct kstatfs的字段复制到用户空间struct statfs缓冲区中。 问题是,许多内核结构字段比用户空间缓冲区中的字段大。 do_statfs_native()验证这些值是否合适,否则将返回-EOVERFLOW

这是唯一的情况下,我可以找到可能导致任何四个系统调用返回-EOVERFLOW

对于statfs64()fstatfs64() ,使用内核函数do_statfs64()将字段从内核struct kstatfs到用户空间struct statfs64缓冲区。 用户空间缓冲区字段至少与内核结构字段一样大,所以不存在溢出风险。 (该函数不会返回-EOVERFLOW 。)

解决方法是确保使用64位版本的struct statfs和相应的系统调用。


为了确保glibc使用结构的正确版本(可以正确描述非常大的文件系统的版本),确保你有

 #define _FILE_OFFSET_BITS 64 

在任何#include之前; 或者,将-D_FILE_OFFSET_BITS=64添加到您的编译器标志。

所有这一切都确保了glibc知道你正在Linux 2.6或更高版本的内核(3.x,4.x等等)上运行,并且它肯定应该尝试使用适当的结构版本,大小的领域。

或者,您可以定义_LARGEFILE64_SOURCE ,以公开struct statfs64struct statvfs64类型以及相应的系统调用的statfs64()statvfs64()包装器。 这可以避免让glibc做任何猜测,并确保使用可以正确描述所有Linux文件系统大小的系统调用版本。

这两个选项都适用于所有Linux架构,32位和64位。

不是一个完整的答案,但关于内核代码(v4.9,目前我没有你的内核的代码,但我怀疑这个部分已经改变了很多),你应该搜索一个值> 0xffffffff以下参数之一: f_blocksf_bfreef_bavailf_bsizef_frsizef_filesf_files ,即除f_fsidf_flagf_namemax之外的任何参数:

 if (sizeof buf->f_blocks == 4) { if ((st.f_blocks | st.f_bfree | st.f_bavail | st.f_bsize | st.f_frsize) & 0xffffffff00000000ULL) return -EOVERFLOW; /* * f_files and f_ffree may be -1; it's okay to stuff * that into 32 bits */ if (st.f_files != -1 && (st.f_files & 0xffffffff00000000ULL)) return -EOVERFLOW; if (st.f_ffree != -1 && (st.f_ffree & 0xffffffff00000000ULL)) return -EOVERFLOW; }