diff options
author | Theodore Ts'o <tytso@mit.edu> | 2025-03-14 07:38:42 +0300 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2025-03-20 22:31:19 +0300 |
commit | f87d3af7419307ae26e705a2b2db36140db367a2 (patch) | |
tree | e316cddca42a89295324ff3a15faabe3513120f7 | |
parent | 5f1cf94d80208f5baa203f10fa762d3f0b567ad8 (diff) | |
download | linux-f87d3af7419307ae26e705a2b2db36140db367a2.tar.xz |
ext4: don't over-report free space or inodes in statvfs
This fixes an analogus bug that was fixed in xfs in commit
4b8d867ca6e2 ("xfs: don't over-report free space or inodes in
statvfs") where statfs can report misleading / incorrect information
where project quota is enabled, and the free space is less than the
remaining quota.
This commit will resolve a test failure in generic/762 which tests for
this bug.
Cc: stable@kernel.org
Fixes: 689c958cbe6b ("ext4: add project quota support")
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
-rw-r--r-- | fs/ext4/super.c | 27 |
1 files changed, 17 insertions, 10 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 4768770715ca..8cafcd3e9f5f 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -6820,22 +6820,29 @@ static int ext4_statfs_project(struct super_block *sb, dquot->dq_dqb.dqb_bhardlimit); limit >>= sb->s_blocksize_bits; - if (limit && buf->f_blocks > limit) { + if (limit) { + uint64_t remaining = 0; + curblock = (dquot->dq_dqb.dqb_curspace + dquot->dq_dqb.dqb_rsvspace) >> sb->s_blocksize_bits; - buf->f_blocks = limit; - buf->f_bfree = buf->f_bavail = - (buf->f_blocks > curblock) ? - (buf->f_blocks - curblock) : 0; + if (limit > curblock) + remaining = limit - curblock; + + buf->f_blocks = min(buf->f_blocks, limit); + buf->f_bfree = min(buf->f_bfree, remaining); + buf->f_bavail = min(buf->f_bavail, remaining); } limit = min_not_zero(dquot->dq_dqb.dqb_isoftlimit, dquot->dq_dqb.dqb_ihardlimit); - if (limit && buf->f_files > limit) { - buf->f_files = limit; - buf->f_ffree = - (buf->f_files > dquot->dq_dqb.dqb_curinodes) ? - (buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0; + if (limit) { + uint64_t remaining = 0; + + if (limit > dquot->dq_dqb.dqb_curinodes) + remaining = limit - dquot->dq_dqb.dqb_curinodes; + + buf->f_files = min(buf->f_files, limit); + buf->f_ffree = min(buf->f_ffree, remaining); } spin_unlock(&dquot->dq_dqb_lock); |