diff options
author | Christoph Hellwig <hch@infradead.org> | 2012-03-13 04:52:35 -0400 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2012-03-14 12:09:06 -0400 |
commit | 9f920f116426806bfa34c1422742e1bf7b7a2b4b (patch) | |
tree | 3ec0a4f006dc10ed56e5bec1b605f5ecbb3a3275 /fs/xfs | |
parent | f8739c3ce2ac9a01515b56026b6a066c0808234b (diff) |
xfs: use per-filesystem radix trees for dquot lookup
Replace the global hash tables for looking up in-memory dquot structures
with per-filesystem radix trees to allow scaling to a large number of
in-memory dquot structures.
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/xfs_dquot.c | 188 | ||||
-rw-r--r-- | fs/xfs/xfs_dquot.h | 12 | ||||
-rw-r--r-- | fs/xfs/xfs_qm.c | 95 | ||||
-rw-r--r-- | fs/xfs/xfs_qm.h | 19 | ||||
-rw-r--r-- | fs/xfs/xfs_quota_priv.h | 11 | ||||
-rw-r--r-- | fs/xfs/xfs_trace.h | 4 |
6 files changed, 66 insertions, 263 deletions
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c index fec1a3d78e9f..49456e555cfa 100644 --- a/fs/xfs/xfs_dquot.c +++ b/fs/xfs/xfs_dquot.c | |||
@@ -43,7 +43,7 @@ | |||
43 | * Lock order: | 43 | * Lock order: |
44 | * | 44 | * |
45 | * ip->i_lock | 45 | * ip->i_lock |
46 | * qh->qh_lock | 46 | * qi->qi_tree_lock |
47 | * qi->qi_dqlist_lock | 47 | * qi->qi_dqlist_lock |
48 | * dquot->q_qlock (xfs_dqlock() and friends) | 48 | * dquot->q_qlock (xfs_dqlock() and friends) |
49 | * dquot->q_flush (xfs_dqflock() and friends) | 49 | * dquot->q_flush (xfs_dqflock() and friends) |
@@ -602,60 +602,6 @@ error0: | |||
602 | } | 602 | } |
603 | 603 | ||
604 | /* | 604 | /* |
605 | * Lookup a dquot in the incore dquot hashtable. We keep two separate | ||
606 | * hashtables for user and group dquots; and, these are global tables | ||
607 | * inside the XQM, not per-filesystem tables. | ||
608 | * The hash chain must be locked by caller, and it is left locked | ||
609 | * on return. Returning dquot is locked. | ||
610 | */ | ||
611 | STATIC int | ||
612 | xfs_qm_dqlookup( | ||
613 | xfs_mount_t *mp, | ||
614 | xfs_dqid_t id, | ||
615 | xfs_dqhash_t *qh, | ||
616 | xfs_dquot_t **O_dqpp) | ||
617 | { | ||
618 | xfs_dquot_t *dqp; | ||
619 | |||
620 | ASSERT(mutex_is_locked(&qh->qh_lock)); | ||
621 | |||
622 | /* | ||
623 | * Traverse the hashchain looking for a match | ||
624 | */ | ||
625 | list_for_each_entry(dqp, &qh->qh_list, q_hashlist) { | ||
626 | /* | ||
627 | * We already have the hashlock. We don't need the | ||
628 | * dqlock to look at the id field of the dquot, since the | ||
629 | * id can't be modified without the hashlock anyway. | ||
630 | */ | ||
631 | if (be32_to_cpu(dqp->q_core.d_id) != id || dqp->q_mount != mp) | ||
632 | continue; | ||
633 | |||
634 | trace_xfs_dqlookup_found(dqp); | ||
635 | |||
636 | xfs_dqlock(dqp); | ||
637 | if (dqp->dq_flags & XFS_DQ_FREEING) { | ||
638 | *O_dqpp = NULL; | ||
639 | xfs_dqunlock(dqp); | ||
640 | return -1; | ||
641 | } | ||
642 | |||
643 | dqp->q_nrefs++; | ||
644 | |||
645 | /* | ||
646 | * move the dquot to the front of the hashchain | ||
647 | */ | ||
648 | list_move(&dqp->q_hashlist, &qh->qh_list); | ||
649 | trace_xfs_dqlookup_done(dqp); | ||
650 | *O_dqpp = dqp; | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | *O_dqpp = NULL; | ||
655 | return 1; | ||
656 | } | ||
657 | |||
658 | /* | ||
659 | * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a | 605 | * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a |
660 | * a locked dquot, doing an allocation (if requested) as needed. | 606 | * a locked dquot, doing an allocation (if requested) as needed. |
661 | * When both an inode and an id are given, the inode's id takes precedence. | 607 | * When both an inode and an id are given, the inode's id takes precedence. |
@@ -672,10 +618,10 @@ xfs_qm_dqget( | |||
672 | uint flags, /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */ | 618 | uint flags, /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */ |
673 | xfs_dquot_t **O_dqpp) /* OUT : locked incore dquot */ | 619 | xfs_dquot_t **O_dqpp) /* OUT : locked incore dquot */ |
674 | { | 620 | { |
675 | xfs_dquot_t *dqp, *dqp1; | 621 | struct xfs_quotainfo *qi = mp->m_quotainfo; |
676 | xfs_dqhash_t *h; | 622 | struct radix_tree_root *tree = XFS_DQUOT_TREE(qi, type); |
677 | uint version; | 623 | struct xfs_dquot *dqp; |
678 | int error; | 624 | int error; |
679 | 625 | ||
680 | ASSERT(XFS_IS_QUOTA_RUNNING(mp)); | 626 | ASSERT(XFS_IS_QUOTA_RUNNING(mp)); |
681 | if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) || | 627 | if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) || |
@@ -683,7 +629,6 @@ xfs_qm_dqget( | |||
683 | (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) { | 629 | (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) { |
684 | return (ESRCH); | 630 | return (ESRCH); |
685 | } | 631 | } |
686 | h = XFS_DQ_HASH(mp, id, type); | ||
687 | 632 | ||
688 | #ifdef DEBUG | 633 | #ifdef DEBUG |
689 | if (xfs_do_dqerror) { | 634 | if (xfs_do_dqerror) { |
@@ -704,34 +649,28 @@ xfs_qm_dqget( | |||
704 | #endif | 649 | #endif |
705 | 650 | ||
706 | restart: | 651 | restart: |
707 | mutex_lock(&h->qh_lock); | 652 | mutex_lock(&qi->qi_tree_lock); |
653 | dqp = radix_tree_lookup(tree, id); | ||
654 | if (dqp) { | ||
655 | xfs_dqlock(dqp); | ||
656 | if (dqp->dq_flags & XFS_DQ_FREEING) { | ||
657 | xfs_dqunlock(dqp); | ||
658 | mutex_unlock(&qi->qi_tree_lock); | ||
659 | trace_xfs_dqget_freeing(dqp); | ||
660 | delay(1); | ||
661 | goto restart; | ||
662 | } | ||
708 | 663 | ||
709 | /* | 664 | dqp->q_nrefs++; |
710 | * Look in the cache (hashtable). | 665 | mutex_unlock(&qi->qi_tree_lock); |
711 | * The chain is kept locked during lookup. | 666 | |
712 | */ | 667 | trace_xfs_dqget_hit(dqp); |
713 | switch (xfs_qm_dqlookup(mp, id, h, O_dqpp)) { | ||
714 | case -1: | ||
715 | XFS_STATS_INC(xs_qm_dquot_dups); | ||
716 | mutex_unlock(&h->qh_lock); | ||
717 | delay(1); | ||
718 | goto restart; | ||
719 | case 0: | ||
720 | XFS_STATS_INC(xs_qm_dqcachehits); | 668 | XFS_STATS_INC(xs_qm_dqcachehits); |
721 | /* | 669 | *O_dqpp = dqp; |
722 | * The dquot was found, moved to the front of the chain, | 670 | return 0; |
723 | * taken off the freelist if it was on it, and locked | ||
724 | * at this point. Just unlock the hashchain and return. | ||
725 | */ | ||
726 | ASSERT(*O_dqpp); | ||
727 | ASSERT(XFS_DQ_IS_LOCKED(*O_dqpp)); | ||
728 | mutex_unlock(&h->qh_lock); | ||
729 | trace_xfs_dqget_hit(*O_dqpp); | ||
730 | return 0; /* success */ | ||
731 | default: | ||
732 | XFS_STATS_INC(xs_qm_dqcachemisses); | ||
733 | break; | ||
734 | } | 671 | } |
672 | mutex_unlock(&qi->qi_tree_lock); | ||
673 | XFS_STATS_INC(xs_qm_dqcachemisses); | ||
735 | 674 | ||
736 | /* | 675 | /* |
737 | * Dquot cache miss. We don't want to keep the inode lock across | 676 | * Dquot cache miss. We don't want to keep the inode lock across |
@@ -742,12 +681,6 @@ restart: | |||
742 | */ | 681 | */ |
743 | if (ip) | 682 | if (ip) |
744 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 683 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
745 | /* | ||
746 | * Save the hashchain version stamp, and unlock the chain, so that | ||
747 | * we don't keep the lock across a disk read | ||
748 | */ | ||
749 | version = h->qh_version; | ||
750 | mutex_unlock(&h->qh_lock); | ||
751 | 684 | ||
752 | error = xfs_qm_dqread(mp, id, type, flags, &dqp); | 685 | error = xfs_qm_dqread(mp, id, type, flags, &dqp); |
753 | 686 | ||
@@ -757,15 +690,14 @@ restart: | |||
757 | if (error) | 690 | if (error) |
758 | return error; | 691 | return error; |
759 | 692 | ||
760 | /* | ||
761 | * Dquot lock comes after hashlock in the lock ordering | ||
762 | */ | ||
763 | if (ip) { | 693 | if (ip) { |
764 | /* | 694 | /* |
765 | * A dquot could be attached to this inode by now, since | 695 | * A dquot could be attached to this inode by now, since |
766 | * we had dropped the ilock. | 696 | * we had dropped the ilock. |
767 | */ | 697 | */ |
768 | if (xfs_this_quota_on(mp, type)) { | 698 | if (xfs_this_quota_on(mp, type)) { |
699 | struct xfs_dquot *dqp1; | ||
700 | |||
769 | dqp1 = xfs_inode_dquot(ip, type); | 701 | dqp1 = xfs_inode_dquot(ip, type); |
770 | if (dqp1) { | 702 | if (dqp1) { |
771 | xfs_qm_dqdestroy(dqp); | 703 | xfs_qm_dqdestroy(dqp); |
@@ -780,51 +712,27 @@ restart: | |||
780 | } | 712 | } |
781 | } | 713 | } |
782 | 714 | ||
783 | /* | 715 | mutex_lock(&qi->qi_tree_lock); |
784 | * Hashlock comes after ilock in lock order | 716 | error = -radix_tree_insert(tree, id, dqp); |
785 | */ | 717 | if (unlikely(error)) { |
786 | mutex_lock(&h->qh_lock); | 718 | WARN_ON(error != EEXIST); |
787 | if (version != h->qh_version) { | 719 | |
788 | xfs_dquot_t *tmpdqp; | ||
789 | /* | 720 | /* |
790 | * Now, see if somebody else put the dquot in the | 721 | * Duplicate found. Just throw away the new dquot and start |
791 | * hashtable before us. This can happen because we didn't | 722 | * over. |
792 | * keep the hashchain lock. We don't have to worry about | ||
793 | * lock order between the two dquots here since dqp isn't | ||
794 | * on any findable lists yet. | ||
795 | */ | 723 | */ |
796 | switch (xfs_qm_dqlookup(mp, id, h, &tmpdqp)) { | 724 | mutex_unlock(&qi->qi_tree_lock); |
797 | case 0: | 725 | trace_xfs_dqget_dup(dqp); |
798 | case -1: | 726 | xfs_qm_dqdestroy(dqp); |
799 | /* | 727 | XFS_STATS_INC(xs_qm_dquot_dups); |
800 | * Duplicate found, either in cache or on its way out. | 728 | goto restart; |
801 | * Just throw away the new dquot and start over. | ||
802 | */ | ||
803 | if (tmpdqp) | ||
804 | xfs_qm_dqput(tmpdqp); | ||
805 | mutex_unlock(&h->qh_lock); | ||
806 | xfs_qm_dqdestroy(dqp); | ||
807 | XFS_STATS_INC(xs_qm_dquot_dups); | ||
808 | goto restart; | ||
809 | default: | ||
810 | break; | ||
811 | } | ||
812 | } | 729 | } |
813 | 730 | ||
814 | /* | 731 | /* |
815 | * Put the dquot at the beginning of the hash-chain and mp's list | ||
816 | * LOCK ORDER: hashlock, freelistlock, mplistlock, udqlock, gdqlock .. | ||
817 | */ | ||
818 | ASSERT(mutex_is_locked(&h->qh_lock)); | ||
819 | dqp->q_hash = h; | ||
820 | list_add(&dqp->q_hashlist, &h->qh_list); | ||
821 | h->qh_version++; | ||
822 | |||
823 | /* | ||
824 | * Attach this dquot to this filesystem's list of all dquots, | 732 | * Attach this dquot to this filesystem's list of all dquots, |
825 | * kept inside the mount structure in m_quotainfo field | 733 | * kept inside the mount structure in m_quotainfo field |
826 | */ | 734 | */ |
827 | mutex_lock(&mp->m_quotainfo->qi_dqlist_lock); | 735 | mutex_lock(&qi->qi_dqlist_lock); |
828 | 736 | ||
829 | /* | 737 | /* |
830 | * We return a locked dquot to the caller, with a reference taken | 738 | * We return a locked dquot to the caller, with a reference taken |
@@ -832,10 +740,11 @@ restart: | |||
832 | xfs_dqlock(dqp); | 740 | xfs_dqlock(dqp); |
833 | dqp->q_nrefs = 1; | 741 | dqp->q_nrefs = 1; |
834 | 742 | ||
835 | list_add(&dqp->q_mplist, &mp->m_quotainfo->qi_dqlist); | 743 | list_add(&dqp->q_mplist, &qi->qi_dqlist); |
836 | mp->m_quotainfo->qi_dquots++; | 744 | qi->qi_dquots++; |
837 | mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock); | 745 | mutex_unlock(&qi->qi_dqlist_lock); |
838 | mutex_unlock(&h->qh_lock); | 746 | mutex_unlock(&qi->qi_tree_lock); |
747 | |||
839 | dqret: | 748 | dqret: |
840 | ASSERT((ip == NULL) || xfs_isilocked(ip, XFS_ILOCK_EXCL)); | 749 | ASSERT((ip == NULL) || xfs_isilocked(ip, XFS_ILOCK_EXCL)); |
841 | trace_xfs_dqget_miss(dqp); | 750 | trace_xfs_dqget_miss(dqp); |
@@ -1117,7 +1026,6 @@ xfs_qm_dqpurge( | |||
1117 | struct xfs_dquot *dqp) | 1026 | struct xfs_dquot *dqp) |
1118 | { | 1027 | { |
1119 | struct xfs_mount *mp = dqp->q_mount; | 1028 | struct xfs_mount *mp = dqp->q_mount; |
1120 | struct xfs_dqhash *qh = dqp->q_hash; | ||
1121 | struct xfs_quotainfo *qi = mp->m_quotainfo; | 1029 | struct xfs_quotainfo *qi = mp->m_quotainfo; |
1122 | 1030 | ||
1123 | xfs_dqlock(dqp); | 1031 | xfs_dqlock(dqp); |
@@ -1164,10 +1072,10 @@ xfs_qm_dqpurge( | |||
1164 | xfs_dqfunlock(dqp); | 1072 | xfs_dqfunlock(dqp); |
1165 | xfs_dqunlock(dqp); | 1073 | xfs_dqunlock(dqp); |
1166 | 1074 | ||
1167 | mutex_lock(&qh->qh_lock); | 1075 | mutex_lock(&qi->qi_tree_lock); |
1168 | list_del_init(&dqp->q_hashlist); | 1076 | radix_tree_delete(XFS_DQUOT_TREE(qi, dqp->q_core.d_flags), |
1169 | qh->qh_version++; | 1077 | be32_to_cpu(dqp->q_core.d_id)); |
1170 | mutex_unlock(&qh->qh_lock); | 1078 | mutex_unlock(&qi->qi_tree_lock); |
1171 | 1079 | ||
1172 | mutex_lock(&qi->qi_dqlist_lock); | 1080 | mutex_lock(&qi->qi_dqlist_lock); |
1173 | list_del_init(&dqp->q_mplist); | 1081 | list_del_init(&dqp->q_mplist); |
diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h index f291c25e5992..4061f1731271 100644 --- a/fs/xfs/xfs_dquot.h +++ b/fs/xfs/xfs_dquot.h | |||
@@ -29,16 +29,6 @@ | |||
29 | * when quotas are off. | 29 | * when quotas are off. |
30 | */ | 30 | */ |
31 | 31 | ||
32 | /* | ||
33 | * The hash chain headers (hash buckets) | ||
34 | */ | ||
35 | typedef struct xfs_dqhash { | ||
36 | struct list_head qh_list; | ||
37 | struct mutex qh_lock; | ||
38 | uint qh_version; /* ever increasing version */ | ||
39 | uint qh_nelems; /* number of dquots on the list */ | ||
40 | } xfs_dqhash_t; | ||
41 | |||
42 | struct xfs_mount; | 32 | struct xfs_mount; |
43 | struct xfs_trans; | 33 | struct xfs_trans; |
44 | 34 | ||
@@ -49,8 +39,6 @@ typedef struct xfs_dquot { | |||
49 | uint dq_flags; /* various flags (XFS_DQ_*) */ | 39 | uint dq_flags; /* various flags (XFS_DQ_*) */ |
50 | struct list_head q_lru; /* global free list of dquots */ | 40 | struct list_head q_lru; /* global free list of dquots */ |
51 | struct list_head q_mplist; /* mount's list of dquots */ | 41 | struct list_head q_mplist; /* mount's list of dquots */ |
52 | struct list_head q_hashlist; /* gloabl hash list of dquots */ | ||
53 | xfs_dqhash_t *q_hash; /* the hashchain header */ | ||
54 | struct xfs_mount*q_mount; /* filesystem this relates to */ | 42 | struct xfs_mount*q_mount; /* filesystem this relates to */ |
55 | struct xfs_trans*q_transp; /* trans this belongs to currently */ | 43 | struct xfs_trans*q_transp; /* trans this belongs to currently */ |
56 | uint q_nrefs; /* # active refs from inodes */ | 44 | uint q_nrefs; /* # active refs from inodes */ |
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index a2579e1d687f..bb884e701cd9 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c | |||
@@ -54,9 +54,6 @@ struct xfs_qm *xfs_Gqm; | |||
54 | kmem_zone_t *qm_dqzone; | 54 | kmem_zone_t *qm_dqzone; |
55 | kmem_zone_t *qm_dqtrxzone; | 55 | kmem_zone_t *qm_dqtrxzone; |
56 | 56 | ||
57 | STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int); | ||
58 | STATIC void xfs_qm_list_destroy(xfs_dqlist_t *); | ||
59 | |||
60 | STATIC int xfs_qm_init_quotainos(xfs_mount_t *); | 57 | STATIC int xfs_qm_init_quotainos(xfs_mount_t *); |
61 | STATIC int xfs_qm_init_quotainfo(xfs_mount_t *); | 58 | STATIC int xfs_qm_init_quotainfo(xfs_mount_t *); |
62 | STATIC int xfs_qm_shake(struct shrinker *, struct shrink_control *); | 59 | STATIC int xfs_qm_shake(struct shrinker *, struct shrink_control *); |
@@ -68,37 +65,9 @@ STATIC int xfs_qm_shake(struct shrinker *, struct shrink_control *); | |||
68 | STATIC struct xfs_qm * | 65 | STATIC struct xfs_qm * |
69 | xfs_Gqm_init(void) | 66 | xfs_Gqm_init(void) |
70 | { | 67 | { |
71 | xfs_dqhash_t *udqhash, *gdqhash; | ||
72 | xfs_qm_t *xqm; | 68 | xfs_qm_t *xqm; |
73 | size_t hsize; | ||
74 | uint i; | ||
75 | |||
76 | /* | ||
77 | * Initialize the dquot hash tables. | ||
78 | */ | ||
79 | udqhash = kmem_zalloc_greedy(&hsize, | ||
80 | XFS_QM_HASHSIZE_LOW * sizeof(xfs_dqhash_t), | ||
81 | XFS_QM_HASHSIZE_HIGH * sizeof(xfs_dqhash_t)); | ||
82 | if (!udqhash) | ||
83 | goto out; | ||
84 | |||
85 | gdqhash = kmem_zalloc_large(hsize); | ||
86 | if (!gdqhash) | ||
87 | goto out_free_udqhash; | ||
88 | |||
89 | hsize /= sizeof(xfs_dqhash_t); | ||
90 | 69 | ||
91 | xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP); | 70 | xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP); |
92 | xqm->qm_dqhashmask = hsize - 1; | ||
93 | xqm->qm_usr_dqhtable = udqhash; | ||
94 | xqm->qm_grp_dqhtable = gdqhash; | ||
95 | ASSERT(xqm->qm_usr_dqhtable != NULL); | ||
96 | ASSERT(xqm->qm_grp_dqhtable != NULL); | ||
97 | |||
98 | for (i = 0; i < hsize; i++) { | ||
99 | xfs_qm_list_init(&(xqm->qm_usr_dqhtable[i]), "uxdqh", i); | ||
100 | xfs_qm_list_init(&(xqm->qm_grp_dqhtable[i]), "gxdqh", i); | ||
101 | } | ||
102 | 71 | ||
103 | /* | 72 | /* |
104 | * dquot zone. we register our own low-memory callback. | 73 | * dquot zone. we register our own low-memory callback. |
@@ -122,11 +91,6 @@ xfs_Gqm_init(void) | |||
122 | 91 | ||
123 | xqm->qm_nrefs = 0; | 92 | xqm->qm_nrefs = 0; |
124 | return xqm; | 93 | return xqm; |
125 | |||
126 | out_free_udqhash: | ||
127 | kmem_free_large(udqhash); | ||
128 | out: | ||
129 | return NULL; | ||
130 | } | 94 | } |
131 | 95 | ||
132 | /* | 96 | /* |
@@ -136,22 +100,9 @@ STATIC void | |||
136 | xfs_qm_destroy( | 100 | xfs_qm_destroy( |
137 | struct xfs_qm *xqm) | 101 | struct xfs_qm *xqm) |
138 | { | 102 | { |
139 | int hsize, i; | ||
140 | |||
141 | ASSERT(xqm != NULL); | 103 | ASSERT(xqm != NULL); |
142 | ASSERT(xqm->qm_nrefs == 0); | 104 | ASSERT(xqm->qm_nrefs == 0); |
143 | 105 | ||
144 | hsize = xqm->qm_dqhashmask + 1; | ||
145 | for (i = 0; i < hsize; i++) { | ||
146 | xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i])); | ||
147 | xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i])); | ||
148 | } | ||
149 | kmem_free_large(xqm->qm_usr_dqhtable); | ||
150 | kmem_free_large(xqm->qm_grp_dqhtable); | ||
151 | xqm->qm_usr_dqhtable = NULL; | ||
152 | xqm->qm_grp_dqhtable = NULL; | ||
153 | xqm->qm_dqhashmask = 0; | ||
154 | |||
155 | kmem_free(xqm); | 106 | kmem_free(xqm); |
156 | } | 107 | } |
157 | 108 | ||
@@ -762,14 +713,6 @@ xfs_qm_dqdetach( | |||
762 | } | 713 | } |
763 | 714 | ||
764 | /* | 715 | /* |
765 | * The hash chains and the mplist use the same xfs_dqhash structure as | ||
766 | * their list head, but we can take the mplist qh_lock and one of the | ||
767 | * hash qh_locks at the same time without any problem as they aren't | ||
768 | * related. | ||
769 | */ | ||
770 | static struct lock_class_key xfs_quota_mplist_class; | ||
771 | |||
772 | /* | ||
773 | * This initializes all the quota information that's kept in the | 716 | * This initializes all the quota information that's kept in the |
774 | * mount structure | 717 | * mount structure |
775 | */ | 718 | */ |
@@ -802,9 +745,12 @@ xfs_qm_init_quotainfo( | |||
802 | return error; | 745 | return error; |
803 | } | 746 | } |
804 | 747 | ||
748 | INIT_RADIX_TREE(&qinf->qi_uquota_tree, GFP_NOFS); | ||
749 | INIT_RADIX_TREE(&qinf->qi_gquota_tree, GFP_NOFS); | ||
750 | mutex_init(&qinf->qi_tree_lock); | ||
751 | |||
805 | INIT_LIST_HEAD(&qinf->qi_dqlist); | 752 | INIT_LIST_HEAD(&qinf->qi_dqlist); |
806 | mutex_init(&qinf->qi_dqlist_lock); | 753 | mutex_init(&qinf->qi_dqlist_lock); |
807 | lockdep_set_class(&qinf->qi_dqlist_lock, &xfs_quota_mplist_class); | ||
808 | 754 | ||
809 | INIT_LIST_HEAD(&qinf->qi_lru_list); | 755 | INIT_LIST_HEAD(&qinf->qi_lru_list); |
810 | qinf->qi_lru_count = 0; | 756 | qinf->qi_lru_count = 0; |
@@ -924,30 +870,6 @@ xfs_qm_destroy_quotainfo( | |||
924 | mp->m_quotainfo = NULL; | 870 | mp->m_quotainfo = NULL; |
925 | } | 871 | } |
926 | 872 | ||
927 | |||
928 | |||
929 | /* ------------------- PRIVATE STATIC FUNCTIONS ----------------------- */ | ||
930 | |||
931 | /* ARGSUSED */ | ||
932 | STATIC void | ||
933 | xfs_qm_list_init( | ||
934 | xfs_dqlist_t *list, | ||
935 | char *str, | ||
936 | int n) | ||
937 | { | ||
938 | mutex_init(&list->qh_lock); | ||
939 | INIT_LIST_HEAD(&list->qh_list); | ||
940 | list->qh_version = 0; | ||
941 | list->qh_nelems = 0; | ||
942 | } | ||
943 | |||
944 | STATIC void | ||
945 | xfs_qm_list_destroy( | ||
946 | xfs_dqlist_t *list) | ||
947 | { | ||
948 | mutex_destroy(&(list->qh_lock)); | ||
949 | } | ||
950 | |||
951 | /* | 873 | /* |
952 | * Create an inode and return with a reference already taken, but unlocked | 874 | * Create an inode and return with a reference already taken, but unlocked |
953 | * This is how we create quota inodes | 875 | * This is how we create quota inodes |
@@ -1592,10 +1514,10 @@ xfs_qm_dqfree_one( | |||
1592 | struct xfs_mount *mp = dqp->q_mount; | 1514 | struct xfs_mount *mp = dqp->q_mount; |
1593 | struct xfs_quotainfo *qi = mp->m_quotainfo; | 1515 | struct xfs_quotainfo *qi = mp->m_quotainfo; |
1594 | 1516 | ||
1595 | mutex_lock(&dqp->q_hash->qh_lock); | 1517 | mutex_lock(&qi->qi_tree_lock); |
1596 | list_del_init(&dqp->q_hashlist); | 1518 | radix_tree_delete(XFS_DQUOT_TREE(qi, dqp->q_core.d_flags), |
1597 | dqp->q_hash->qh_version++; | 1519 | be32_to_cpu(dqp->q_core.d_id)); |
1598 | mutex_unlock(&dqp->q_hash->qh_lock); | 1520 | mutex_unlock(&qi->qi_tree_lock); |
1599 | 1521 | ||
1600 | mutex_lock(&qi->qi_dqlist_lock); | 1522 | mutex_lock(&qi->qi_dqlist_lock); |
1601 | list_del_init(&dqp->q_mplist); | 1523 | list_del_init(&dqp->q_mplist); |
@@ -1634,7 +1556,6 @@ xfs_qm_dqreclaim_one( | |||
1634 | return; | 1556 | return; |
1635 | } | 1557 | } |
1636 | 1558 | ||
1637 | ASSERT(dqp->q_hash); | ||
1638 | ASSERT(!list_empty(&dqp->q_mplist)); | 1559 | ASSERT(!list_empty(&dqp->q_mplist)); |
1639 | 1560 | ||
1640 | /* | 1561 | /* |
diff --git a/fs/xfs/xfs_qm.h b/fs/xfs/xfs_qm.h index c236bba9bfab..8f4b117823cc 100644 --- a/fs/xfs/xfs_qm.h +++ b/fs/xfs/xfs_qm.h | |||
@@ -31,12 +31,6 @@ extern kmem_zone_t *qm_dqzone; | |||
31 | extern kmem_zone_t *qm_dqtrxzone; | 31 | extern kmem_zone_t *qm_dqtrxzone; |
32 | 32 | ||
33 | /* | 33 | /* |
34 | * Dquot hashtable constants/threshold values. | ||
35 | */ | ||
36 | #define XFS_QM_HASHSIZE_LOW (PAGE_SIZE / sizeof(xfs_dqhash_t)) | ||
37 | #define XFS_QM_HASHSIZE_HIGH ((PAGE_SIZE * 4) / sizeof(xfs_dqhash_t)) | ||
38 | |||
39 | /* | ||
40 | * This defines the unit of allocation of dquots. | 34 | * This defines the unit of allocation of dquots. |
41 | * Currently, it is just one file system block, and a 4K blk contains 30 | 35 | * Currently, it is just one file system block, and a 4K blk contains 30 |
42 | * (136 * 30 = 4080) dquots. It's probably not worth trying to make | 36 | * (136 * 30 = 4080) dquots. It's probably not worth trying to make |
@@ -47,15 +41,10 @@ extern kmem_zone_t *qm_dqtrxzone; | |||
47 | */ | 41 | */ |
48 | #define XFS_DQUOT_CLUSTER_SIZE_FSB (xfs_filblks_t)1 | 42 | #define XFS_DQUOT_CLUSTER_SIZE_FSB (xfs_filblks_t)1 |
49 | 43 | ||
50 | typedef xfs_dqhash_t xfs_dqlist_t; | ||
51 | |||
52 | /* | 44 | /* |
53 | * Quota Manager (global) structure. Lives only in core. | 45 | * Quota Manager (global) structure. Lives only in core. |
54 | */ | 46 | */ |
55 | typedef struct xfs_qm { | 47 | typedef struct xfs_qm { |
56 | xfs_dqlist_t *qm_usr_dqhtable;/* udquot hash table */ | ||
57 | xfs_dqlist_t *qm_grp_dqhtable;/* gdquot hash table */ | ||
58 | uint qm_dqhashmask; /* # buckets in dq hashtab - 1 */ | ||
59 | uint qm_nrefs; /* file systems with quota on */ | 48 | uint qm_nrefs; /* file systems with quota on */ |
60 | kmem_zone_t *qm_dqzone; /* dquot mem-alloc zone */ | 49 | kmem_zone_t *qm_dqzone; /* dquot mem-alloc zone */ |
61 | kmem_zone_t *qm_dqtrxzone; /* t_dqinfo of transactions */ | 50 | kmem_zone_t *qm_dqtrxzone; /* t_dqinfo of transactions */ |
@@ -66,6 +55,9 @@ typedef struct xfs_qm { | |||
66 | * The mount structure keeps a pointer to this. | 55 | * The mount structure keeps a pointer to this. |
67 | */ | 56 | */ |
68 | typedef struct xfs_quotainfo { | 57 | typedef struct xfs_quotainfo { |
58 | struct radix_tree_root qi_uquota_tree; | ||
59 | struct radix_tree_root qi_gquota_tree; | ||
60 | struct mutex qi_tree_lock; | ||
69 | xfs_inode_t *qi_uquotaip; /* user quota inode */ | 61 | xfs_inode_t *qi_uquotaip; /* user quota inode */ |
70 | xfs_inode_t *qi_gquotaip; /* group quota inode */ | 62 | xfs_inode_t *qi_gquotaip; /* group quota inode */ |
71 | struct list_head qi_lru_list; | 63 | struct list_head qi_lru_list; |
@@ -94,6 +86,11 @@ typedef struct xfs_quotainfo { | |||
94 | struct shrinker qi_shrinker; | 86 | struct shrinker qi_shrinker; |
95 | } xfs_quotainfo_t; | 87 | } xfs_quotainfo_t; |
96 | 88 | ||
89 | #define XFS_DQUOT_TREE(qi, type) \ | ||
90 | ((type & XFS_DQ_USER) ? \ | ||
91 | &((qi)->qi_uquota_tree) : \ | ||
92 | &((qi)->qi_gquota_tree)) | ||
93 | |||
97 | 94 | ||
98 | extern void xfs_trans_mod_dquot(xfs_trans_t *, xfs_dquot_t *, uint, long); | 95 | extern void xfs_trans_mod_dquot(xfs_trans_t *, xfs_dquot_t *, uint, long); |
99 | extern int xfs_trans_reserve_quota_bydquots(xfs_trans_t *, xfs_mount_t *, | 96 | extern int xfs_trans_reserve_quota_bydquots(xfs_trans_t *, xfs_mount_t *, |
diff --git a/fs/xfs/xfs_quota_priv.h b/fs/xfs/xfs_quota_priv.h index 94a3d927d716..6d86219d93da 100644 --- a/fs/xfs/xfs_quota_priv.h +++ b/fs/xfs/xfs_quota_priv.h | |||
@@ -24,17 +24,6 @@ | |||
24 | */ | 24 | */ |
25 | #define XFS_DQITER_MAP_SIZE 10 | 25 | #define XFS_DQITER_MAP_SIZE 10 |
26 | 26 | ||
27 | /* | ||
28 | * Hash into a bucket in the dquot hash table, based on <mp, id>. | ||
29 | */ | ||
30 | #define XFS_DQ_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \ | ||
31 | (__psunsigned_t)(id)) & \ | ||
32 | (xfs_Gqm->qm_dqhashmask - 1)) | ||
33 | #define XFS_DQ_HASH(mp, id, type) (type == XFS_DQ_USER ? \ | ||
34 | (xfs_Gqm->qm_usr_dqhtable + \ | ||
35 | XFS_DQ_HASHVAL(mp, id)) : \ | ||
36 | (xfs_Gqm->qm_grp_dqhtable + \ | ||
37 | XFS_DQ_HASHVAL(mp, id))) | ||
38 | #define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \ | 27 | #define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \ |
39 | !dqp->q_core.d_blk_hardlimit && \ | 28 | !dqp->q_core.d_blk_hardlimit && \ |
40 | !dqp->q_core.d_blk_softlimit && \ | 29 | !dqp->q_core.d_blk_softlimit && \ |
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index ceaf6fe67e41..75eb54af4d58 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h | |||
@@ -741,10 +741,10 @@ DEFINE_DQUOT_EVENT(xfs_dqalloc); | |||
741 | DEFINE_DQUOT_EVENT(xfs_dqtobp_read); | 741 | DEFINE_DQUOT_EVENT(xfs_dqtobp_read); |
742 | DEFINE_DQUOT_EVENT(xfs_dqread); | 742 | DEFINE_DQUOT_EVENT(xfs_dqread); |
743 | DEFINE_DQUOT_EVENT(xfs_dqread_fail); | 743 | DEFINE_DQUOT_EVENT(xfs_dqread_fail); |
744 | DEFINE_DQUOT_EVENT(xfs_dqlookup_found); | ||
745 | DEFINE_DQUOT_EVENT(xfs_dqlookup_done); | ||
746 | DEFINE_DQUOT_EVENT(xfs_dqget_hit); | 744 | DEFINE_DQUOT_EVENT(xfs_dqget_hit); |
747 | DEFINE_DQUOT_EVENT(xfs_dqget_miss); | 745 | DEFINE_DQUOT_EVENT(xfs_dqget_miss); |
746 | DEFINE_DQUOT_EVENT(xfs_dqget_freeing); | ||
747 | DEFINE_DQUOT_EVENT(xfs_dqget_dup); | ||
748 | DEFINE_DQUOT_EVENT(xfs_dqput); | 748 | DEFINE_DQUOT_EVENT(xfs_dqput); |
749 | DEFINE_DQUOT_EVENT(xfs_dqput_wait); | 749 | DEFINE_DQUOT_EVENT(xfs_dqput_wait); |
750 | DEFINE_DQUOT_EVENT(xfs_dqput_free); | 750 | DEFINE_DQUOT_EVENT(xfs_dqput_free); |