Skip to content

Commit

Permalink
xfs: use a normal shrinker for the dquot freelist
Browse files Browse the repository at this point in the history
Stop reusing dquots from the freelist when allocating new ones directly, and
implement a shrinker that actually follows the specifications for the
interface.  The shrinker implementation is still highly suboptimal at this
point, but we can gradually work on it.

This also fixes an bug in the previous lock ordering, where we would take
the hash and dqlist locks inside of the freelist lock against the normal
lock ordering.  This is only solvable by introducing the dispose list,
and thus not when using direct reclaim of unused dquots for new allocations.

As a side-effect the quota upper bound and used to free ratio values in
/proc/fs/xfs/xqm are set to 0 as these values don't make any sense in the
new world order.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ben Myers <bpm@sgi.com>
  • Loading branch information
Christoph Hellwig authored and Ben Myers committed Feb 10, 2012
1 parent 4505360 commit 04da0c8
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 282 deletions.
6 changes: 0 additions & 6 deletions fs/xfs/kmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,4 @@ kmem_zone_destroy(kmem_zone_t *zone)
extern void *kmem_zone_alloc(kmem_zone_t *, unsigned int __nocast);
extern void *kmem_zone_zalloc(kmem_zone_t *, unsigned int __nocast);

static inline int
kmem_shake_allow(gfp_t gfp_mask)
{
return ((gfp_mask & __GFP_WAIT) && (gfp_mask & __GFP_FS));
}

#endif /* __XFS_SUPPORT_KMEM_H__ */
103 changes: 26 additions & 77 deletions fs/xfs/xfs_dquot.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,82 +62,6 @@ int xfs_dqerror_mod = 33;

static struct lock_class_key xfs_dquot_other_class;

/*
* Allocate and initialize a dquot. We don't always allocate fresh memory;
* we try to reclaim a free dquot if the number of incore dquots are above
* a threshold.
* The only field inside the core that gets initialized at this point
* is the d_id field. The idea is to fill in the entire q_core
* when we read in the on disk dquot.
*/
STATIC xfs_dquot_t *
xfs_qm_dqinit(
xfs_mount_t *mp,
xfs_dqid_t id,
uint type)
{
xfs_dquot_t *dqp;
boolean_t brandnewdquot;

brandnewdquot = xfs_qm_dqalloc_incore(&dqp);
dqp->dq_flags = type;
dqp->q_core.d_id = cpu_to_be32(id);
dqp->q_mount = mp;

/*
* No need to re-initialize these if this is a reclaimed dquot.
*/
if (brandnewdquot) {
INIT_LIST_HEAD(&dqp->q_freelist);
mutex_init(&dqp->q_qlock);
init_waitqueue_head(&dqp->q_pinwait);

/*
* Because we want to use a counting completion, complete
* the flush completion once to allow a single access to
* the flush completion without blocking.
*/
init_completion(&dqp->q_flush);
complete(&dqp->q_flush);

trace_xfs_dqinit(dqp);
} else {
/*
* Only the q_core portion was zeroed in dqreclaim_one().
* So, we need to reset others.
*/
dqp->q_nrefs = 0;
dqp->q_blkno = 0;
INIT_LIST_HEAD(&dqp->q_mplist);
INIT_LIST_HEAD(&dqp->q_hashlist);
dqp->q_bufoffset = 0;
dqp->q_fileoffset = 0;
dqp->q_transp = NULL;
dqp->q_gdquot = NULL;
dqp->q_res_bcount = 0;
dqp->q_res_icount = 0;
dqp->q_res_rtbcount = 0;
atomic_set(&dqp->q_pincount, 0);
dqp->q_hash = NULL;
ASSERT(list_empty(&dqp->q_freelist));

trace_xfs_dqreuse(dqp);
}

/*
* In either case we need to make sure group quotas have a different
* lock class than user quotas, to make sure lockdep knows we can
* locks of one of each at the same time.
*/
if (!(type & XFS_DQ_USER))
lockdep_set_class(&dqp->q_qlock, &xfs_dquot_other_class);

/*
* log item gets initialized later
*/
return (dqp);
}

/*
* This is called to free all the memory associated with a dquot
*/
Expand Down Expand Up @@ -567,7 +491,32 @@ xfs_qm_dqread(
int error;
int cancelflags = 0;

dqp = xfs_qm_dqinit(mp, id, type);

dqp = kmem_zone_zalloc(xfs_Gqm->qm_dqzone, KM_SLEEP);

dqp->dq_flags = type;
dqp->q_core.d_id = cpu_to_be32(id);
dqp->q_mount = mp;
INIT_LIST_HEAD(&dqp->q_freelist);
mutex_init(&dqp->q_qlock);
init_waitqueue_head(&dqp->q_pinwait);

/*
* Because we want to use a counting completion, complete
* the flush completion once to allow a single access to
* the flush completion without blocking.
*/
init_completion(&dqp->q_flush);
complete(&dqp->q_flush);

/*
* Make sure group quotas have a different lock class than user
* quotas.
*/
if (!(type & XFS_DQ_USER))
lockdep_set_class(&dqp->q_qlock, &xfs_dquot_other_class);

atomic_inc(&xfs_Gqm->qm_totaldquots);

trace_xfs_dqread(dqp);

Expand Down
Loading

0 comments on commit 04da0c8

Please sign in to comment.