aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs/zpl_super.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/zfs/zpl_super.c')
-rw-r--r--module/zfs/zpl_super.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/module/zfs/zpl_super.c b/module/zfs/zpl_super.c
index 5c426b0a9..216c79401 100644
--- a/module/zfs/zpl_super.c
+++ b/module/zfs/zpl_super.c
@@ -181,6 +181,28 @@ zpl_statfs(struct dentry *dentry, struct kstatfs *statp)
spl_fstrans_unmark(cookie);
ASSERT3S(error, <=, 0);
+ /*
+ * If required by a 32-bit system call, dynamically scale the
+ * block size up to 16MiB and decrease the block counts. This
+ * allows for a maximum size of 64EiB to be reported. The file
+ * counts must be artificially capped at 2^32-1.
+ */
+ if (unlikely(zpl_is_32bit_api())) {
+ while (statp->f_blocks > UINT32_MAX &&
+ statp->f_bsize < SPA_MAXBLOCKSIZE) {
+ statp->f_frsize <<= 1;
+ statp->f_bsize <<= 1;
+
+ statp->f_blocks >>= 1;
+ statp->f_bfree >>= 1;
+ statp->f_bavail >>= 1;
+ }
+
+ uint64_t usedobjs = statp->f_files - statp->f_ffree;
+ statp->f_ffree = MIN(statp->f_ffree, UINT32_MAX - usedobjs);
+ statp->f_files = statp->f_ffree + usedobjs;
+ }
+
return (error);
}