Skip to content

Commit 6f94a4c

Browse files
jthornberkergon
authored andcommitted
dm thin: fix stacked bi_next usage
Avoid using the bi_next field for the holder of a cell when deferring bios because a stacked device below might change it. Store the holder in a new field in struct cell instead. When a cell is created, the bio that triggered creation (the holder) was added to the same bio list as subsequent bios. In some cases we pass this holder bio directly to devices underneath. If those devices use the bi_next field there will be trouble... This also simplifies some code that had to work out which bio was the holder. Signed-off-by: Joe Thornber <[email protected]> Cc: [email protected] Signed-off-by: Mike Snitzer <[email protected]> Signed-off-by: Alasdair G Kergon <[email protected]>
1 parent 72c6e7a commit 6f94a4c

File tree

1 file changed

+73
-51
lines changed

1 file changed

+73
-51
lines changed

drivers/md/dm-thin.c

Lines changed: 73 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ struct cell {
124124
struct hlist_node list;
125125
struct bio_prison *prison;
126126
struct cell_key key;
127-
unsigned count;
127+
struct bio *holder;
128128
struct bio_list bios;
129129
};
130130

@@ -220,55 +220,60 @@ static struct cell *__search_bucket(struct hlist_head *bucket,
220220
* This may block if a new cell needs allocating. You must ensure that
221221
* cells will be unlocked even if the calling thread is blocked.
222222
*
223-
* Returns the number of entries in the cell prior to the new addition
224-
* or < 0 on failure.
223+
* Returns 1 if the cell was already held, 0 if @inmate is the new holder.
225224
*/
226225
static int bio_detain(struct bio_prison *prison, struct cell_key *key,
227226
struct bio *inmate, struct cell **ref)
228227
{
229-
int r;
228+
int r = 1;
230229
unsigned long flags;
231230
uint32_t hash = hash_key(prison, key);
232-
struct cell *uninitialized_var(cell), *cell2 = NULL;
231+
struct cell *cell, *cell2;
233232

234233
BUG_ON(hash > prison->nr_buckets);
235234

236235
spin_lock_irqsave(&prison->lock, flags);
236+
237237
cell = __search_bucket(prison->cells + hash, key);
238+
if (cell) {
239+
bio_list_add(&cell->bios, inmate);
240+
goto out;
241+
}
238242

239-
if (!cell) {
240-
/*
241-
* Allocate a new cell
242-
*/
243-
spin_unlock_irqrestore(&prison->lock, flags);
244-
cell2 = mempool_alloc(prison->cell_pool, GFP_NOIO);
245-
spin_lock_irqsave(&prison->lock, flags);
243+
/*
244+
* Allocate a new cell
245+
*/
246+
spin_unlock_irqrestore(&prison->lock, flags);
247+
cell2 = mempool_alloc(prison->cell_pool, GFP_NOIO);
248+
spin_lock_irqsave(&prison->lock, flags);
246249

247-
/*
248-
* We've been unlocked, so we have to double check that
249-
* nobody else has inserted this cell in the meantime.
250-
*/
251-
cell = __search_bucket(prison->cells + hash, key);
250+
/*
251+
* We've been unlocked, so we have to double check that
252+
* nobody else has inserted this cell in the meantime.
253+
*/
254+
cell = __search_bucket(prison->cells + hash, key);
255+
if (cell) {
256+
mempool_free(cell2, prison->cell_pool);
257+
bio_list_add(&cell->bios, inmate);
258+
goto out;
259+
}
260+
261+
/*
262+
* Use new cell.
263+
*/
264+
cell = cell2;
252265

253-
if (!cell) {
254-
cell = cell2;
255-
cell2 = NULL;
266+
cell->prison = prison;
267+
memcpy(&cell->key, key, sizeof(cell->key));
268+
cell->holder = inmate;
269+
bio_list_init(&cell->bios);
270+
hlist_add_head(&cell->list, prison->cells + hash);
256271

257-
cell->prison = prison;
258-
memcpy(&cell->key, key, sizeof(cell->key));
259-
cell->count = 0;
260-
bio_list_init(&cell->bios);
261-
hlist_add_head(&cell->list, prison->cells + hash);
262-
}
263-
}
272+
r = 0;
264273

265-
r = cell->count++;
266-
bio_list_add(&cell->bios, inmate);
274+
out:
267275
spin_unlock_irqrestore(&prison->lock, flags);
268276

269-
if (cell2)
270-
mempool_free(cell2, prison->cell_pool);
271-
272277
*ref = cell;
273278

274279
return r;
@@ -283,8 +288,8 @@ static void __cell_release(struct cell *cell, struct bio_list *inmates)
283288

284289
hlist_del(&cell->list);
285290

286-
if (inmates)
287-
bio_list_merge(inmates, &cell->bios);
291+
bio_list_add(inmates, cell->holder);
292+
bio_list_merge(inmates, &cell->bios);
288293

289294
mempool_free(cell, prison->cell_pool);
290295
}
@@ -305,22 +310,44 @@ static void cell_release(struct cell *cell, struct bio_list *bios)
305310
* bio may be in the cell. This function releases the cell, and also does
306311
* a sanity check.
307312
*/
313+
static void __cell_release_singleton(struct cell *cell, struct bio *bio)
314+
{
315+
hlist_del(&cell->list);
316+
BUG_ON(cell->holder != bio);
317+
BUG_ON(!bio_list_empty(&cell->bios));
318+
}
319+
308320
static void cell_release_singleton(struct cell *cell, struct bio *bio)
309321
{
310-
struct bio_prison *prison = cell->prison;
311-
struct bio_list bios;
312-
struct bio *b;
313322
unsigned long flags;
314-
315-
bio_list_init(&bios);
323+
struct bio_prison *prison = cell->prison;
316324

317325
spin_lock_irqsave(&prison->lock, flags);
318-
__cell_release(cell, &bios);
326+
__cell_release_singleton(cell, bio);
319327
spin_unlock_irqrestore(&prison->lock, flags);
328+
}
329+
330+
/*
331+
* Sometimes we don't want the holder, just the additional bios.
332+
*/
333+
static void __cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
334+
{
335+
struct bio_prison *prison = cell->prison;
320336

321-
b = bio_list_pop(&bios);
322-
BUG_ON(b != bio);
323-
BUG_ON(!bio_list_empty(&bios));
337+
hlist_del(&cell->list);
338+
bio_list_merge(inmates, &cell->bios);
339+
340+
mempool_free(cell, prison->cell_pool);
341+
}
342+
343+
static void cell_release_no_holder(struct cell *cell, struct bio_list *inmates)
344+
{
345+
unsigned long flags;
346+
struct bio_prison *prison = cell->prison;
347+
348+
spin_lock_irqsave(&prison->lock, flags);
349+
__cell_release_no_holder(cell, inmates);
350+
spin_unlock_irqrestore(&prison->lock, flags);
324351
}
325352

326353
static void cell_error(struct cell *cell)
@@ -800,21 +827,16 @@ static void cell_defer(struct thin_c *tc, struct cell *cell,
800827
* Same as cell_defer above, except it omits one particular detainee,
801828
* a write bio that covers the block and has already been processed.
802829
*/
803-
static void cell_defer_except(struct thin_c *tc, struct cell *cell,
804-
struct bio *exception)
830+
static void cell_defer_except(struct thin_c *tc, struct cell *cell)
805831
{
806832
struct bio_list bios;
807-
struct bio *bio;
808833
struct pool *pool = tc->pool;
809834
unsigned long flags;
810835

811836
bio_list_init(&bios);
812-
cell_release(cell, &bios);
813837

814838
spin_lock_irqsave(&pool->lock, flags);
815-
while ((bio = bio_list_pop(&bios)))
816-
if (bio != exception)
817-
bio_list_add(&pool->deferred_bios, bio);
839+
cell_release_no_holder(cell, &pool->deferred_bios);
818840
spin_unlock_irqrestore(&pool->lock, flags);
819841

820842
wake_worker(pool);
@@ -854,7 +876,7 @@ static void process_prepared_mapping(struct new_mapping *m)
854876
* the bios in the cell.
855877
*/
856878
if (bio) {
857-
cell_defer_except(tc, m->cell, bio);
879+
cell_defer_except(tc, m->cell);
858880
bio_endio(bio, 0);
859881
} else
860882
cell_defer(tc, m->cell, m->data_block);

0 commit comments

Comments
 (0)