summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2020-07-14 10:36:09 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-08-26 10:40:55 +0200
commit711f5688bb97966c20eca91ea17ab303e48c93e4 (patch)
tree49020b4084cb64521ec932dc45b9e5691647911a
parent8fe5e38acbe71f93551dc0b84d6750cd21caaaad (diff)
downloadlinux-stable-711f5688bb97966c20eca91ea17ab303e48c93e4.tar.gz
linux-stable-711f5688bb97966c20eca91ea17ab303e48c93e4.tar.bz2
linux-stable-711f5688bb97966c20eca91ea17ab303e48c93e4.zip
xfs: fix inode quota reservation checks
[ Upstream commit f959b5d037e71a4d69b5bf71faffa065d9269b4a ] xfs_trans_dqresv is the function that we use to make reservations against resource quotas. Each resource contains two counters: the q_core counter, which tracks resources allocated on disk; and the dquot reservation counter, which tracks how much of that resource has either been allocated or reserved by threads that are working on metadata updates. For disk blocks, we compare the proposed reservation counter against the hard and soft limits to decide if we're going to fail the operation. However, for inodes we inexplicably compare against the q_core counter, not the incore reservation count. Since the q_core counter is always lower than the reservation count and we unlock the dquot between reservation and transaction commit, this means that multiple threads can reserve the last inode count before we hit the hard limit, and when they commit, we'll be well over the hard limit. Fix this by checking against the incore inode reservation counter, since we would appear to maintain that correctly (and that's what we report in GETQUOTA). Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Allison Collins <allison.henderson@oracle.com> Reviewed-by: Chandan Babu R <chandanrlinux@gmail.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--fs/xfs/xfs_trans_dquot.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index 16457465833b..904780dd74aa 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -646,7 +646,7 @@ xfs_trans_dqresv(
}
}
if (ninos > 0) {
- total_count = be64_to_cpu(dqp->q_core.d_icount) + ninos;
+ total_count = dqp->q_res_icount + ninos;
timer = be32_to_cpu(dqp->q_core.d_itimer);
warns = be16_to_cpu(dqp->q_core.d_iwarns);
warnlimit = dqp->q_mount->m_quotainfo->qi_iwarnlimit;