summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2007-08-28 20:28:12 +0000
committerjhb <jhb@FreeBSD.org>2007-08-28 20:28:12 +0000
commit736eaf5ce3efb9100c867e89a189456aaf2cfb94 (patch)
tree6c90a59f892dc8f1d97e9a4c9dbc5d141cf5adfa /sys/kern
parent5b26984cf1dd44727a7b2c2a6c0cfcf737b5efee (diff)
downloadFreeBSD-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')
-rw-r--r--sys/kern/vfs_syscalls.c50
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;
OpenPOWER on IntegriCloud