Commit 025b96853fe0bdc977d88b4242ca5e1f19d9bb66
Committed by
Alasdair G Kergon
1 parent
6beca5eb6e
Exists in
master
and in
20 other branches
dm thin: remove cells from stack
This patch takes advantage of the new bio-prison interface where the memory is now passed in rather than using a mempool in bio-prison. This allows the map function to avoid performing potentially-blocking allocations that could lead to deadlocks: We want to avoid the cell allocation that is done in bio_detain. (The potential for mempool deadlocks still remains in other functions that use bio_detain.) Signed-off-by: Joe Thornber <ejt@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Showing 3 changed files with 43 additions and 23 deletions Side-by-side Diff
drivers/md/dm-bio-prison.c
... | ... | @@ -14,13 +14,6 @@ |
14 | 14 | |
15 | 15 | /*----------------------------------------------------------------*/ |
16 | 16 | |
17 | -struct dm_bio_prison_cell { | |
18 | - struct hlist_node list; | |
19 | - struct dm_cell_key key; | |
20 | - struct bio *holder; | |
21 | - struct bio_list bios; | |
22 | -}; | |
23 | - | |
24 | 17 | struct dm_bio_prison { |
25 | 18 | spinlock_t lock; |
26 | 19 | mempool_t *cell_pool; |
drivers/md/dm-bio-prison.h
... | ... | @@ -22,13 +22,23 @@ |
22 | 22 | * subsequently unlocked the bios become available. |
23 | 23 | */ |
24 | 24 | struct dm_bio_prison; |
25 | -struct dm_bio_prison_cell; | |
26 | 25 | |
27 | 26 | /* FIXME: this needs to be more abstract */ |
28 | 27 | struct dm_cell_key { |
29 | 28 | int virtual; |
30 | 29 | dm_thin_id dev; |
31 | 30 | dm_block_t block; |
31 | +}; | |
32 | + | |
33 | +/* | |
34 | + * Treat this as opaque, only in header so callers can manage allocation | |
35 | + * themselves. | |
36 | + */ | |
37 | +struct dm_bio_prison_cell { | |
38 | + struct hlist_node list; | |
39 | + struct dm_cell_key key; | |
40 | + struct bio *holder; | |
41 | + struct bio_list bios; | |
32 | 42 | }; |
33 | 43 | |
34 | 44 | struct dm_bio_prison *dm_bio_prison_create(unsigned nr_cells); |
drivers/md/dm-thin.c
... | ... | @@ -229,6 +229,17 @@ |
229 | 229 | |
230 | 230 | /*----------------------------------------------------------------*/ |
231 | 231 | |
232 | +/* | |
233 | + * wake_worker() is used when new work is queued and when pool_resume is | |
234 | + * ready to continue deferred IO processing. | |
235 | + */ | |
236 | +static void wake_worker(struct pool *pool) | |
237 | +{ | |
238 | + queue_work(pool->wq, &pool->worker); | |
239 | +} | |
240 | + | |
241 | +/*----------------------------------------------------------------*/ | |
242 | + | |
232 | 243 | static int bio_detain(struct pool *pool, struct dm_cell_key *key, struct bio *bio, |
233 | 244 | struct dm_bio_prison_cell **cell_result) |
234 | 245 | { |
... | ... | @@ -268,6 +279,19 @@ |
268 | 279 | dm_bio_prison_free_cell(pool->prison, cell); |
269 | 280 | } |
270 | 281 | |
282 | +static void cell_defer_no_holder_no_free(struct thin_c *tc, | |
283 | + struct dm_bio_prison_cell *cell) | |
284 | +{ | |
285 | + struct pool *pool = tc->pool; | |
286 | + unsigned long flags; | |
287 | + | |
288 | + spin_lock_irqsave(&pool->lock, flags); | |
289 | + dm_cell_release_no_holder(pool->prison, cell, &pool->deferred_bios); | |
290 | + spin_unlock_irqrestore(&pool->lock, flags); | |
291 | + | |
292 | + wake_worker(pool); | |
293 | +} | |
294 | + | |
271 | 295 | static void cell_error(struct pool *pool, |
272 | 296 | struct dm_bio_prison_cell *cell) |
273 | 297 | { |
... | ... | @@ -477,15 +501,6 @@ |
477 | 501 | issue(tc, bio); |
478 | 502 | } |
479 | 503 | |
480 | -/* | |
481 | - * wake_worker() is used when new work is queued and when pool_resume is | |
482 | - * ready to continue deferred IO processing. | |
483 | - */ | |
484 | -static void wake_worker(struct pool *pool) | |
485 | -{ | |
486 | - queue_work(pool->wq, &pool->worker); | |
487 | -} | |
488 | - | |
489 | 504 | /*----------------------------------------------------------------*/ |
490 | 505 | |
491 | 506 | /* |
... | ... | @@ -601,6 +616,7 @@ |
601 | 616 | list_del(&m->list); |
602 | 617 | mempool_free(m, m->tc->pool->mapping_pool); |
603 | 618 | } |
619 | + | |
604 | 620 | static void process_prepared_mapping(struct dm_thin_new_mapping *m) |
605 | 621 | { |
606 | 622 | struct thin_c *tc = m->tc; |
... | ... | @@ -1438,7 +1454,8 @@ |
1438 | 1454 | dm_block_t block = get_bio_block(tc, bio); |
1439 | 1455 | struct dm_thin_device *td = tc->td; |
1440 | 1456 | struct dm_thin_lookup_result result; |
1441 | - struct dm_bio_prison_cell *cell1, *cell2; | |
1457 | + struct dm_bio_prison_cell cell1, cell2; | |
1458 | + struct dm_bio_prison_cell *cell_result; | |
1442 | 1459 | struct dm_cell_key key; |
1443 | 1460 | |
1444 | 1461 | thin_hook_bio(tc, bio); |
1445 | 1462 | |
1446 | 1463 | |
... | ... | @@ -1480,18 +1497,18 @@ |
1480 | 1497 | } |
1481 | 1498 | |
1482 | 1499 | build_virtual_key(tc->td, block, &key); |
1483 | - if (bio_detain(tc->pool, &key, bio, &cell1)) | |
1500 | + if (dm_bio_detain(tc->pool->prison, &key, bio, &cell1, &cell_result)) | |
1484 | 1501 | return DM_MAPIO_SUBMITTED; |
1485 | 1502 | |
1486 | 1503 | build_data_key(tc->td, result.block, &key); |
1487 | - if (bio_detain(tc->pool, &key, bio, &cell2)) { | |
1488 | - cell_defer_no_holder(tc, cell1); | |
1504 | + if (dm_bio_detain(tc->pool->prison, &key, bio, &cell2, &cell_result)) { | |
1505 | + cell_defer_no_holder_no_free(tc, &cell1); | |
1489 | 1506 | return DM_MAPIO_SUBMITTED; |
1490 | 1507 | } |
1491 | 1508 | |
1492 | 1509 | inc_all_io_entry(tc->pool, bio); |
1493 | - cell_defer_no_holder(tc, cell2); | |
1494 | - cell_defer_no_holder(tc, cell1); | |
1510 | + cell_defer_no_holder_no_free(tc, &cell2); | |
1511 | + cell_defer_no_holder_no_free(tc, &cell1); | |
1495 | 1512 | |
1496 | 1513 | remap(tc, bio, result.block); |
1497 | 1514 | return DM_MAPIO_REMAPPED; |