diff options
| -rw-r--r-- | drivers/md/dm-bio-prison.c | 66 |
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 | ||
| 17 | struct dm_bio_prison { | 17 | struct bucket { |
| 18 | spinlock_t lock; | 18 | spinlock_t lock; |
| 19 | struct hlist_head cells; | ||
| 20 | }; | ||
| 21 | |||
| 22 | struct 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 | ||
| 41 | static struct kmem_cache *_cell_cache; | 45 | static struct kmem_cache *_cell_cache; |
| 42 | 46 | ||
| 47 | static 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 | ||
| 110 | static struct dm_bio_prison_cell *__search_bucket(struct hlist_head *bucket, | 119 | static 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 | |||
| 125 | static 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 | ||
| 122 | static void __setup_new_cell(struct dm_bio_prison *prison, | 137 | static 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 | ||
| 134 | static int __bio_detain(struct dm_bio_prison *prison, | 148 | static 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 | } |
| 216 | EXPORT_SYMBOL_GPL(dm_cell_release); | 231 | EXPORT_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 | } |
| 238 | EXPORT_SYMBOL_GPL(dm_cell_release_no_holder); | 254 | EXPORT_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); |
