aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorHeinz Mauelshagen <heinzm@redhat.com>2014-06-05 10:23:09 -0400
committerMike Snitzer <snitzer@redhat.com>2014-06-11 16:48:54 -0400
commitadcc44472bacb227ebc0b1a8876efa5302474338 (patch)
tree594f3024476830cb98887266b282307cc960dd3d /drivers/md
parent11f0431be2f99c574a65c6dfc0ca205511500f29 (diff)
dm bio prison: implement per bucket locking in the dm_bio_prison hash table
Split the single per bio-prison lock by using per bucket locking. Per bucket locking benefits both dm-thin and dm-cache targets by reducing bio-prison lock contention. Signed-off-by: Heinz Mauelshagen <heinzm@redhat.com> Signed-off-by: Joe Thornber <ejt@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/dm-bio-prison.c66
1 files changed, 39 insertions, 27 deletions
diff --git a/drivers/md/dm-bio-prison.c b/drivers/md/dm-bio-prison.c
index 71434382cb64..f752d12081ff 100644
--- a/drivers/md/dm-bio-prison.c
+++ b/drivers/md/dm-bio-prison.c
@@ -14,13 +14,17 @@
14 14
15/*----------------------------------------------------------------*/ 15/*----------------------------------------------------------------*/
16 16
17struct dm_bio_prison { 17struct bucket {
18 spinlock_t lock; 18 spinlock_t lock;
19 struct hlist_head cells;
20};
21
22struct dm_bio_prison {
19 mempool_t *cell_pool; 23 mempool_t *cell_pool;
20 24
21 unsigned nr_buckets; 25 unsigned nr_buckets;
22 unsigned hash_mask; 26 unsigned hash_mask;
23 struct hlist_head *cells; 27 struct bucket *buckets;
24}; 28};
25 29
26/*----------------------------------------------------------------*/ 30/*----------------------------------------------------------------*/
@@ -40,6 +44,12 @@ static uint32_t calc_nr_buckets(unsigned nr_cells)
40 44
41static struct kmem_cache *_cell_cache; 45static struct kmem_cache *_cell_cache;
42 46
47static void init_bucket(struct bucket *b)
48{
49 spin_lock_init(&b->lock);
50 INIT_HLIST_HEAD(&b->cells);
51}
52
43/* 53/*
44 * @nr_cells should be the number of cells you want in use _concurrently_. 54 * @nr_cells should be the number of cells you want in use _concurrently_.
45 * Don't confuse it with the number of distinct keys. 55 * Don't confuse it with the number of distinct keys.
@@ -49,13 +59,12 @@ struct dm_bio_prison *dm_bio_prison_create(unsigned nr_cells)
49 unsigned i; 59 unsigned i;
50 uint32_t nr_buckets = calc_nr_buckets(nr_cells); 60 uint32_t nr_buckets = calc_nr_buckets(nr_cells);
51 size_t len = sizeof(struct dm_bio_prison) + 61 size_t len = sizeof(struct dm_bio_prison) +
52 (sizeof(struct hlist_head) * nr_buckets); 62 (sizeof(struct bucket) * nr_buckets);
53 struct dm_bio_prison *prison = kmalloc(len, GFP_KERNEL); 63 struct dm_bio_prison *prison = kmalloc(len, GFP_KERNEL);
54 64
55 if (!prison) 65 if (!prison)
56 return NULL; 66 return NULL;
57 67
58 spin_lock_init(&prison->lock);
59 prison->cell_pool = mempool_create_slab_pool(nr_cells, _cell_cache); 68 prison->cell_pool = mempool_create_slab_pool(nr_cells, _cell_cache);
60 if (!prison->cell_pool) { 69 if (!prison->cell_pool) {
61 kfree(prison); 70 kfree(prison);
@@ -64,9 +73,9 @@ struct dm_bio_prison *dm_bio_prison_create(unsigned nr_cells)
64 73
65 prison->nr_buckets = nr_buckets; 74 prison->nr_buckets = nr_buckets;
66 prison->hash_mask = nr_buckets - 1; 75 prison->hash_mask = nr_buckets - 1;
67 prison->cells = (struct hlist_head *) (prison + 1); 76 prison->buckets = (struct bucket *) (prison + 1);
68 for (i = 0; i < nr_buckets; i++) 77 for (i = 0; i < nr_buckets; i++)
69 INIT_HLIST_HEAD(prison->cells + i); 78 init_bucket(prison->buckets + i);
70 79
71 return prison; 80 return prison;
72} 81}
@@ -107,40 +116,44 @@ static int keys_equal(struct dm_cell_key *lhs, struct dm_cell_key *rhs)
107 (lhs->block == rhs->block); 116 (lhs->block == rhs->block);
108} 117}
109 118
110static struct dm_bio_prison_cell *__search_bucket(struct hlist_head *bucket, 119static struct bucket *get_bucket(struct dm_bio_prison *prison,
120 struct dm_cell_key *key)
121{
122 return prison->buckets + hash_key(prison, key);
123}
124
125static struct dm_bio_prison_cell *__search_bucket(struct bucket *b,
111 struct dm_cell_key *key) 126 struct dm_cell_key *key)
112{ 127{
113 struct dm_bio_prison_cell *cell; 128 struct dm_bio_prison_cell *cell;
114 129
115 hlist_for_each_entry(cell, bucket, list) 130 hlist_for_each_entry(cell, &b->cells, list)
116 if (keys_equal(&cell->key, key)) 131 if (keys_equal(&cell->key, key))
117 return cell; 132 return cell;
118 133
119 return NULL; 134 return NULL;
120} 135}
121 136
122static void __setup_new_cell(struct dm_bio_prison *prison, 137static void __setup_new_cell(struct bucket *b,
123 struct dm_cell_key *key, 138 struct dm_cell_key *key,
124 struct bio *holder, 139 struct bio *holder,
125 uint32_t hash,
126 struct dm_bio_prison_cell *cell) 140 struct dm_bio_prison_cell *cell)
127{ 141{
128 memcpy(&cell->key, key, sizeof(cell->key)); 142 memcpy(&cell->key, key, sizeof(cell->key));
129 cell->holder = holder; 143 cell->holder = holder;
130 bio_list_init(&cell->bios); 144 bio_list_init(&cell->bios);
131 hlist_add_head(&cell->list, prison->cells + hash); 145 hlist_add_head(&cell->list, &b->cells);
132} 146}
133 147
134static int __bio_detain(struct dm_bio_prison *prison, 148static int __bio_detain(struct bucket *b,
135 struct dm_cell_key *key, 149 struct dm_cell_key *key,
136 struct bio *inmate, 150 struct bio *inmate,
137 struct dm_bio_prison_cell *cell_prealloc, 151 struct dm_bio_prison_cell *cell_prealloc,
138 struct dm_bio_prison_cell **cell_result) 152 struct dm_bio_prison_cell **cell_result)
139{ 153{
140 uint32_t hash = hash_key(prison, key);
141 struct dm_bio_prison_cell *cell; 154 struct dm_bio_prison_cell *cell;
142 155
143 cell = __search_bucket(prison->cells + hash, key); 156 cell = __search_bucket(b, key);
144 if (cell) { 157 if (cell) {
145 if (inmate) 158 if (inmate)
146 bio_list_add(&cell->bios, inmate); 159 bio_list_add(&cell->bios, inmate);
@@ -148,7 +161,7 @@ static int __bio_detain(struct dm_bio_prison *prison,
148 return 1; 161 return 1;
149 } 162 }
150 163
151 __setup_new_cell(prison, key, inmate, hash, cell_prealloc); 164 __setup_new_cell(b, key, inmate, cell_prealloc);
152 *cell_result = cell_prealloc; 165 *cell_result = cell_prealloc;
153 return 0; 166 return 0;
154} 167}
@@ -161,10 +174,11 @@ static int bio_detain(struct dm_bio_prison *prison,
161{ 174{
162 int r; 175 int r;
163 unsigned long flags; 176 unsigned long flags;
177 struct bucket *b = get_bucket(prison, key);
164 178
165 spin_lock_irqsave(&prison->lock, flags); 179 spin_lock_irqsave(&b->lock, flags);
166 r = __bio_detain(prison, key, inmate, cell_prealloc, cell_result); 180 r = __bio_detain(b, key, inmate, cell_prealloc, cell_result);
167 spin_unlock_irqrestore(&prison->lock, flags); 181 spin_unlock_irqrestore(&b->lock, flags);
168 182
169 return r; 183 return r;
170} 184}
@@ -208,10 +222,11 @@ void dm_cell_release(struct dm_bio_prison *prison,
208 struct bio_list *bios) 222 struct bio_list *bios)
209{ 223{
210 unsigned long flags; 224 unsigned long flags;
225 struct bucket *b = get_bucket(prison, &cell->key);
211 226
212 spin_lock_irqsave(&prison->lock, flags); 227 spin_lock_irqsave(&b->lock, flags);
213 __cell_release(cell, bios); 228 __cell_release(cell, bios);
214 spin_unlock_irqrestore(&prison->lock, flags); 229 spin_unlock_irqrestore(&b->lock, flags);
215} 230}
216EXPORT_SYMBOL_GPL(dm_cell_release); 231EXPORT_SYMBOL_GPL(dm_cell_release);
217 232
@@ -230,10 +245,11 @@ void dm_cell_release_no_holder(struct dm_bio_prison *prison,
230 struct bio_list *inmates) 245 struct bio_list *inmates)
231{ 246{
232 unsigned long flags; 247 unsigned long flags;
248 struct bucket *b = get_bucket(prison, &cell->key);
233 249
234 spin_lock_irqsave(&prison->lock, flags); 250 spin_lock_irqsave(&b->lock, flags);
235 __cell_release_no_holder(cell, inmates); 251 __cell_release_no_holder(cell, inmates);
236 spin_unlock_irqrestore(&prison->lock, flags); 252 spin_unlock_irqrestore(&b->lock, flags);
237} 253}
238EXPORT_SYMBOL_GPL(dm_cell_release_no_holder); 254EXPORT_SYMBOL_GPL(dm_cell_release_no_holder);
239 255
@@ -242,13 +258,9 @@ void dm_cell_error(struct dm_bio_prison *prison,
242{ 258{
243 struct bio_list bios; 259 struct bio_list bios;
244 struct bio *bio; 260 struct bio *bio;
245 unsigned long flags;
246 261
247 bio_list_init(&bios); 262 bio_list_init(&bios);
248 263 dm_cell_release(prison, cell, &bios);
249 spin_lock_irqsave(&prison->lock, flags);
250 __cell_release(cell, &bios);
251 spin_unlock_irqrestore(&prison->lock, flags);
252 264
253 while ((bio = bio_list_pop(&bios))) 265 while ((bio = bio_list_pop(&bios)))
254 bio_endio(bio, error); 266 bio_endio(bio, error);