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/xfs_qm.c | |
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/xfs_qm.c')
-rw-r--r-- | fs/xfs/xfs_qm.c | 95 |
1 files changed, 8 insertions, 87 deletions
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 | /* |