2 * Copyright (C) 2012 Red Hat, Inc.
4 * This file is released under the GPL.
8 #include "dm-bio-prison.h"
10 #include <linux/spinlock.h>
11 #include <linux/mempool.h>
12 #include <linux/module.h>
13 #include <linux/slab.h>
15 /*----------------------------------------------------------------*/
17 struct dm_bio_prison_cell
{
18 struct hlist_node list
;
19 struct dm_bio_prison
*prison
;
20 struct dm_cell_key key
;
25 struct dm_bio_prison
{
31 struct hlist_head
*cells
;
34 /*----------------------------------------------------------------*/
36 static uint32_t calc_nr_buckets(unsigned nr_cells
)
41 nr_cells
= min(nr_cells
, 8192u);
49 static struct kmem_cache
*_cell_cache
;
52 * @nr_cells should be the number of cells you want in use _concurrently_.
53 * Don't confuse it with the number of distinct keys.
55 struct dm_bio_prison
*dm_bio_prison_create(unsigned nr_cells
)
58 uint32_t nr_buckets
= calc_nr_buckets(nr_cells
);
59 size_t len
= sizeof(struct dm_bio_prison
) +
60 (sizeof(struct hlist_head
) * nr_buckets
);
61 struct dm_bio_prison
*prison
= kmalloc(len
, GFP_KERNEL
);
66 spin_lock_init(&prison
->lock
);
67 prison
->cell_pool
= mempool_create_slab_pool(nr_cells
, _cell_cache
);
68 if (!prison
->cell_pool
) {
73 prison
->nr_buckets
= nr_buckets
;
74 prison
->hash_mask
= nr_buckets
- 1;
75 prison
->cells
= (struct hlist_head
*) (prison
+ 1);
76 for (i
= 0; i
< nr_buckets
; i
++)
77 INIT_HLIST_HEAD(prison
->cells
+ i
);
81 EXPORT_SYMBOL_GPL(dm_bio_prison_create
);
83 void dm_bio_prison_destroy(struct dm_bio_prison
*prison
)
85 mempool_destroy(prison
->cell_pool
);
88 EXPORT_SYMBOL_GPL(dm_bio_prison_destroy
);
90 static uint32_t hash_key(struct dm_bio_prison
*prison
, struct dm_cell_key
*key
)
92 const unsigned long BIG_PRIME
= 4294967291UL;
93 uint64_t hash
= key
->block
* BIG_PRIME
;
95 return (uint32_t) (hash
& prison
->hash_mask
);
98 static int keys_equal(struct dm_cell_key
*lhs
, struct dm_cell_key
*rhs
)
100 return (lhs
->virtual == rhs
->virtual) &&
101 (lhs
->dev
== rhs
->dev
) &&
102 (lhs
->block
== rhs
->block
);
105 static struct dm_bio_prison_cell
*__search_bucket(struct hlist_head
*bucket
,
106 struct dm_cell_key
*key
)
108 struct dm_bio_prison_cell
*cell
;
109 struct hlist_node
*tmp
;
111 hlist_for_each_entry(cell
, tmp
, bucket
, list
)
112 if (keys_equal(&cell
->key
, key
))
119 * This may block if a new cell needs allocating. You must ensure that
120 * cells will be unlocked even if the calling thread is blocked.
122 * Returns 1 if the cell was already held, 0 if @inmate is the new holder.
124 int dm_bio_detain(struct dm_bio_prison
*prison
, struct dm_cell_key
*key
,
125 struct bio
*inmate
, struct dm_bio_prison_cell
**ref
)
129 uint32_t hash
= hash_key(prison
, key
);
130 struct dm_bio_prison_cell
*cell
, *cell2
;
132 BUG_ON(hash
> prison
->nr_buckets
);
134 spin_lock_irqsave(&prison
->lock
, flags
);
136 cell
= __search_bucket(prison
->cells
+ hash
, key
);
138 bio_list_add(&cell
->bios
, inmate
);
143 * Allocate a new cell
145 spin_unlock_irqrestore(&prison
->lock
, flags
);
146 cell2
= mempool_alloc(prison
->cell_pool
, GFP_NOIO
);
147 spin_lock_irqsave(&prison
->lock
, flags
);
150 * We've been unlocked, so we have to double check that
151 * nobody else has inserted this cell in the meantime.
153 cell
= __search_bucket(prison
->cells
+ hash
, key
);
155 mempool_free(cell2
, prison
->cell_pool
);
156 bio_list_add(&cell
->bios
, inmate
);
165 cell
->prison
= prison
;
166 memcpy(&cell
->key
, key
, sizeof(cell
->key
));
167 cell
->holder
= inmate
;
168 bio_list_init(&cell
->bios
);
169 hlist_add_head(&cell
->list
, prison
->cells
+ hash
);
174 spin_unlock_irqrestore(&prison
->lock
, flags
);
180 EXPORT_SYMBOL_GPL(dm_bio_detain
);
183 * @inmates must have been initialised prior to this call
185 static void __cell_release(struct dm_bio_prison_cell
*cell
, struct bio_list
*inmates
)
187 struct dm_bio_prison
*prison
= cell
->prison
;
189 hlist_del(&cell
->list
);
192 bio_list_add(inmates
, cell
->holder
);
193 bio_list_merge(inmates
, &cell
->bios
);
196 mempool_free(cell
, prison
->cell_pool
);
199 void dm_cell_release(struct dm_bio_prison_cell
*cell
, struct bio_list
*bios
)
202 struct dm_bio_prison
*prison
= cell
->prison
;
204 spin_lock_irqsave(&prison
->lock
, flags
);
205 __cell_release(cell
, bios
);
206 spin_unlock_irqrestore(&prison
->lock
, flags
);
208 EXPORT_SYMBOL_GPL(dm_cell_release
);
211 * There are a couple of places where we put a bio into a cell briefly
212 * before taking it out again. In these situations we know that no other
213 * bio may be in the cell. This function releases the cell, and also does
216 static void __cell_release_singleton(struct dm_bio_prison_cell
*cell
, struct bio
*bio
)
218 BUG_ON(cell
->holder
!= bio
);
219 BUG_ON(!bio_list_empty(&cell
->bios
));
221 __cell_release(cell
, NULL
);
224 void dm_cell_release_singleton(struct dm_bio_prison_cell
*cell
, struct bio
*bio
)
227 struct dm_bio_prison
*prison
= cell
->prison
;
229 spin_lock_irqsave(&prison
->lock
, flags
);
230 __cell_release_singleton(cell
, bio
);
231 spin_unlock_irqrestore(&prison
->lock
, flags
);
233 EXPORT_SYMBOL_GPL(dm_cell_release_singleton
);
236 * Sometimes we don't want the holder, just the additional bios.
238 static void __cell_release_no_holder(struct dm_bio_prison_cell
*cell
, struct bio_list
*inmates
)
240 struct dm_bio_prison
*prison
= cell
->prison
;
242 hlist_del(&cell
->list
);
243 bio_list_merge(inmates
, &cell
->bios
);
245 mempool_free(cell
, prison
->cell_pool
);
248 void dm_cell_release_no_holder(struct dm_bio_prison_cell
*cell
, struct bio_list
*inmates
)
251 struct dm_bio_prison
*prison
= cell
->prison
;
253 spin_lock_irqsave(&prison
->lock
, flags
);
254 __cell_release_no_holder(cell
, inmates
);
255 spin_unlock_irqrestore(&prison
->lock
, flags
);
257 EXPORT_SYMBOL_GPL(dm_cell_release_no_holder
);
259 void dm_cell_error(struct dm_bio_prison_cell
*cell
)
261 struct dm_bio_prison
*prison
= cell
->prison
;
262 struct bio_list bios
;
266 bio_list_init(&bios
);
268 spin_lock_irqsave(&prison
->lock
, flags
);
269 __cell_release(cell
, &bios
);
270 spin_unlock_irqrestore(&prison
->lock
, flags
);
272 while ((bio
= bio_list_pop(&bios
)))
275 EXPORT_SYMBOL_GPL(dm_cell_error
);
277 /*----------------------------------------------------------------*/
279 #define DEFERRED_SET_SIZE 64
281 struct dm_deferred_entry
{
282 struct dm_deferred_set
*ds
;
284 struct list_head work_items
;
287 struct dm_deferred_set
{
289 unsigned current_entry
;
291 struct dm_deferred_entry entries
[DEFERRED_SET_SIZE
];
294 struct dm_deferred_set
*dm_deferred_set_create(void)
297 struct dm_deferred_set
*ds
;
299 ds
= kmalloc(sizeof(*ds
), GFP_KERNEL
);
303 spin_lock_init(&ds
->lock
);
304 ds
->current_entry
= 0;
306 for (i
= 0; i
< DEFERRED_SET_SIZE
; i
++) {
307 ds
->entries
[i
].ds
= ds
;
308 ds
->entries
[i
].count
= 0;
309 INIT_LIST_HEAD(&ds
->entries
[i
].work_items
);
314 EXPORT_SYMBOL_GPL(dm_deferred_set_create
);
316 void dm_deferred_set_destroy(struct dm_deferred_set
*ds
)
320 EXPORT_SYMBOL_GPL(dm_deferred_set_destroy
);
322 struct dm_deferred_entry
*dm_deferred_entry_inc(struct dm_deferred_set
*ds
)
325 struct dm_deferred_entry
*entry
;
327 spin_lock_irqsave(&ds
->lock
, flags
);
328 entry
= ds
->entries
+ ds
->current_entry
;
330 spin_unlock_irqrestore(&ds
->lock
, flags
);
334 EXPORT_SYMBOL_GPL(dm_deferred_entry_inc
);
336 static unsigned ds_next(unsigned index
)
338 return (index
+ 1) % DEFERRED_SET_SIZE
;
341 static void __sweep(struct dm_deferred_set
*ds
, struct list_head
*head
)
343 while ((ds
->sweeper
!= ds
->current_entry
) &&
344 !ds
->entries
[ds
->sweeper
].count
) {
345 list_splice_init(&ds
->entries
[ds
->sweeper
].work_items
, head
);
346 ds
->sweeper
= ds_next(ds
->sweeper
);
349 if ((ds
->sweeper
== ds
->current_entry
) && !ds
->entries
[ds
->sweeper
].count
)
350 list_splice_init(&ds
->entries
[ds
->sweeper
].work_items
, head
);
353 void dm_deferred_entry_dec(struct dm_deferred_entry
*entry
, struct list_head
*head
)
357 spin_lock_irqsave(&entry
->ds
->lock
, flags
);
358 BUG_ON(!entry
->count
);
360 __sweep(entry
->ds
, head
);
361 spin_unlock_irqrestore(&entry
->ds
->lock
, flags
);
363 EXPORT_SYMBOL_GPL(dm_deferred_entry_dec
);
366 * Returns 1 if deferred or 0 if no pending items to delay job.
368 int dm_deferred_set_add_work(struct dm_deferred_set
*ds
, struct list_head
*work
)
374 spin_lock_irqsave(&ds
->lock
, flags
);
375 if ((ds
->sweeper
== ds
->current_entry
) &&
376 !ds
->entries
[ds
->current_entry
].count
)
379 list_add(work
, &ds
->entries
[ds
->current_entry
].work_items
);
380 next_entry
= ds_next(ds
->current_entry
);
381 if (!ds
->entries
[next_entry
].count
)
382 ds
->current_entry
= next_entry
;
384 spin_unlock_irqrestore(&ds
->lock
, flags
);
388 EXPORT_SYMBOL_GPL(dm_deferred_set_add_work
);
390 /*----------------------------------------------------------------*/
392 static int __init
dm_bio_prison_init(void)
394 _cell_cache
= KMEM_CACHE(dm_bio_prison_cell
, 0);
401 static void __exit
dm_bio_prison_exit(void)
403 kmem_cache_destroy(_cell_cache
);
410 module_init(dm_bio_prison_init
);
411 module_exit(dm_bio_prison_exit
);
413 MODULE_DESCRIPTION(DM_NAME
" bio prison");
414 MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
415 MODULE_LICENSE("GPL");