diff options
| author | Mike Snitzer <snitzer@redhat.com> | 2012-06-02 19:30:00 -0400 |
|---|---|---|
| committer | Alasdair G Kergon <agk@redhat.com> | 2012-06-02 19:30:00 -0400 |
| commit | a24c25696b7133dd534d7a9436e576af79d9ce3b (patch) | |
| tree | 7b8b429aec7d7b2cebfbfbba0047911dc79290aa | |
| parent | 35991652baa12ff3d0e420c0d0cb2ad9f7076e5b (diff) | |
dm thin: use slab mempools
Use dedicated caches prefixed with a "dm_" name rather than relying on
kmalloc mempools backed by generic slab caches so the memory usage of
thin provisioning (and any leaks) can be accounted for independently.
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
| -rw-r--r-- | drivers/md/dm-thin.c | 161 |
1 files changed, 99 insertions, 62 deletions
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index eb3d138ff55a..db1b041ce975 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c | |||
| @@ -111,7 +111,7 @@ struct cell_key { | |||
| 111 | dm_block_t block; | 111 | dm_block_t block; |
| 112 | }; | 112 | }; |
| 113 | 113 | ||
| 114 | struct cell { | 114 | struct dm_bio_prison_cell { |
| 115 | struct hlist_node list; | 115 | struct hlist_node list; |
| 116 | struct bio_prison *prison; | 116 | struct bio_prison *prison; |
| 117 | struct cell_key key; | 117 | struct cell_key key; |
| @@ -141,6 +141,8 @@ static uint32_t calc_nr_buckets(unsigned nr_cells) | |||
| 141 | return n; | 141 | return n; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | static struct kmem_cache *_cell_cache; | ||
| 145 | |||
| 144 | /* | 146 | /* |
| 145 | * @nr_cells should be the number of cells you want in use _concurrently_. | 147 | * @nr_cells should be the number of cells you want in use _concurrently_. |
| 146 | * Don't confuse it with the number of distinct keys. | 148 | * Don't confuse it with the number of distinct keys. |
| @@ -157,8 +159,7 @@ static struct bio_prison *prison_create(unsigned nr_cells) | |||
| 157 | return NULL; | 159 | return NULL; |
| 158 | 160 | ||
| 159 | spin_lock_init(&prison->lock); | 161 | spin_lock_init(&prison->lock); |
| 160 | prison->cell_pool = mempool_create_kmalloc_pool(nr_cells, | 162 | prison->cell_pool = mempool_create_slab_pool(nr_cells, _cell_cache); |
| 161 | sizeof(struct cell)); | ||
| 162 | if (!prison->cell_pool) { | 163 | if (!prison->cell_pool) { |
| 163 | kfree(prison); | 164 | kfree(prison); |
| 164 | return NULL; | 165 | return NULL; |
| @@ -194,10 +195,10 @@ static int keys_equal(struct cell_key *lhs, struct cell_key *rhs) | |||
| 194 | (lhs->block == rhs->block); | 195 | (lhs->block == rhs->block); |
| 195 | } | 196 | } |
| 196 | 197 | ||
| 197 | static struct cell *__search_bucket(struct hlist_head *bucket, | 198 | static struct dm_bio_prison_cell *__search_bucket(struct hlist_head *bucket, |
| 198 | struct cell_key *key) | 199 | struct cell_key *key) |
| 199 | { | 200 | { |
| 200 | struct cell *cell; | 201 | struct dm_bio_prison_cell *cell; |
| 201 | struct hlist_node *tmp; | 202 | struct hlist_node *tmp; |
| 202 | 203 | ||
| 203 | hlist_for_each_entry(cell, tmp, bucket, list) | 204 | hlist_for_each_entry(cell, tmp, bucket, list) |
| @@ -214,12 +215,12 @@ static struct cell *__search_bucket(struct hlist_head *bucket, | |||
| 214 | * Returns 1 if the cell was already held, 0 if @inmate is the new holder. | 215 | * Returns 1 if the cell was already held, 0 if @inmate is the new holder. |
| 215 | */ | 216 | */ |
| 216 | static int bio_detain(struct bio_prison *prison, struct cell_key *key, | 217 | static int bio_detain(struct bio_prison *prison, struct cell_key *key, |
| 217 | struct bio *inmate, struct cell **ref) | 218 | struct bio *inmate, struct dm_bio_prison_cell **ref) |
| 218 | { | 219 | { |
| 219 | int r = 1; | 220 | int r = 1; |
| 220 | unsigned long flags; | 221 | unsigned long flags; |
| 221 | uint32_t hash = hash_key(prison, key); | 222 | uint32_t hash = hash_key(prison, key); |
| 222 | struct cell *cell, *cell2; | 223 | struct dm_bio_prison_cell *cell, *cell2; |
| 223 | 224 | ||
| 224 | BUG_ON(hash > prison->nr_buckets); | 225 | BUG_ON(hash > prison->nr_buckets); |
| 225 | 226 | ||
| @@ -273,7 +274,7 @@ out: | |||
| 273 | /* | 274 | /* |
| 274 | * @inmates must have been initialised prior to this call | 275 | * @inmates must have been initialised prior to this call |
| 275 | */ | 276 | */ |
| 276 | static void __cell_release(struct cell *cell, struct bio_list *inmates) | 277 | static void __cell_release(struct dm_bio_prison_cell *cell, struct bio_list *inmates) |
| 277 | { | 278 | { |
| 278 | struct bio_prison *prison = cell->prison; | 279 | struct bio_prison *prison = cell->prison; |
| 279 | 280 | ||
| @@ -287,7 +288,7 @@ static void __cell_release(struct cell *cell, struct bio_list *inmates) | |||
| 287 | mempool_free(cell, prison->cell_pool); | 288 | mempool_free(cell, prison->cell_pool); |
| 288 | } | 289 | } |
| 289 | 290 | ||
| 290 | static void cell_release(struct cell *cell, struct bio_list *bios) | 291 | static void cell_release(struct dm_bio_prison_cell *cell, struct bio_list *bios) |
| 291 | { | 292 | { |
| 292 | unsigned long flags; | 293 | unsigned long flags; |
| 293 | struct bio_prison *prison = cell->prison; | 294 | struct bio_prison *prison = cell->prison; |
| @@ -303,7 +304,7 @@ static void cell_release(struct cell *cell, struct bio_list *bios) | |||
| 303 | * bio may be in the cell. This function releases the cell, and also does | 304 | * bio may be in the cell. This function releases the cell, and also does |
| 304 | * a sanity check. | 305 | * a sanity check. |
| 305 | */ | 306 | */ |
| 306 | static void __cell_release_singleton(struct cell *cell, struct bio *bio) | 307 | static void __cell_release_singleton(struct dm_bio_prison_cell *cell, struct bio *bio) |
| 307 | { | 308 | { |
| 308 | BUG_ON(cell->holder != bio); | 309 | BUG_ON(cell->holder != bio); |
| 309 | BUG_ON(!bio_list_empty(&cell->bios)); | 310 | BUG_ON(!bio_list_empty(&cell->bios)); |
| @@ -311,7 +312,7 @@ static void __cell_release_singleton(struct cell *cell, struct bio *bio) | |||
| 311 | __cell_release(cell, NULL); | 312 | __cell_release(cell, NULL); |
| 312 | } | 313 | } |
| 313 | 314 | ||
| 314 | static void cell_release_singleton(struct cell *cell, struct bio *bio) | 315 | static void cell_release_singleton(struct dm_bio_prison_cell *cell, struct bio *bio) |
| 315 | { | 316 | { |
| 316 | unsigned long flags; | 317 | unsigned long flags; |
| 317 | struct bio_prison *prison = cell->prison; | 318 | struct bio_prison *prison = cell->prison; |
| @@ -324,7 +325,8 @@ static void cell_release_singleton(struct cell *cell, struct bio *bio) | |||
| 324 | /* | 325 | /* |
| 325 | * Sometimes we don't want the holder, just the additional bios. | 326 | * Sometimes we don't want the holder, just the additional bios. |
| 326 | */ | 327 | */ |
| 327 | static void __cell_release_no_holder(struct cell *cell, struct bio_list *inmates) | 328 | static void __cell_release_no_holder(struct dm_bio_prison_cell *cell, |
| 329 | struct bio_list *inmates) | ||
| 328 | { | 330 | { |
| 329 | struct bio_prison *prison = cell->prison; | 331 | struct bio_prison *prison = cell->prison; |
| 330 | 332 | ||
| @@ -334,7 +336,8 @@ static void __cell_release_no_holder(struct cell *cell, struct bio_list *inmates | |||
| 334 | mempool_free(cell, prison->cell_pool); | 336 | mempool_free(cell, prison->cell_pool); |
| 335 | } | 337 | } |
| 336 | 338 | ||
| 337 | static void cell_release_no_holder(struct cell *cell, struct bio_list *inmates) | 339 | static void cell_release_no_holder(struct dm_bio_prison_cell *cell, |
| 340 | struct bio_list *inmates) | ||
| 338 | { | 341 | { |
| 339 | unsigned long flags; | 342 | unsigned long flags; |
| 340 | struct bio_prison *prison = cell->prison; | 343 | struct bio_prison *prison = cell->prison; |
| @@ -344,7 +347,7 @@ static void cell_release_no_holder(struct cell *cell, struct bio_list *inmates) | |||
| 344 | spin_unlock_irqrestore(&prison->lock, flags); | 347 | spin_unlock_irqrestore(&prison->lock, flags); |
| 345 | } | 348 | } |
| 346 | 349 | ||
| 347 | static void cell_error(struct cell *cell) | 350 | static void cell_error(struct dm_bio_prison_cell *cell) |
| 348 | { | 351 | { |
| 349 | struct bio_prison *prison = cell->prison; | 352 | struct bio_prison *prison = cell->prison; |
| 350 | struct bio_list bios; | 353 | struct bio_list bios; |
| @@ -491,7 +494,7 @@ static void build_virtual_key(struct dm_thin_device *td, dm_block_t b, | |||
| 491 | * also provides the interface for creating and destroying internal | 494 | * also provides the interface for creating and destroying internal |
| 492 | * devices. | 495 | * devices. |
| 493 | */ | 496 | */ |
| 494 | struct new_mapping; | 497 | struct dm_thin_new_mapping; |
| 495 | 498 | ||
| 496 | struct pool_features { | 499 | struct pool_features { |
| 497 | unsigned zero_new_blocks:1; | 500 | unsigned zero_new_blocks:1; |
| @@ -537,7 +540,7 @@ struct pool { | |||
| 537 | struct deferred_set shared_read_ds; | 540 | struct deferred_set shared_read_ds; |
| 538 | struct deferred_set all_io_ds; | 541 | struct deferred_set all_io_ds; |
| 539 | 542 | ||
| 540 | struct new_mapping *next_mapping; | 543 | struct dm_thin_new_mapping *next_mapping; |
| 541 | mempool_t *mapping_pool; | 544 | mempool_t *mapping_pool; |
| 542 | mempool_t *endio_hook_pool; | 545 | mempool_t *endio_hook_pool; |
| 543 | }; | 546 | }; |
| @@ -630,11 +633,11 @@ static struct pool *__pool_table_lookup_metadata_dev(struct block_device *md_dev | |||
| 630 | 633 | ||
| 631 | /*----------------------------------------------------------------*/ | 634 | /*----------------------------------------------------------------*/ |
| 632 | 635 | ||
| 633 | struct endio_hook { | 636 | struct dm_thin_endio_hook { |
| 634 | struct thin_c *tc; | 637 | struct thin_c *tc; |
| 635 | struct deferred_entry *shared_read_entry; | 638 | struct deferred_entry *shared_read_entry; |
| 636 | struct deferred_entry *all_io_entry; | 639 | struct deferred_entry *all_io_entry; |
| 637 | struct new_mapping *overwrite_mapping; | 640 | struct dm_thin_new_mapping *overwrite_mapping; |
| 638 | }; | 641 | }; |
| 639 | 642 | ||
| 640 | static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master) | 643 | static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master) |
| @@ -647,7 +650,8 @@ static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master) | |||
| 647 | bio_list_init(master); | 650 | bio_list_init(master); |
| 648 | 651 | ||
| 649 | while ((bio = bio_list_pop(&bios))) { | 652 | while ((bio = bio_list_pop(&bios))) { |
| 650 | struct endio_hook *h = dm_get_mapinfo(bio)->ptr; | 653 | struct dm_thin_endio_hook *h = dm_get_mapinfo(bio)->ptr; |
| 654 | |||
| 651 | |||
