summaryrefslogtreecommitdiff
path: root/fs/xfs/xfs_dquot.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2025-11-10 14:22:57 +0100
committerCarlos Maiolino <cem@kernel.org>2025-11-11 11:45:57 +0100
commit0c5e80bd579f7bec3704bad6c1f72b13b0d73b53 (patch)
tree51be9ec5f30da3d0229e243bc9b7e79d8f1f122d /fs/xfs/xfs_dquot.c
parent6129b088e1f10938b86f44948ad698b39dd19faa (diff)
xfs: use a lockref for the xfs_dquot reference count
The xfs_dquot structure currently uses the anti-pattern of using the in-object lock that protects the content to also serialize reference count updates for the structure, leading to a cumbersome free path. This is partially papered over by the fact that we never free the dquot directly but always through the LRU. Switch to use a lockref instead and move the reference counter manipulations out of q_qlock. To make this work, xfs_qm_flush_one and xfs_qm_flush_one are converted to acquire a dquot reference while flushing to integrate with the lockref "get if not dead" scheme. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Carlos Maiolino <cem@kernel.org>
Diffstat (limited to 'fs/xfs/xfs_dquot.c')
-rw-r--r--fs/xfs/xfs_dquot.c17
1 files changed, 9 insertions, 8 deletions
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index c2326cee7fae..34c325524ab9 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -816,20 +816,17 @@ restart:
return NULL;
}
- mutex_lock(&dqp->q_qlock);
- if (dqp->q_flags & XFS_DQFLAG_FREEING) {
- mutex_unlock(&dqp->q_qlock);
+ if (!lockref_get_not_dead(&dqp->q_lockref)) {
mutex_unlock(&qi->qi_tree_lock);
trace_xfs_dqget_freeing(dqp);
delay(1);
goto restart;
}
-
- dqp->q_nrefs++;
mutex_unlock(&qi->qi_tree_lock);
trace_xfs_dqget_hit(dqp);
XFS_STATS_INC(mp, xs_qm_dqcachehits);
+ mutex_lock(&dqp->q_qlock);
return dqp;
}
@@ -866,7 +863,7 @@ xfs_qm_dqget_cache_insert(
/* Return a locked dquot to the caller, with a reference taken. */
mutex_lock(&dqp->q_qlock);
- dqp->q_nrefs = 1;
+ lockref_init(&dqp->q_lockref);
qi->qi_dquots++;
out_unlock:
@@ -1124,18 +1121,22 @@ void
xfs_qm_dqput(
struct xfs_dquot *dqp)
{
- ASSERT(dqp->q_nrefs > 0);
ASSERT(XFS_DQ_IS_LOCKED(dqp));
trace_xfs_dqput(dqp);
- if (--dqp->q_nrefs == 0) {
+ if (lockref_put_or_lock(&dqp->q_lockref))
+ goto out_unlock;
+
+ if (!--dqp->q_lockref.count) {
struct xfs_quotainfo *qi = dqp->q_mount->m_quotainfo;
trace_xfs_dqput_free(dqp);
if (list_lru_add_obj(&qi->qi_lru, &dqp->q_lru))
XFS_STATS_INC(dqp->q_mount, xs_qm_dquot_unused);
}
+ spin_unlock(&dqp->q_lockref.lock);
+out_unlock:
mutex_unlock(&dqp->q_qlock);
}