aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2011-12-06 16:58:17 -0500
committerBen Myers <bpm@sgi.com>2011-12-13 17:46:28 -0500
commitbe7ffc38a80a78e6b68d0f51fae8e8d57b55324c (patch)
treebb5ca49fd1dc92051e9898a653d7bdd26c93af59 /fs/xfs
parent80a376bfb7f8ff8f1942cb1bdd0052e908918252 (diff)
xfs: implement lazy removal for the dquot freelist
Do not remove dquots from the freelist when we grab a reference to them in xfs_qm_dqlookup, but leave them on the freelist util scanning notices that they have a reference. This speeds up the lookup fastpath, and greatly simplifies the lock ordering constraints. Note that the same scheme is used by the VFS inode and dentry caches. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_dquot.c67
-rw-r--r--fs/xfs/xfs_qm.c22
-rw-r--r--fs/xfs/xfs_quota.h4
-rw-r--r--fs/xfs/xfs_trace.h2
4 files changed, 30 insertions, 65 deletions
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 3f94f2428a35..35d2b8aad0f9 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -722,58 +722,25 @@ xfs_qm_dqlookup(
722 * dqlock to look at the id field of the dquot, since the 722 * dqlock to look at the id field of the dquot, since the
723 * id can't be modified without the hashlock anyway. 723 * id can't be modified without the hashlock anyway.
724 */ 724 */
725 if (be32_to_cpu(dqp->q_core.d_id) == id && dqp->q_mount == mp) { 725 if (be32_to_cpu(dqp->q_core.d_id) != id || dqp->q_mount != mp)
726 trace_xfs_dqlookup_found(dqp); 726 continue;
727 727
728 /* 728 trace_xfs_dqlookup_found(dqp);
729 * All in core dquots must be on the dqlist of mp
730 */
731 ASSERT(!list_empty(&dqp->q_mplist));
732
733 xfs_dqlock(dqp);
734 if (dqp->q_nrefs == 0) {
735 ASSERT(!list_empty(&dqp->q_freelist));
736 if (!mutex_trylock(&xfs_Gqm->qm_dqfrlist_lock)) {
737 trace_xfs_dqlookup_want(dqp);
738
739 /*
740 * We may have raced with dqreclaim_one()
741 * (and lost). So, flag that we don't
742 * want the dquot to be reclaimed.
743 */
744 dqp->dq_flags |= XFS_DQ_WANT;
745 xfs_dqunlock(dqp);
746 mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
747 xfs_dqlock(dqp);
748 dqp->dq_flags &= ~(XFS_DQ_WANT);
749 }
750
751 if (dqp->q_nrefs == 0) {
752 /* take it off the freelist */
753 trace_xfs_dqlookup_freelist(dqp);
754 list_del_init(&dqp->q_freelist);
755 xfs_Gqm->qm_dqfrlist_cnt--;
756 }
757 XFS_DQHOLD(dqp);
758 mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
759 } else {
760 XFS_DQHOLD(dqp);
761 }
762 729
763 /* 730 xfs_dqlock(dqp);
764 * move the dquot to the front of the hashchain 731 XFS_DQHOLD(dqp);
765 */ 732
766 ASSERT(mutex_is_locked(&qh->qh_lock)); 733 /*
767 list_move(&dqp->q_hashlist, &qh->qh_list); 734 * move the dquot to the front of the hashchain
768 trace_xfs_dqlookup_done(dqp); 735 */
769 *O_dqpp = dqp; 736 list_move(&dqp->q_hashlist, &qh->qh_list);
770 return 0; 737 trace_xfs_dqlookup_done(dqp);
771 } 738 *O_dqpp = dqp;
739 return 0;
772 } 740 }
773 741
774 *O_dqpp = NULL; 742 *O_dqpp = NULL;
775 ASSERT(mutex_is_locked(&qh->qh_lock)); 743 return 1;
776 return (1);
777} 744}
778 745
779/* 746/*
@@ -1033,8 +1000,10 @@ xfs_qm_dqput(
1033 if (--dqp->q_nrefs == 0) { 1000 if (--dqp->q_nrefs == 0) {
1034 trace_xfs_dqput_free(dqp); 1001 trace_xfs_dqput_free(dqp);
1035 1002
1036 list_add_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist); 1003 if (list_empty(&dqp->q_freelist)) {
1037 xfs_Gqm->qm_dqfrlist_cnt++; 1004 list_add_tail(&dqp->q_freelist, &xfs_Gqm->qm_dqfrlist);
1005 xfs_Gqm->qm_dqfrlist_cnt++;
1006 }
1038 1007
1039 /* 1008 /*
1040 * If we just added a udquot to the freelist, then 1009 * If we just added a udquot to the freelist, then
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index be1df6839237..6a0c4f0d9306 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -517,13 +517,12 @@ xfs_qm_dqpurge_int(
517 * get them off mplist and hashlist, but leave them on freelist. 517 * get them off mplist and hashlist, but leave them on freelist.
518 */ 518 */
519 list_for_each_entry_safe(dqp, n, &q->qi_dqlist, q_mplist) { 519 list_for_each_entry_safe(dqp, n, &q->qi_dqlist, q_mplist) {
520 /* 520 xfs_dqlock(dqp);
521 * It's OK to look at the type without taking dqlock here. 521 if ((dqp->dq_flags & dqtype) == 0) {
522 * We're holding the mplist lock here, and that's needed for 522 xfs_dqunlock(dqp);
523 * a dqreclaim.
524 */
525 if ((dqp->dq_flags & dqtype) == 0)
526 continue; 523 continue;
524 }
525 xfs_dqunlock(dqp);
527 526
528 if (!mutex_trylock(&dqp->q_hash->qh_lock)) { 527 if (!mutex_trylock(&dqp->q_hash->qh_lock)) {
529 nrecl = q->qi_dqreclaims; 528 nrecl = q->qi_dqreclaims;
@@ -1692,14 +1691,15 @@ again:
1692 xfs_dqlock(dqp); 1691 xfs_dqlock(dqp);
1693 1692
1694 /* 1693 /*
1695 * We are racing with dqlookup here. Naturally we don't 1694 * This dquot has already been grabbed by dqlookup.
1696 * want to reclaim a dquot that lookup wants. We release the 1695 * Remove it from the freelist and try again.
1697 * freelist lock and start over, so that lookup will grab
1698 * both the dquot and the freelistlock.
1699 */ 1696 */
1700 if (dqp->dq_flags & XFS_DQ_WANT) { 1697 if (dqp->q_nrefs) {
1701 trace_xfs_dqreclaim_want(dqp); 1698 trace_xfs_dqreclaim_want(dqp);
1702 XQM_STATS_INC(xqmstats.xs_qm_dqwants); 1699 XQM_STATS_INC(xqmstats.xs_qm_dqwants);
1700
1701 list_del_init(&dqp->q_freelist);
1702 xfs_Gqm->qm_dqfrlist_cnt--;
1703 restarts++; 1703 restarts++;
1704 startagain = 1; 1704 startagain = 1;
1705 goto dqunlock; 1705 goto dqunlock;
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
index cbafdee8b98a..487653ddbef0 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -87,7 +87,6 @@ typedef struct xfs_dqblk {
87#define XFS_DQ_PROJ 0x0002 /* project quota */ 87#define XFS_DQ_PROJ 0x0002 /* project quota */
88#define XFS_DQ_GROUP 0x0004 /* a group quota */ 88#define XFS_DQ_GROUP 0x0004 /* a group quota */
89#define XFS_DQ_DIRTY 0x0008 /* dquot is dirty */ 89#define XFS_DQ_DIRTY 0x0008 /* dquot is dirty */
90#define XFS_DQ_WANT 0x0010 /* for lookup/reclaim race */
91 90
92#define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP) 91#define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
93 92
@@ -95,8 +94,7 @@ typedef struct xfs_dqblk {
95 { XFS_DQ_USER, "USER" }, \ 94 { XFS_DQ_USER, "USER" }, \
96 { XFS_DQ_PROJ, "PROJ" }, \ 95 { XFS_DQ_PROJ, "PROJ" }, \
97 { XFS_DQ_GROUP, "GROUP" }, \ 96 { XFS_DQ_GROUP, "GROUP" }, \
98 { XFS_DQ_DIRTY, "DIRTY" }, \ 97 { XFS_DQ_DIRTY, "DIRTY" }
99 { XFS_DQ_WANT, "WANT" }
100 98
101/* 99/*
102 * In the worst case, when both user and group quotas are on, 100 * In the worst case, when both user and group quotas are on,
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 494035798873..a9d5b1e06efe 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -743,8 +743,6 @@ DEFINE_DQUOT_EVENT(xfs_dqtobp_read);
743DEFINE_DQUOT_EVENT(xfs_dqread); 743DEFINE_DQUOT_EVENT(xfs_dqread);
744DEFINE_DQUOT_EVENT(xfs_dqread_fail); 744DEFINE_DQUOT_EVENT(xfs_dqread_fail);
745DEFINE_DQUOT_EVENT(xfs_dqlookup_found); 745DEFINE_DQUOT_EVENT(xfs_dqlookup_found);
746DEFINE_DQUOT_EVENT(xfs_dqlookup_want);
747DEFINE_DQUOT_EVENT(xfs_dqlookup_freelist);
748DEFINE_DQUOT_EVENT(xfs_dqlookup_done); 746DEFINE_DQUOT_EVENT(xfs_dqlookup_done);
749DEFINE_DQUOT_EVENT(xfs_dqget_hit); 747DEFINE_DQUOT_EVENT(xfs_dqget_hit);
750DEFINE_DQUOT_EVENT(xfs_dqget_miss); 748DEFINE_DQUOT_EVENT(xfs_dqget_miss);