diff options
author | Christoph Hellwig <hch@infradead.org> | 2011-12-06 16:58:17 -0500 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2011-12-13 17:46:28 -0500 |
commit | be7ffc38a80a78e6b68d0f51fae8e8d57b55324c (patch) | |
tree | bb5ca49fd1dc92051e9898a653d7bdd26c93af59 /fs/xfs | |
parent | 80a376bfb7f8ff8f1942cb1bdd0052e908918252 (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.c | 67 | ||||
-rw-r--r-- | fs/xfs/xfs_qm.c | 22 | ||||
-rw-r--r-- | fs/xfs/xfs_quota.h | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_trace.h | 2 |
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); | |||
743 | DEFINE_DQUOT_EVENT(xfs_dqread); | 743 | DEFINE_DQUOT_EVENT(xfs_dqread); |
744 | DEFINE_DQUOT_EVENT(xfs_dqread_fail); | 744 | DEFINE_DQUOT_EVENT(xfs_dqread_fail); |
745 | DEFINE_DQUOT_EVENT(xfs_dqlookup_found); | 745 | DEFINE_DQUOT_EVENT(xfs_dqlookup_found); |
746 | DEFINE_DQUOT_EVENT(xfs_dqlookup_want); | ||
747 | DEFINE_DQUOT_EVENT(xfs_dqlookup_freelist); | ||
748 | DEFINE_DQUOT_EVENT(xfs_dqlookup_done); | 746 | DEFINE_DQUOT_EVENT(xfs_dqlookup_done); |
749 | DEFINE_DQUOT_EVENT(xfs_dqget_hit); | 747 | DEFINE_DQUOT_EVENT(xfs_dqget_hit); |
750 | DEFINE_DQUOT_EVENT(xfs_dqget_miss); | 748 | DEFINE_DQUOT_EVENT(xfs_dqget_miss); |