aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-bio-prison.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-bio-prison.c')
-rw-r--r--drivers/md/dm-bio-prison.c139
1 files changed, 72 insertions, 67 deletions
diff --git a/drivers/md/dm-bio-prison.c b/drivers/md/dm-bio-prison.c
index d9d3f1c7b662..ca5771d3ffd7 100644
--- a/drivers/md/dm-bio-prison.c
+++ b/drivers/md/dm-bio-prison.c
@@ -16,7 +16,6 @@
16 16
17struct dm_bio_prison_cell { 17struct dm_bio_prison_cell {
18 struct hlist_node list; 18 struct hlist_node list;
19 struct dm_bio_prison *prison;
20 struct dm_cell_key key; 19 struct dm_cell_key key;
21 struct bio *holder; 20 struct bio *holder;
22 struct bio_list bios; 21 struct bio_list bios;
@@ -87,6 +86,19 @@ void dm_bio_prison_destroy(struct dm_bio_prison *prison)
87} 86}
88EXPORT_SYMBOL_GPL(dm_bio_prison_destroy); 87EXPORT_SYMBOL_GPL(dm_bio_prison_destroy);
89 88
89struct dm_bio_prison_cell *dm_bio_prison_alloc_cell(struct dm_bio_prison *prison, gfp_t gfp)
90{
91 return mempool_alloc(prison->cell_pool, gfp);
92}
93EXPORT_SYMBOL_GPL(dm_bio_prison_alloc_cell);
94
95void dm_bio_prison_free_cell(struct dm_bio_prison *prison,
96 struct dm_bio_prison_cell *cell)
97{
98 mempool_free(cell, prison->cell_pool);
99}
100EXPORT_SYMBOL_GPL(dm_bio_prison_free_cell);
101
90static uint32_t hash_key(struct dm_bio_prison *prison, struct dm_cell_key *key) 102static uint32_t hash_key(struct dm_bio_prison *prison, struct dm_cell_key *key)
91{ 103{
92 const unsigned long BIG_PRIME = 4294967291UL; 104 const unsigned long BIG_PRIME = 4294967291UL;
@@ -114,91 +126,86 @@ static struct dm_bio_prison_cell *__search_bucket(struct hlist_head *bucket,
114 return NULL; 126 return NULL;
115} 127}
116 128
117/* 129static void __setup_new_cell(struct dm_bio_prison *prison,
118 * This may block if a new cell needs allocating. You must ensure that 130 struct dm_cell_key *key,
119 * cells will be unlocked even if the calling thread is blocked. 131 struct bio *holder,
120 * 132 uint32_t hash,
121 * Returns 1 if the cell was already held, 0 if @inmate is the new holder. 133 struct dm_bio_prison_cell *cell)
122 */
123int dm_bio_detain(struct dm_bio_prison *prison, struct dm_cell_key *key,
124 struct bio *inmate, struct dm_bio_prison_cell **ref)
125{ 134{
126 int r = 1; 135 memcpy(&cell->key, key, sizeof(cell->key));
127 unsigned long flags; 136 cell->holder = holder;
128 uint32_t hash = hash_key(prison, key); 137 bio_list_init(&cell->bios);
129 struct dm_bio_prison_cell *cell, *cell2; 138 hlist_add_head(&cell->list, prison->cells + hash);
130 139}
131 BUG_ON(hash > prison->nr_buckets);
132
133 spin_lock_irqsave(&prison->lock, flags);
134
135 cell = __search_bucket(prison->cells + hash, key);
136 if (cell) {
137 bio_list_add(&cell->bios, inmate);
138 goto out;
139 }
140 140
141 /* 141static int __bio_detain(struct dm_bio_prison *prison,
142 * Allocate a new cell 142 struct dm_cell_key *key,
143 */ 143 struct bio *inmate,
144 spin_unlock_irqrestore(&prison->lock, flags); 144 struct dm_bio_prison_cell *cell_prealloc,
145 cell2 = mempool_alloc(prison->cell_pool, GFP_NOIO); 145 struct dm_bio_prison_cell **cell_result)
146 spin_lock_irqsave(&prison->lock, flags); 146{
147 uint32_t hash = hash_key(prison, key);
148 struct dm_bio_prison_cell *cell;
147 149
148 /*
149 * We've been unlocked, so we have to double check that
150 * nobody else has inserted this cell in the meantime.
151 */
152 cell = __search_bucket(prison->cells + hash, key); 150 cell = __search_bucket(prison->cells + hash, key);
153 if (cell) { 151 if (cell) {
154 mempool_free(cell2, prison->cell_pool); 152 if (inmate)
155 bio_list_add(&cell->bios, inmate); 153 bio_list_add(&cell->bios, inmate);
156 goto out; 154 *cell_result = cell;
155 return 1;
157 } 156 }
158 157
159 /* 158 __setup_new_cell(prison, key, inmate, hash, cell_prealloc);
160 * Use new cell. 159 *cell_result = cell_prealloc;
161 */ 160 return 0;
162 cell = cell2; 161}
163
164 cell->prison = prison;
165 memcpy(&cell->key, key, sizeof(cell->key));
166 cell->holder = inmate;
167 bio_list_init(&cell->bios);
168 hlist_add_head(&cell->list, prison->cells + hash);
169 162
170 r = 0; 163static int bio_detain(struct dm_bio_prison *prison,
164 struct dm_cell_key *key,
165 struct bio *inmate,
166 struct dm_bio_prison_cell *cell_prealloc,
167 struct dm_bio_prison_cell **cell_result)
168{
169 int r;
170 unsigned long flags;
171 171
172out: 172 spin_lock_irqsave(&prison->lock, flags);
173 r = __bio_detain(prison, key, inmate, cell_prealloc, cell_result);
173 spin_unlock_irqrestore(&prison->lock, flags); 174 spin_unlock_irqrestore(&prison->lock, flags);
174 175
175 *ref = cell;
176
177 return r; 176 return r;
178} 177}
178
179int dm_bio_detain(struct dm_bio_prison *prison,
180 struct dm_cell_key *key,
181 struct bio *inmate,
182 struct dm_bio_prison_cell *cell_prealloc,
183 struct dm_bio_prison_cell **cell_result)
184{
185 return bio_detain(prison, key, inmate, cell_prealloc, cell_result);
186}
179EXPORT_SYMBOL_GPL(dm_bio_detain); 187EXPORT_SYMBOL_GPL(dm_bio_detain);
180 188
181/* 189/*
182 * @inmates must have been initialised prior to this call 190 * @inmates must have been initialised prior to this call
183 */ 191 */
184static void __cell_release(struct dm_bio_prison_cell *cell, struct bio_list *inmates) 192static void __cell_release(struct dm_bio_prison_cell *cell,
193 struct bio_list *inmates)
185{ 194{
186 struct dm_bio_prison *prison = cell->prison;
187
188 hlist_del(&cell->list); 195 hlist_del(&cell->list);
189 196
190 if (inmates) { 197 if (inmates) {
191 bio_list_add(inmates, cell->holder); 198 if (cell->holder)
199 bio_list_add(inmates, cell->holder);
192 bio_list_merge(inmates, &cell->bios); 200 bio_list_merge(inmates, &cell->bios);
193 } 201 }
194
195 mempool_free(cell, prison->cell_pool);
196} 202}
197 203
198void dm_cell_release(struct dm_bio_prison_cell *cell, struct bio_list *bios) 204void dm_cell_release(struct dm_bio_prison *prison,
205 struct dm_bio_prison_cell *cell,
206 struct bio_list *bios)
199{ 207{
200 unsigned long flags; 208 unsigned long flags;
201 struct dm_bio_prison *prison = cell->prison;
202 209
203 spin_lock_irqsave(&prison->lock, flags); 210 spin_lock_irqsave(&prison->lock, flags);
204 __cell_release(cell, bios); 211 __cell_release(cell, bios);
@@ -209,20 +216,18 @@ EXPORT_SYMBOL_GPL(dm_cell_release);
209/* 216/*
210 * Sometimes we don't want the holder, just the additional bios. 217 * Sometimes we don't want the holder, just the additional bios.
211 */ 218 */
212static void __cell_release_no_holder(struct dm_bio_prison_cell *cell, struct bio_list *inmates) 219static void __cell_release_no_holder(struct dm_bio_prison_cell *cell,
220 struct bio_list *inmates)
213{ 221{
214 struct dm_bio_prison *prison = cell->prison;
215
216 hlist_del(&cell->list); 222 hlist_del(&cell->list);
217 bio_list_merge(inmates, &cell->bios); 223 bio_list_merge(inmates, &cell->bios);
218
219 mempool_free(cell, prison->cell_pool);
220} 224}
221 225
222void dm_cell_release_no_holder(struct dm_bio_prison_cell *cell, struct bio_list *inmates) 226void dm_cell_release_no_holder(struct dm_bio_prison *prison,
227 struct dm_bio_prison_cell *cell,
228 struct bio_list *inmates)
223{ 229{
224 unsigned long flags; 230 unsigned long flags;
225 struct dm_bio_prison *prison = cell->prison;
226 231
227 spin_lock_irqsave(&prison->lock, flags); 232 spin_lock_irqsave(&prison->lock, flags);
228 __cell_release_no_holder(cell, inmates); 233 __cell_release_no_holder(cell, inmates);
@@ -230,9 +235,9 @@ void dm_cell_release_no_holder(struct dm_bio_prison_cell *cell, struct bio_list
230} 235}
231EXPORT_SYMBOL_GPL(dm_cell_release_no_holder); 236EXPORT_SYMBOL_GPL(dm_cell_release_no_holder);
232 237
233void dm_cell_error(struct dm_bio_prison_cell *cell) 238void dm_cell_error(struct dm_bio_prison *prison,
239 struct dm_bio_prison_cell *cell)
234{ 240{
235 struct dm_bio_prison *prison = cell->prison;
236 struct bio_list bios; 241 struct bio_list bios;
237 struct bio *bio; 242 struct bio *bio;
238 unsigned long flags; 243 unsigned long flags;