blob: f752d12081ffe31a4a6b62b25654d66a54756ee4 [file] [log] [blame]
Mike Snitzer4f81a412012-10-12 21:02:13 +01001/*
2 * Copyright (C) 2012 Red Hat, Inc.
3 *
4 * This file is released under the GPL.
5 */
6
7#include "dm.h"
8#include "dm-bio-prison.h"
9
10#include <linux/spinlock.h>
11#include <linux/mempool.h>
12#include <linux/module.h>
13#include <linux/slab.h>
14
15/*----------------------------------------------------------------*/
16
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +010017struct bucket {
Mike Snitzer4f81a412012-10-12 21:02:13 +010018 spinlock_t lock;
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +010019 struct hlist_head cells;
20};
21
22struct dm_bio_prison {
Mike Snitzer4f81a412012-10-12 21:02:13 +010023 mempool_t *cell_pool;
24
25 unsigned nr_buckets;
26 unsigned hash_mask;
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +010027 struct bucket *buckets;
Mike Snitzer4f81a412012-10-12 21:02:13 +010028};
29
30/*----------------------------------------------------------------*/
31
32static uint32_t calc_nr_buckets(unsigned nr_cells)
33{
34 uint32_t n = 128;
35
36 nr_cells /= 4;
37 nr_cells = min(nr_cells, 8192u);
38
39 while (n < nr_cells)
40 n <<= 1;
41
42 return n;
43}
44
45static struct kmem_cache *_cell_cache;
46
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +010047static void init_bucket(struct bucket *b)
48{
49 spin_lock_init(&b->lock);
50 INIT_HLIST_HEAD(&b->cells);
51}
52
Mike Snitzer4f81a412012-10-12 21:02:13 +010053/*
54 * @nr_cells should be the number of cells you want in use _concurrently_.
55 * Don't confuse it with the number of distinct keys.
56 */
57struct dm_bio_prison *dm_bio_prison_create(unsigned nr_cells)
58{
59 unsigned i;
60 uint32_t nr_buckets = calc_nr_buckets(nr_cells);
61 size_t len = sizeof(struct dm_bio_prison) +
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +010062 (sizeof(struct bucket) * nr_buckets);
Mike Snitzer4f81a412012-10-12 21:02:13 +010063 struct dm_bio_prison *prison = kmalloc(len, GFP_KERNEL);
64
65 if (!prison)
66 return NULL;
67
Mike Snitzer4f81a412012-10-12 21:02:13 +010068 prison->cell_pool = mempool_create_slab_pool(nr_cells, _cell_cache);
69 if (!prison->cell_pool) {
70 kfree(prison);
71 return NULL;
72 }
73
74 prison->nr_buckets = nr_buckets;
75 prison->hash_mask = nr_buckets - 1;
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +010076 prison->buckets = (struct bucket *) (prison + 1);
Mike Snitzer4f81a412012-10-12 21:02:13 +010077 for (i = 0; i < nr_buckets; i++)
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +010078 init_bucket(prison->buckets + i);
Mike Snitzer4f81a412012-10-12 21:02:13 +010079
80 return prison;
81}
82EXPORT_SYMBOL_GPL(dm_bio_prison_create);
83
84void dm_bio_prison_destroy(struct dm_bio_prison *prison)
85{
86 mempool_destroy(prison->cell_pool);
87 kfree(prison);
88}
89EXPORT_SYMBOL_GPL(dm_bio_prison_destroy);
90
Joe Thornber6beca5e2013-03-01 22:45:50 +000091struct dm_bio_prison_cell *dm_bio_prison_alloc_cell(struct dm_bio_prison *prison, gfp_t gfp)
92{
93 return mempool_alloc(prison->cell_pool, gfp);
94}
95EXPORT_SYMBOL_GPL(dm_bio_prison_alloc_cell);
96
97void dm_bio_prison_free_cell(struct dm_bio_prison *prison,
98 struct dm_bio_prison_cell *cell)
99{
100 mempool_free(cell, prison->cell_pool);
101}
102EXPORT_SYMBOL_GPL(dm_bio_prison_free_cell);
103
Mike Snitzer4f81a412012-10-12 21:02:13 +0100104static uint32_t hash_key(struct dm_bio_prison *prison, struct dm_cell_key *key)
105{
106 const unsigned long BIG_PRIME = 4294967291UL;
107 uint64_t hash = key->block * BIG_PRIME;
108
109 return (uint32_t) (hash & prison->hash_mask);
110}
111
112static int keys_equal(struct dm_cell_key *lhs, struct dm_cell_key *rhs)
113{
114 return (lhs->virtual == rhs->virtual) &&
115 (lhs->dev == rhs->dev) &&
116 (lhs->block == rhs->block);
117}
118
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100119static 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,
Mike Snitzer4f81a412012-10-12 21:02:13 +0100126 struct dm_cell_key *key)
127{
128 struct dm_bio_prison_cell *cell;
Mike Snitzer4f81a412012-10-12 21:02:13 +0100129
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100130 hlist_for_each_entry(cell, &b->cells, list)
Mike Snitzer4f81a412012-10-12 21:02:13 +0100131 if (keys_equal(&cell->key, key))
132 return cell;
133
134 return NULL;
135}
136
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100137static void __setup_new_cell(struct bucket *b,
Joe Thornber6beca5e2013-03-01 22:45:50 +0000138 struct dm_cell_key *key,
139 struct bio *holder,
Joe Thornber6beca5e2013-03-01 22:45:50 +0000140 struct dm_bio_prison_cell *cell)
Mike Snitzer4f81a412012-10-12 21:02:13 +0100141{
Mike Snitzer4f81a412012-10-12 21:02:13 +0100142 memcpy(&cell->key, key, sizeof(cell->key));
Joe Thornber6beca5e2013-03-01 22:45:50 +0000143 cell->holder = holder;
Mike Snitzer4f81a412012-10-12 21:02:13 +0100144 bio_list_init(&cell->bios);
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100145 hlist_add_head(&cell->list, &b->cells);
Joe Thornber6beca5e2013-03-01 22:45:50 +0000146}
Mike Snitzer4f81a412012-10-12 21:02:13 +0100147
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100148static int __bio_detain(struct bucket *b,
Joe Thornber6beca5e2013-03-01 22:45:50 +0000149 struct dm_cell_key *key,
150 struct bio *inmate,
151 struct dm_bio_prison_cell *cell_prealloc,
152 struct dm_bio_prison_cell **cell_result)
153{
Joe Thornber6beca5e2013-03-01 22:45:50 +0000154 struct dm_bio_prison_cell *cell;
Mike Snitzer4f81a412012-10-12 21:02:13 +0100155
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100156 cell = __search_bucket(b, key);
Joe Thornber6beca5e2013-03-01 22:45:50 +0000157 if (cell) {
158 if (inmate)
159 bio_list_add(&cell->bios, inmate);
160 *cell_result = cell;
161 return 1;
162 }
163
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100164 __setup_new_cell(b, key, inmate, cell_prealloc);
Joe Thornber6beca5e2013-03-01 22:45:50 +0000165 *cell_result = cell_prealloc;
166 return 0;
167}
168
169static int bio_detain(struct dm_bio_prison *prison,
170 struct dm_cell_key *key,
171 struct bio *inmate,
172 struct dm_bio_prison_cell *cell_prealloc,
173 struct dm_bio_prison_cell **cell_result)
174{
175 int r;
176 unsigned long flags;
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100177 struct bucket *b = get_bucket(prison, key);
Joe Thornber6beca5e2013-03-01 22:45:50 +0000178
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100179 spin_lock_irqsave(&b->lock, flags);
180 r = __bio_detain(b, key, inmate, cell_prealloc, cell_result);
181 spin_unlock_irqrestore(&b->lock, flags);
Mike Snitzer4f81a412012-10-12 21:02:13 +0100182
Mike Snitzer4f81a412012-10-12 21:02:13 +0100183 return r;
184}
Joe Thornber6beca5e2013-03-01 22:45:50 +0000185
186int dm_bio_detain(struct dm_bio_prison *prison,
187 struct dm_cell_key *key,
188 struct bio *inmate,
189 struct dm_bio_prison_cell *cell_prealloc,
190 struct dm_bio_prison_cell **cell_result)
191{
192 return bio_detain(prison, key, inmate, cell_prealloc, cell_result);
193}
Mike Snitzer4f81a412012-10-12 21:02:13 +0100194EXPORT_SYMBOL_GPL(dm_bio_detain);
195
Joe Thornberc6b4fcb2013-03-01 22:45:51 +0000196int dm_get_cell(struct dm_bio_prison *prison,
197 struct dm_cell_key *key,
198 struct dm_bio_prison_cell *cell_prealloc,
199 struct dm_bio_prison_cell **cell_result)
200{
201 return bio_detain(prison, key, NULL, cell_prealloc, cell_result);
202}
203EXPORT_SYMBOL_GPL(dm_get_cell);
204
Mike Snitzer4f81a412012-10-12 21:02:13 +0100205/*
206 * @inmates must have been initialised prior to this call
207 */
Joe Thornber6beca5e2013-03-01 22:45:50 +0000208static void __cell_release(struct dm_bio_prison_cell *cell,
209 struct bio_list *inmates)
Mike Snitzer4f81a412012-10-12 21:02:13 +0100210{
Mike Snitzer4f81a412012-10-12 21:02:13 +0100211 hlist_del(&cell->list);
212
213 if (inmates) {
Joe Thornber6beca5e2013-03-01 22:45:50 +0000214 if (cell->holder)
215 bio_list_add(inmates, cell->holder);
Mike Snitzer4f81a412012-10-12 21:02:13 +0100216 bio_list_merge(inmates, &cell->bios);
217 }
Mike Snitzer4f81a412012-10-12 21:02:13 +0100218}
219
Joe Thornber6beca5e2013-03-01 22:45:50 +0000220void dm_cell_release(struct dm_bio_prison *prison,
221 struct dm_bio_prison_cell *cell,
222 struct bio_list *bios)
Mike Snitzer4f81a412012-10-12 21:02:13 +0100223{
224 unsigned long flags;
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100225 struct bucket *b = get_bucket(prison, &cell->key);
Mike Snitzer4f81a412012-10-12 21:02:13 +0100226
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100227 spin_lock_irqsave(&b->lock, flags);
Mike Snitzer4f81a412012-10-12 21:02:13 +0100228 __cell_release(cell, bios);
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100229 spin_unlock_irqrestore(&b->lock, flags);
Mike Snitzer4f81a412012-10-12 21:02:13 +0100230}
231EXPORT_SYMBOL_GPL(dm_cell_release);
232
233/*
Mike Snitzer4f81a412012-10-12 21:02:13 +0100234 * Sometimes we don't want the holder, just the additional bios.
235 */
Joe Thornber6beca5e2013-03-01 22:45:50 +0000236static void __cell_release_no_holder(struct dm_bio_prison_cell *cell,
237 struct bio_list *inmates)
Mike Snitzer4f81a412012-10-12 21:02:13 +0100238{
Mike Snitzer4f81a412012-10-12 21:02:13 +0100239 hlist_del(&cell->list);
240 bio_list_merge(inmates, &cell->bios);
Mike Snitzer4f81a412012-10-12 21:02:13 +0100241}
242
Joe Thornber6beca5e2013-03-01 22:45:50 +0000243void dm_cell_release_no_holder(struct dm_bio_prison *prison,
244 struct dm_bio_prison_cell *cell,
245 struct bio_list *inmates)
Mike Snitzer4f81a412012-10-12 21:02:13 +0100246{
247 unsigned long flags;
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100248 struct bucket *b = get_bucket(prison, &cell->key);
Mike Snitzer4f81a412012-10-12 21:02:13 +0100249
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100250 spin_lock_irqsave(&b->lock, flags);
Mike Snitzer4f81a412012-10-12 21:02:13 +0100251 __cell_release_no_holder(cell, inmates);
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100252 spin_unlock_irqrestore(&b->lock, flags);
Mike Snitzer4f81a412012-10-12 21:02:13 +0100253}
254EXPORT_SYMBOL_GPL(dm_cell_release_no_holder);
255
Joe Thornber6beca5e2013-03-01 22:45:50 +0000256void dm_cell_error(struct dm_bio_prison *prison,
Mike Snitzeraf918052014-05-22 14:32:51 -0400257 struct dm_bio_prison_cell *cell, int error)
Mike Snitzer4f81a412012-10-12 21:02:13 +0100258{
Mike Snitzer4f81a412012-10-12 21:02:13 +0100259 struct bio_list bios;
260 struct bio *bio;
Mike Snitzer4f81a412012-10-12 21:02:13 +0100261
262 bio_list_init(&bios);
Heinz Mauelshagenadcc4442014-06-05 15:23:09 +0100263 dm_cell_release(prison, cell, &bios);
Mike Snitzer4f81a412012-10-12 21:02:13 +0100264
265 while ((bio = bio_list_pop(&bios)))
Mike Snitzeraf918052014-05-22 14:32:51 -0400266 bio_endio(bio, error);
Mike Snitzer4f81a412012-10-12 21:02:13 +0100267}
268EXPORT_SYMBOL_GPL(dm_cell_error);
269
270/*----------------------------------------------------------------*/
271
272#define DEFERRED_SET_SIZE 64
273
274struct dm_deferred_entry {
275 struct dm_deferred_set *ds;
276 unsigned count;
277 struct list_head work_items;
278};
279
280struct dm_deferred_set {
281 spinlock_t lock;
282 unsigned current_entry;
283 unsigned sweeper;
284 struct dm_deferred_entry entries[DEFERRED_SET_SIZE];
285};
286
287struct dm_deferred_set *dm_deferred_set_create(void)
288{
289 int i;
290 struct dm_deferred_set *ds;
291
292 ds = kmalloc(sizeof(*ds), GFP_KERNEL);
293 if (!ds)
294 return NULL;
295
296 spin_lock_init(&ds->lock);
297 ds->current_entry = 0;
298 ds->sweeper = 0;
299 for (i = 0; i < DEFERRED_SET_SIZE; i++) {
300 ds->entries[i].ds = ds;
301 ds->entries[i].count = 0;
302 INIT_LIST_HEAD(&ds->entries[i].work_items);
303 }
304
305 return ds;
306}
307EXPORT_SYMBOL_GPL(dm_deferred_set_create);
308
309void dm_deferred_set_destroy(struct dm_deferred_set *ds)
310{
311 kfree(ds);
312}
313EXPORT_SYMBOL_GPL(dm_deferred_set_destroy);
314
315struct dm_deferred_entry *dm_deferred_entry_inc(struct dm_deferred_set *ds)
316{
317 unsigned long flags;
318 struct dm_deferred_entry *entry;
319
320 spin_lock_irqsave(&ds->lock, flags);
321 entry = ds->entries + ds->current_entry;
322 entry->count++;
323 spin_unlock_irqrestore(&ds->lock, flags);
324
325 return entry;
326}
327EXPORT_SYMBOL_GPL(dm_deferred_entry_inc);
328
329static unsigned ds_next(unsigned index)
330{
331 return (index + 1) % DEFERRED_SET_SIZE;
332}
333
334static void __sweep(struct dm_deferred_set *ds, struct list_head *head)
335{
336 while ((ds->sweeper != ds->current_entry) &&
337 !ds->entries[ds->sweeper].count) {
338 list_splice_init(&ds->entries[ds->sweeper].work_items, head);
339 ds->sweeper = ds_next(ds->sweeper);
340 }
341
342 if ((ds->sweeper == ds->current_entry) && !ds->entries[ds->sweeper].count)
343 list_splice_init(&ds->entries[ds->sweeper].work_items, head);
344}
345
346void dm_deferred_entry_dec(struct dm_deferred_entry *entry, struct list_head *head)
347{
348 unsigned long flags;
349
350 spin_lock_irqsave(&entry->ds->lock, flags);
351 BUG_ON(!entry->count);
352 --entry->count;
353 __sweep(entry->ds, head);
354 spin_unlock_irqrestore(&entry->ds->lock, flags);
355}
356EXPORT_SYMBOL_GPL(dm_deferred_entry_dec);
357
358/*
359 * Returns 1 if deferred or 0 if no pending items to delay job.
360 */
361int dm_deferred_set_add_work(struct dm_deferred_set *ds, struct list_head *work)
362{
363 int r = 1;
364 unsigned long flags;
365 unsigned next_entry;
366
367 spin_lock_irqsave(&ds->lock, flags);
368 if ((ds->sweeper == ds->current_entry) &&
369 !ds->entries[ds->current_entry].count)
370 r = 0;
371 else {
372 list_add(work, &ds->entries[ds->current_entry].work_items);
373 next_entry = ds_next(ds->current_entry);
374 if (!ds->entries[next_entry].count)
375 ds->current_entry = next_entry;
376 }
377 spin_unlock_irqrestore(&ds->lock, flags);
378
379 return r;
380}
381EXPORT_SYMBOL_GPL(dm_deferred_set_add_work);
382
383/*----------------------------------------------------------------*/
384
385static int __init dm_bio_prison_init(void)
386{
387 _cell_cache = KMEM_CACHE(dm_bio_prison_cell, 0);
388 if (!_cell_cache)
389 return -ENOMEM;
390
391 return 0;
392}
393
394static void __exit dm_bio_prison_exit(void)
395{
396 kmem_cache_destroy(_cell_cache);
397 _cell_cache = NULL;
398}
399
400/*
401 * module hooks
402 */
403module_init(dm_bio_prison_init);
404module_exit(dm_bio_prison_exit);
405
406MODULE_DESCRIPTION(DM_NAME " bio prison");
407MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
408MODULE_LICENSE("GPL");