Commit dd324cb79e54 ("xfs: refactor xfs_fs_statfs") made xfs_statfs_data() limit f_bfree with max(0LL, ...) instead of max_t(int64_t, 0, ...). However, the value is an unsigned difference, so max() never picks 0. As of now, when the free block counter is below the count of unavailable blocks, statfs() reports f_bfree and f_bavail close to 2^64 instead of 0, and df prints negative sizes. A similar issue happened before and was fixed by commit 237aac4624aa ("xfs: ensure f_bfree returned by statfs() is non-negative"). Perhaps the refactored code needs that fix as well. The issue can be reproduced on a new 2 GiB filesystem mounted on /mnt: for i in $(seq 3000); do head -c 65536 /dev/zero > /mnt/s$i; done dd if=/dev/zero of=/mnt/big bs=1M xfs_io -x -c 'resblks 100000000' /mnt for i in $(seq 1 2 3000); do rm /mnt/s$i; done sync df -h /mnt Before commit dd324cb79e54 ("xfs: refactor xfs_fs_statfs"), the result is: Filesystem Size Used Avail Use% Mounted on /dev/vda 2.0G 2.0G 0 100% /mnt After that commit, the result is: Filesystem Size Used Avail Use% Mounted on /dev/vda 2.0G -64Z -24K 100% /mnt This patch will compare the difference as a signed value again. Fixes: dd324cb79e54 ("xfs: refactor xfs_fs_statfs") Cc: stable@vger.kernel.org # v6.14 Signed-off-by: Hengyu Liang --- The resblks ioctl only keeps the reproducer short. The same values show up after filling a filesystem, writing with O_DIRECT into preallocated space and deleting files. Application impact (Ubuntu 26.04 user space, XFS root in that state): on v6.13, "apt install" stops with "You don't have enough free space in /var/cache/apt/archives/". On v6.14, it prints "18.4 EB available", starts the download and fails with ENOSPC. GNOME's "Low Disk Space" notification is sent on v6.13 and not on v6.14. Tested on xfs for-next: with this patch, df, apt and the notification behave as on v6.13. fs/xfs/xfs_super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 5a06132aa384..42be6bd34d43 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -916,7 +916,7 @@ xfs_statfs_data( xfs_sum_freecounter(mp, XC_FREE_BLOCKS); /* make sure st->f_bfree does not underflow */ - st->f_bfree = max(0LL, + st->f_bfree = max_t(int64_t, 0, fdblocks - xfs_freecounter_unavailable(mp, XC_FREE_BLOCKS)); /* base-commit: 48326a2382d80715475d10ce98734ac65d2d2150 -- 2.53.0