xfs: remove XFS_DQ_INACTIVE
Free dquots when purging them during umount instead of keeping them around on the freelist in a degraded state. The out of order locking in xfs_qm_dqpurge will be removed again later in this series. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Ben Myers <bpm@sgi.com>
This commit is contained in:
parent
497507b9ee
commit
80a376bfb7
3 changed files with 25 additions and 70 deletions
|
@ -1302,6 +1302,14 @@ xfs_qm_dqpurge(
|
||||||
ASSERT(mutex_is_locked(&mp->m_quotainfo->qi_dqlist_lock));
|
ASSERT(mutex_is_locked(&mp->m_quotainfo->qi_dqlist_lock));
|
||||||
ASSERT(mutex_is_locked(&dqp->q_hash->qh_lock));
|
ASSERT(mutex_is_locked(&dqp->q_hash->qh_lock));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX(hch): horrible locking order, will get cleaned up ASAP.
|
||||||
|
*/
|
||||||
|
if (!mutex_trylock(&xfs_Gqm->qm_dqfrlist_lock)) {
|
||||||
|
mutex_unlock(&dqp->q_hash->qh_lock);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
xfs_dqlock(dqp);
|
xfs_dqlock(dqp);
|
||||||
/*
|
/*
|
||||||
* We really can't afford to purge a dquot that is
|
* We really can't afford to purge a dquot that is
|
||||||
|
@ -1364,25 +1372,23 @@ xfs_qm_dqpurge(
|
||||||
|
|
||||||
list_del_init(&dqp->q_hashlist);
|
list_del_init(&dqp->q_hashlist);
|
||||||
qh->qh_version++;
|
qh->qh_version++;
|
||||||
|
|
||||||
list_del_init(&dqp->q_mplist);
|
list_del_init(&dqp->q_mplist);
|
||||||
mp->m_quotainfo->qi_dqreclaims++;
|
mp->m_quotainfo->qi_dqreclaims++;
|
||||||
mp->m_quotainfo->qi_dquots--;
|
mp->m_quotainfo->qi_dquots--;
|
||||||
/*
|
|
||||||
* XXX Move this to the front of the freelist, if we can get the
|
|
||||||
* freelist lock.
|
|
||||||
*/
|
|
||||||
ASSERT(!list_empty(&dqp->q_freelist));
|
|
||||||
|
|
||||||
dqp->q_mount = NULL;
|
list_del_init(&dqp->q_freelist);
|
||||||
dqp->q_hash = NULL;
|
xfs_Gqm->qm_dqfrlist_cnt--;
|
||||||
dqp->dq_flags = XFS_DQ_INACTIVE;
|
|
||||||
memset(&dqp->q_core, 0, sizeof(dqp->q_core));
|
|
||||||
xfs_dqfunlock(dqp);
|
xfs_dqfunlock(dqp);
|
||||||
xfs_dqunlock(dqp);
|
xfs_dqunlock(dqp);
|
||||||
mutex_unlock(&qh->qh_lock);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
|
||||||
|
mutex_unlock(&qh->qh_lock);
|
||||||
|
|
||||||
|
xfs_qm_dqdestroy(dqp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Give the buffer a little push if it is incore and
|
* Give the buffer a little push if it is incore and
|
||||||
|
|
|
@ -154,12 +154,17 @@ STATIC void
|
||||||
xfs_qm_destroy(
|
xfs_qm_destroy(
|
||||||
struct xfs_qm *xqm)
|
struct xfs_qm *xqm)
|
||||||
{
|
{
|
||||||
struct xfs_dquot *dqp, *n;
|
|
||||||
int hsize, i;
|
int hsize, i;
|
||||||
|
|
||||||
ASSERT(xqm != NULL);
|
ASSERT(xqm != NULL);
|
||||||
ASSERT(xqm->qm_nrefs == 0);
|
ASSERT(xqm->qm_nrefs == 0);
|
||||||
|
|
||||||
unregister_shrinker(&xfs_qm_shaker);
|
unregister_shrinker(&xfs_qm_shaker);
|
||||||
|
|
||||||
|
mutex_lock(&xqm->qm_dqfrlist_lock);
|
||||||
|
ASSERT(list_empty(&xqm->qm_dqfrlist));
|
||||||
|
mutex_unlock(&xqm->qm_dqfrlist_lock);
|
||||||
|
|
||||||
hsize = xqm->qm_dqhashmask + 1;
|
hsize = xqm->qm_dqhashmask + 1;
|
||||||
for (i = 0; i < hsize; i++) {
|
for (i = 0; i < hsize; i++) {
|
||||||
xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
|
xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
|
||||||
|
@ -171,17 +176,6 @@ xfs_qm_destroy(
|
||||||
xqm->qm_grp_dqhtable = NULL;
|
xqm->qm_grp_dqhtable = NULL;
|
||||||
xqm->qm_dqhashmask = 0;
|
xqm->qm_dqhashmask = 0;
|
||||||
|
|
||||||
/* frlist cleanup */
|
|
||||||
mutex_lock(&xqm->qm_dqfrlist_lock);
|
|
||||||
list_for_each_entry_safe(dqp, n, &xqm->qm_dqfrlist, q_freelist) {
|
|
||||||
xfs_dqlock(dqp);
|
|
||||||
list_del_init(&dqp->q_freelist);
|
|
||||||
xfs_Gqm->qm_dqfrlist_cnt--;
|
|
||||||
xfs_dqunlock(dqp);
|
|
||||||
xfs_qm_dqdestroy(dqp);
|
|
||||||
}
|
|
||||||
mutex_unlock(&xqm->qm_dqfrlist_lock);
|
|
||||||
mutex_destroy(&xqm->qm_dqfrlist_lock);
|
|
||||||
kmem_free(xqm);
|
kmem_free(xqm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,33 +226,9 @@ STATIC void
|
||||||
xfs_qm_rele_quotafs_ref(
|
xfs_qm_rele_quotafs_ref(
|
||||||
struct xfs_mount *mp)
|
struct xfs_mount *mp)
|
||||||
{
|
{
|
||||||
xfs_dquot_t *dqp, *n;
|
|
||||||
|
|
||||||
ASSERT(xfs_Gqm);
|
ASSERT(xfs_Gqm);
|
||||||
ASSERT(xfs_Gqm->qm_nrefs > 0);
|
ASSERT(xfs_Gqm->qm_nrefs > 0);
|
||||||
|
|
||||||
/*
|
|
||||||
* Go thru the freelist and destroy all inactive dquots.
|
|
||||||
*/
|
|
||||||
mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
|
|
||||||
|
|
||||||
list_for_each_entry_safe(dqp, n, &xfs_Gqm->qm_dqfrlist, q_freelist) {
|
|
||||||
xfs_dqlock(dqp);
|
|
||||||
if (dqp->dq_flags & XFS_DQ_INACTIVE) {
|
|
||||||
ASSERT(dqp->q_mount == NULL);
|
|
||||||
ASSERT(! XFS_DQ_IS_DIRTY(dqp));
|
|
||||||
ASSERT(list_empty(&dqp->q_hashlist));
|
|
||||||
ASSERT(list_empty(&dqp->q_mplist));
|
|
||||||
list_del_init(&dqp->q_freelist);
|
|
||||||
xfs_Gqm->qm_dqfrlist_cnt--;
|
|
||||||
xfs_dqunlock(dqp);
|
|
||||||
xfs_qm_dqdestroy(dqp);
|
|
||||||
} else {
|
|
||||||
xfs_dqunlock(dqp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Destroy the entire XQM. If somebody mounts with quotaon, this'll
|
* Destroy the entire XQM. If somebody mounts with quotaon, this'll
|
||||||
* be restarted.
|
* be restarted.
|
||||||
|
@ -1728,8 +1698,6 @@ again:
|
||||||
* both the dquot and the freelistlock.
|
* both the dquot and the freelistlock.
|
||||||
*/
|
*/
|
||||||
if (dqp->dq_flags & XFS_DQ_WANT) {
|
if (dqp->dq_flags & XFS_DQ_WANT) {
|
||||||
ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE));
|
|
||||||
|
|
||||||
trace_xfs_dqreclaim_want(dqp);
|
trace_xfs_dqreclaim_want(dqp);
|
||||||
XQM_STATS_INC(xqmstats.xs_qm_dqwants);
|
XQM_STATS_INC(xqmstats.xs_qm_dqwants);
|
||||||
restarts++;
|
restarts++;
|
||||||
|
@ -1737,23 +1705,6 @@ again:
|
||||||
goto dqunlock;
|
goto dqunlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If the dquot is inactive, we are assured that it is
|
|
||||||
* not on the mplist or the hashlist, and that makes our
|
|
||||||
* life easier.
|
|
||||||
*/
|
|
||||||
if (dqp->dq_flags & XFS_DQ_INACTIVE) {
|
|
||||||
ASSERT(mp == NULL);
|
|
||||||
ASSERT(! XFS_DQ_IS_DIRTY(dqp));
|
|
||||||
ASSERT(list_empty(&dqp->q_hashlist));
|
|
||||||
ASSERT(list_empty(&dqp->q_mplist));
|
|
||||||
list_del_init(&dqp->q_freelist);
|
|
||||||
xfs_Gqm->qm_dqfrlist_cnt--;
|
|
||||||
dqpout = dqp;
|
|
||||||
XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);
|
|
||||||
goto dqunlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(dqp->q_hash);
|
ASSERT(dqp->q_hash);
|
||||||
ASSERT(!list_empty(&dqp->q_mplist));
|
ASSERT(!list_empty(&dqp->q_mplist));
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,6 @@ typedef struct xfs_dqblk {
|
||||||
#define XFS_DQ_GROUP 0x0004 /* a group quota */
|
#define XFS_DQ_GROUP 0x0004 /* a group quota */
|
||||||
#define XFS_DQ_DIRTY 0x0008 /* dquot is dirty */
|
#define XFS_DQ_DIRTY 0x0008 /* dquot is dirty */
|
||||||
#define XFS_DQ_WANT 0x0010 /* for lookup/reclaim race */
|
#define XFS_DQ_WANT 0x0010 /* for lookup/reclaim race */
|
||||||
#define XFS_DQ_INACTIVE 0x0020 /* dq off mplist & hashlist */
|
|
||||||
|
|
||||||
#define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
|
#define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
|
||||||
|
|
||||||
|
@ -97,8 +96,7 @@ typedef struct xfs_dqblk {
|
||||||
{ XFS_DQ_PROJ, "PROJ" }, \
|
{ XFS_DQ_PROJ, "PROJ" }, \
|
||||||
{ XFS_DQ_GROUP, "GROUP" }, \
|
{ XFS_DQ_GROUP, "GROUP" }, \
|
||||||
{ XFS_DQ_DIRTY, "DIRTY" }, \
|
{ XFS_DQ_DIRTY, "DIRTY" }, \
|
||||||
{ XFS_DQ_WANT, "WANT" }, \
|
{ XFS_DQ_WANT, "WANT" }
|
||||||
{ XFS_DQ_INACTIVE, "INACTIVE" }
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In the worst case, when both user and group quotas are on,
|
* In the worst case, when both user and group quotas are on,
|
||||||
|
|
Loading…
Add table
Reference in a new issue