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

时间:2016-12-02 10:07:28

标签: c linux filesystems system-calls glibc

我的服务器上安装了Red Hat Enterprise Linux Server 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

我能够找到系统调用返回错误EOVERFLOW,但不确定struct statvfs的哪个成员导致此错误。

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

  

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

2 个答案:

答案 0 :(得分:3)

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复制到用户空间{{ 1}}缓冲区。问题是,许多内核结构字段大于用户空间缓冲区中的字段。 struct statfs验证值是否合适,否则将返回do_statfs_native()

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

对于-EOVERFLOWstatfs64(),内核函数fstatfs64()用于将字段从内核do_statfs64()复制到用户空间struct kstatfs缓冲区。用户空间缓冲区字段至少与内核结构字段一样大,因此不存在溢出的风险。 (该函数永远不会返回struct statfs64。)

修复是为了确保您使用64位版本的-EOVERFLOW以及相应的系统调用。

为确保glibc使用正确的版本(能够正确描述非常大的文件系统的版本),请确保

struct statfs
在任何#define _FILE_OFFSET_BITS 64 之前

;或者,将#include添加到编译器标志中。

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

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

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

答案 1 :(得分:1)

不是完整的答案,但关于内核代码(v4.9,我目前没有内核代码,但我怀疑这部分已经发生了很大的变化),你应该搜索一个值> 0xffffffff用于以下参数之一:f_blocksf_bfreef_bavailf_bsizef_frsizef_files或{{ 1}},即除f_filesf_fsidf_flag以外的任何参数:

f_namemax