Reputation: 1382
I have a Red Hat Enterprise Linux Server release 6.6 (2.6.32-504.el6.x86_64) installed on my server and have below partitions hierarchy.
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
I issue a statvfs
call on each of the
/mediax
partition but the system call fails with error Value too large for defined data type
.
I was able to find the system call returned error EOVERFLOW
but not sure which member of struct statvfs
resulted in this.
Does it have to do anything with the size of the /mediax partitions.
Note: Partitions are of xfs file system type.
Upvotes: 4
Views: 2970
Reputation: 39406
As mentioned in the man 2 statfs
man page:
The original Linux statfs() and fstatfs() system calls were not designed with extremely large file sizes in mind. Subsequently, Linux 2.6 added new statfs64() and fstatfs64() system calls that employ a new structure, statfs64. The new structure contains the same fields as the original statfs structure, but the sizes of various fields are increased, to accommodate large file sizes. The glibc statfs() and fstatfs() wrapper functions transparently deal with the kernel differences.
In your case, you are using the non-64-bit versions of the syscalls for some reason.
The Linux kernel implements the fstat*fs*()
and stat*fs*()
library calls using four different syscalls (plus optionally their compatibility versions): fstatfs()
, fstatfs64()
, statfs()
, and statfs64()
. All four are defined in fs/statfs.c
in the kernel sources, and use kernel internal function vfs_statfs()
to gather the necessary information into a struct kstatfs
structure.
Both statfs()
and fstatfs()
use the kernel internal function do_statfs_native()
(in fs/statfs.c
) to copy the fields from a kernel struct kstatfs
to the userspace struct statfs
buffer. The problem is, many of the kernel structure fields are larger than the fields in the userspace buffer. The do_statfs_native()
verifies that the values fit, and if not, will return -EOVERFLOW
otherwise.
That is the only case I can find that may cause any of the four syscalls to return -EOVERFLOW
.
For statfs64()
and fstatfs64()
, kernel function do_statfs64()
is used to copy the fields from the kernel-internal struct kstatfs
to an userspace struct statfs64
buffer. The userspace buffer fields are at least as large as the kernel structure fields are, so there is no risk of overflow. (The function never returns -EOVERFLOW
.)
The fix is to ensure you use the 64-bit versions of the struct statfs
, and the corresponding syscalls.
To ensure glibc uses the correct versions (the ones that can correctly describe very large filesystems) of the structures, ensure you have
#define _FILE_OFFSET_BITS 64
before any #include
s; or, add -D_FILE_OFFSET_BITS=64
to your compiler flags.
All this does is it ensures that glibc knows that you are running on a Linux 2.6 or later kernel (3.x, 4.x, and so on), and that it definitely should try and use the versions of the structures with properly-sized fields.
Alternatively, you can define _LARGEFILE64_SOURCE
, to expose the struct statfs64
and struct statvfs64
types and corresponding statfs64()
and statvfs64()
wrappers around the syscalls. This avoids letting glibc do any guesswork, and ensures you use the versions of the syscalls that can correctly describe all Linux filesystem sizes.
Both of these options work on all Linux architectures, 32-bit and 64-bit.
Upvotes: 3
Reputation: 8180
Not a full answer, but regarding the kernel code (v4.9, I have currently no code of your kernel, but I doubt that this part has changed a lot), you should search for a value > 0xffffffff
for one of the following parameters: f_blocks
, f_bfree
, f_bavail
, f_bsize
, f_frsize
, f_files
or f_files
, i.e., any parameter except f_fsid
, f_flag
, and f_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;
}
Upvotes: 1