Skip to content

Commit 2aec967

Browse files
Darrick J. Wonggregkh
authored andcommitted
xfs: don't over-report free space or inodes in statvfs
commit 4b8d867 upstream. Emmanual Florac reports a strange occurrence when project quota limits are enabled, free space is lower than the remaining quota, and someone runs statvfs: # mkfs.xfs -f /dev/sda # mount /dev/sda /mnt -o prjquota # xfs_quota -x -c 'limit -p bhard=2G 55' /mnt # mkdir /mnt/dir # xfs_io -c 'chproj 55' -c 'chattr +P' -c 'stat -vvvv' /mnt/dir # fallocate -l 19g /mnt/a # df /mnt /mnt/dir Filesystem Size Used Avail Use% Mounted on /dev/sda 20G 20G 345M 99% /mnt /dev/sda 2.0G 0 2.0G 0% /mnt I think the bug here is that xfs_fill_statvfs_from_dquot unconditionally assigns to f_bfree without checking that the filesystem has enough free space to fill the remaining project quota. However, this is a longstanding behavior of xfs so it's unclear what to do here. Cc: <[email protected]> # v2.6.18 Fixes: 932f2c3 ("[XFS] statvfs component of directory/project quota support, code originally by Glen.") Reported-by: Emmanuel Florac <[email protected]> Signed-off-by: "Darrick J. Wong" <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent a721800 commit 2aec967

File tree

1 file changed

+17
-10
lines changed

1 file changed

+17
-10
lines changed

fs/xfs/xfs_qm_bhv.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,28 @@ xfs_fill_statvfs_from_dquot(
3232
limit = blkres->softlimit ?
3333
blkres->softlimit :
3434
blkres->hardlimit;
35-
if (limit && statp->f_blocks > limit) {
36-
statp->f_blocks = limit;
37-
statp->f_bfree = statp->f_bavail =
38-
(statp->f_blocks > blkres->reserved) ?
39-
(statp->f_blocks - blkres->reserved) : 0;
35+
if (limit) {
36+
uint64_t remaining = 0;
37+
38+
if (limit > blkres->reserved)
39+
remaining = limit - blkres->reserved;
40+
41+
statp->f_blocks = min(statp->f_blocks, limit);
42+
statp->f_bfree = min(statp->f_bfree, remaining);
43+
statp->f_bavail = min(statp->f_bavail, remaining);
4044
}
4145

4246
limit = dqp->q_ino.softlimit ?
4347
dqp->q_ino.softlimit :
4448
dqp->q_ino.hardlimit;
45-
if (limit && statp->f_files > limit) {
46-
statp->f_files = limit;
47-
statp->f_ffree =
48-
(statp->f_files > dqp->q_ino.reserved) ?
49-
(statp->f_files - dqp->q_ino.reserved) : 0;
49+
if (limit) {
50+
uint64_t remaining = 0;
51+
52+
if (limit > dqp->q_ino.reserved)
53+
remaining = limit - dqp->q_ino.reserved;
54+
55+
statp->f_files = min(statp->f_files, limit);
56+
statp->f_ffree = min(statp->f_ffree, remaining);
5057
}
5158
}
5259

0 commit comments

Comments
 (0)