mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	xfs: don't over-report free space or inodes in statvfs
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: <stable@vger.kernel.org> # v2.6.18
Fixes: 932f2c3231 ("[XFS] statvfs component of directory/project quota support, code originally by Glen.")
Reported-by: Emmanuel Florac <eflorac@intellique.com>
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
			
			
This commit is contained in:
		
							parent
							
								
									4bbf9020be
								
							
						
					
					
						commit
						4b8d867ca6
					
				
					 1 changed files with 17 additions and 10 deletions
				
			
		| 
						 | 
				
			
			@ -32,21 +32,28 @@ xfs_fill_statvfs_from_dquot(
 | 
			
		|||
	limit = blkres->softlimit ?
 | 
			
		||||
		blkres->softlimit :
 | 
			
		||||
		blkres->hardlimit;
 | 
			
		||||
	if (limit && statp->f_blocks > limit) {
 | 
			
		||||
		statp->f_blocks = limit;
 | 
			
		||||
		statp->f_bfree = statp->f_bavail =
 | 
			
		||||
			(statp->f_blocks > blkres->reserved) ?
 | 
			
		||||
			 (statp->f_blocks - blkres->reserved) : 0;
 | 
			
		||||
	if (limit) {
 | 
			
		||||
		uint64_t	remaining = 0;
 | 
			
		||||
 | 
			
		||||
		if (limit > blkres->reserved)
 | 
			
		||||
			remaining = limit - blkres->reserved;
 | 
			
		||||
 | 
			
		||||
		statp->f_blocks = min(statp->f_blocks, limit);
 | 
			
		||||
		statp->f_bfree = min(statp->f_bfree, remaining);
 | 
			
		||||
		statp->f_bavail = min(statp->f_bavail, remaining);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	limit = dqp->q_ino.softlimit ?
 | 
			
		||||
		dqp->q_ino.softlimit :
 | 
			
		||||
		dqp->q_ino.hardlimit;
 | 
			
		||||
	if (limit && statp->f_files > limit) {
 | 
			
		||||
		statp->f_files = limit;
 | 
			
		||||
		statp->f_ffree =
 | 
			
		||||
			(statp->f_files > dqp->q_ino.reserved) ?
 | 
			
		||||
			 (statp->f_files - dqp->q_ino.reserved) : 0;
 | 
			
		||||
	if (limit) {
 | 
			
		||||
		uint64_t	remaining = 0;
 | 
			
		||||
 | 
			
		||||
		if (limit > dqp->q_ino.reserved)
 | 
			
		||||
			remaining = limit - dqp->q_ino.reserved;
 | 
			
		||||
 | 
			
		||||
		statp->f_files = min(statp->f_files, limit);
 | 
			
		||||
		statp->f_ffree = min(statp->f_ffree, remaining);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue