diff options
author | jhb <jhb@FreeBSD.org> | 2007-08-28 20:28:12 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2007-08-28 20:28:12 +0000 |
commit | 736eaf5ce3efb9100c867e89a189456aaf2cfb94 (patch) | |
tree | 6c90a59f892dc8f1d97e9a4c9dbc5d141cf5adfa /sys/kern/vfs_syscalls.c | |
parent | 5b26984cf1dd44727a7b2c2a6c0cfcf737b5efee (diff) | |
download | FreeBSD-src-736eaf5ce3efb9100c867e89a189456aaf2cfb94.zip FreeBSD-src-736eaf5ce3efb9100c867e89a189456aaf2cfb94.tar.gz |
Rework the routines to convert a 5.x+ statfs structure (with fixed-size
64-bit counters) to a 4.x statfs structure (with long-sized counters).
- For block counters, we scale up the block size sufficiently large so
that the resulting block counts fit into a the long-sized (long for the
ABI, so 32-bit in freebsd32) counters. In 4.x the NFS client's statfs
VOP did this already. This can lie about the block size to 4.x binaries,
but it presents a more accurate picture of the ratios of free and
available space.
- For non-block counters, fix the freebsd32 stats converter to cap the
values at INT32_MAX rather than losing the upper 32-bits to match the
behavior of the 4.x statfs conversion routine in vfs_syscalls.c
Approved by: re (kensmith)
Diffstat (limited to 'sys/kern/vfs_syscalls.c')
-rw-r--r-- | sys/kern/vfs_syscalls.c | 50 |
1 files changed, 46 insertions, 4 deletions
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 819a74c..d90e322 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -206,6 +206,47 @@ quotactl(td, uap) } /* + * Used by statfs conversion routines to scale the block size up if + * necessary so that all of the block counts are <= 'max_size'. Note + * that 'max_size' should be a bitmask, i.e. 2^n - 1 for some non-zero + * value of 'n'. + */ +void +statfs_scale_blocks(struct statfs *sf, long max_size) +{ + uint64_t count; + int shift; + + KASSERT(powerof2(max_size + 1), ("%s: invalid max_size", __func__)); + + /* + * Attempt to scale the block counts to give a more accurate + * overview to userland of the ratio of free space to used + * space. To do this, find the largest block count and compute + * a divisor that lets it fit into a signed integer <= max_size. + */ + if (sf->f_bavail < 0) + count = -sf->f_bavail; + else + count = sf->f_bavail; + count = MAX(sf->f_blocks, MAX(sf->f_bfree, count)); + if (count <= max_size) + return; + + count >>= flsl(max_size); + shift = 0; + while (count > 0) { + shift++; + count >>=1; + } + + sf->f_bsize <<= shift; + sf->f_blocks >>= shift; + sf->f_bfree >>= shift; + sf->f_bavail >>= shift; +} + +/* * Get filesystem statistics. */ #ifndef _SYS_SYSPROTO_H_ @@ -636,12 +677,13 @@ cvtstatfs(nsp, osp) struct ostatfs *osp; { + statfs_scale_blocks(nsp, LONG_MAX); bzero(osp, sizeof(*osp)); - osp->f_bsize = MIN(nsp->f_bsize, LONG_MAX); + osp->f_bsize = nsp->f_bsize; osp->f_iosize = MIN(nsp->f_iosize, LONG_MAX); - osp->f_blocks = MIN(nsp->f_blocks, LONG_MAX); - osp->f_bfree = MIN(nsp->f_bfree, LONG_MAX); - osp->f_bavail = MIN(nsp->f_bavail, LONG_MAX); + osp->f_blocks = nsp->f_blocks; + osp->f_bfree = nsp->f_bfree; + osp->f_bavail = nsp->f_bavail; osp->f_files = MIN(nsp->f_files, LONG_MAX); osp->f_ffree = MIN(nsp->f_ffree, LONG_MAX); osp->f_owner = nsp->f_owner; |