aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/md/dm-bio-prison.c14
-rw-r--r--drivers/md/dm-bio-prison.h8
-rw-r--r--drivers/md/dm-thin.c90
3 files changed, 83 insertions, 29 deletions
diff --git a/drivers/md/dm-bio-prison.c b/drivers/md/dm-bio-prison.c
index 90a56625245a..bbe22a5dc06b 100644
--- a/drivers/md/dm-bio-prison.c
+++ b/drivers/md/dm-bio-prison.c
@@ -241,6 +241,20 @@ void dm_cell_error(struct dm_bio_prison *prison,
241} 241}
242EXPORT_SYMBOL_GPL(dm_cell_error); 242EXPORT_SYMBOL_GPL(dm_cell_error);
243 243
244void dm_cell_visit_release(struct dm_bio_prison *prison,
245 void (*visit_fn)(void *, struct dm_bio_prison_cell *),
246 void *context,
247 struct dm_bio_prison_cell *cell)
248{
249 unsigned long flags;
250
251 spin_lock_irqsave(&prison->lock, flags);
252 visit_fn(context, cell);
253 rb_erase(&cell->node, &prison->cells);
254 spin_unlock_irqrestore(&prison->lock, flags);
255}
256EXPORT_SYMBOL_GPL(dm_cell_visit_release);
257
244/*----------------------------------------------------------------*/ 258/*----------------------------------------------------------------*/
245 259
246#define DEFERRED_SET_SIZE 64 260#define DEFERRED_SET_SIZE 64
diff --git a/drivers/md/dm-bio-prison.h b/drivers/md/dm-bio-prison.h
index c0cddb118582..b03988667740 100644
--- a/drivers/md/dm-bio-prison.h
+++ b/drivers/md/dm-bio-prison.h
@@ -89,6 +89,14 @@ void dm_cell_release_no_holder(struct dm_bio_prison *prison,
89void dm_cell_error(struct dm_bio_prison *prison, 89void dm_cell_error(struct dm_bio_prison *prison,
90 struct dm_bio_prison_cell *cell, int error); 90 struct dm_bio_prison_cell *cell, int error);
91 91
92/*
93 * Visits the cell and then releases. Guarantees no new inmates are
94 * inserted between the visit and release.
95 */
96void dm_cell_visit_release(struct dm_bio_prison *prison,
97 void (*visit_fn)(void *, struct dm_bio_prison_cell *),
98 void *context, struct dm_bio_prison_cell *cell);
99
92/*----------------------------------------------------------------*/ 100/*----------------------------------------------------------------*/
93 101
94/* 102/*
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index 912d7f4d89d1..5036d4b3f368 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -343,6 +343,15 @@ static void cell_release(struct pool *pool,
343 dm_bio_prison_free_cell(pool->prison, cell); 343 dm_bio_prison_free_cell(pool->prison, cell);
344} 344}
345 345
346static void cell_visit_release(struct pool *pool,
347 void (*fn)(void *, struct dm_bio_prison_cell *),
348 void *context,
349 struct dm_bio_prison_cell *cell)
350{
351 dm_cell_visit_release(pool->prison, fn, context, cell);
352 dm_bio_prison_free_cell(pool->prison, cell);
353}
354
346static void cell_release_no_holder(struct pool *pool, 355static void cell_release_no_holder(struct pool *pool,
347 struct dm_bio_prison_cell *cell, 356 struct dm_bio_prison_cell *cell,
348 struct bio_list *bios) 357 struct bio_list *bios)
@@ -697,55 +706,75 @@ static void overwrite_endio(struct bio *bio, int err)
697 */ 706 */
698 707
699/* 708/*
700 * This sends the bios in the cell back to the deferred_bios list. 709 * This sends the bios in the cell, except the original holder, back
710 * to the deferred_bios list.
701 */ 711 */
702static void cell_defer(struct thin_c *tc, struct dm_bio_prison_cell *cell) 712static void cell_defer_no_holder(struct thin_c *tc, struct dm_bio_prison_cell *cell)
703{ 713{
704 struct pool *pool = tc->pool; 714 struct pool *pool = tc->pool;
705 unsigned long flags; 715 unsigned long flags;
706 716
707 spin_lock_irqsave(&tc->lock, flags); 717 spin_lock_irqsave(&tc->lock, flags);
708 cell_release(pool, cell, &tc->deferred_bio_list); 718 cell_release_no_holder(pool, cell, &tc->deferred_bio_list);
709 spin_unlock_irqrestore(&tc->lock, flags); 719 spin_unlock_irqrestore(&tc->lock, flags);
710 720
711 wake_worker(pool); 721 wake_worker(pool);
712} 722}
713 723
714/* 724static void thin_defer_bio(struct thin_c *tc, struct bio *bio);
715 * Same as cell_defer above, except it omits the original holder of the cell. 725
716 */ 726struct remap_info {
717static void cell_defer_no_holder(struct thin_c *tc, struct dm_bio_prison_cell *cell) 727 struct thin_c *tc;
728 struct bio_list defer_bios;
729 struct bio_list issue_bios;
730};
731
732static void __inc_remap_and_issue_cell(void *context,
733 struct dm_bio_prison_cell *cell)
718{ 734{
719 struct pool *pool = tc->pool; 735 struct remap_info *info = context;
720 unsigned long flags; 736 struct bio *bio;
721 737
722 spin_lock_irqsave(&tc->lock, flags); 738 while ((bio = bio_list_pop(&cell->bios))) {
723 cell_release_no_holder(pool, cell, &tc->deferred_bio_list); 739 if (bio->bi_rw & (REQ_DISCARD | REQ_FLUSH | REQ_FUA))
724 spin_unlock_irqrestore(&tc->lock, flags); 740 bio_list_add(&info->defer_bios, bio);
741 else {
742 inc_all_io_entry(info->tc->pool, bio);
725 743
726 wake_worker(pool); 744 /*
745 * We can't issue the bios with the bio prison lock
746 * held, so we add them to a list to issue on
747 * return from this function.
748 */
749 bio_list_add(&info->issue_bios, bio);
750 }
751 }
727} 752}
728 753
729static void thin_defer_bio(struct thin_c *tc, struct bio *bio);
730
731static void inc_remap_and_issue_cell(struct thin_c *tc, 754static void inc_remap_and_issue_cell(struct thin_c *tc,
732 struct dm_bio_prison_cell *cell, 755 struct dm_bio_prison_cell *cell,
733 dm_block_t block) 756 dm_block_t block)
734{ 757{
735 struct bio *bio; 758 struct bio *bio;
736 struct bio_list bios; 759 struct remap_info info;
737 760
738 bio_list_init(&bios); 761 info.tc = tc;
739 cell_release_no_holder(tc->pool, cell, &bios); 762 bio_list_init(&info.defer_bios);
763 bio_list_init(&info.issue_bios);
740 764
741 while ((bio = bio_list_pop(&bios))) { 765 /*
742 if (bio->bi_rw & (REQ_DISCARD | REQ_FLUSH | REQ_FUA)) 766 * We have to be careful to inc any bios we're about to issue
743 thin_defer_bio(tc, bio); 767 * before the cell is released, and avoid a race with new bios
744 else { 768 * being added to the cell.
745 inc_all_io_entry(tc->pool, bio); 769 */
746 remap_and_issue(tc, bio, block); 770 cell_visit_release(tc->pool, __inc_remap_and_issue_cell,
747 } 771 &info, cell);
748 } 772
773 while ((bio = bio_list_pop(&info.defer_bios)))
774 thin_defer_bio(tc, bio);
775
776 while ((bio = bio_list_pop(&info.issue_bios)))
777 remap_and_issue(info.tc, bio, block);
749} 778}
750 779
751static void process_prepared_mapping_fail(struct dm_thin_new_mapping *m) 780static void process_prepared_mapping_fail(struct dm_thin_new_mapping *m)
@@ -796,10 +825,13 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m)
796 * the bios in the cell. 825 * the bios in the cell.
797 */ 826 */
798 if (bio) { 827 if (bio) {
799 cell_defer_no_holder(tc, m->cell); 828 inc_remap_and_issue_cell(tc, m->cell, m->data_block);
800 bio_endio(bio, 0); 829 bio_endio(bio, 0);
801 } else 830 } else {
802 cell_defer(tc, m->cell); 831 inc_all_io_entry(tc->pool, m->cell->holder);
832 remap_and_issue(tc, m->cell->holder, m->data_block);
833 inc_remap_and_issue_cell(tc, m->cell, m->data_block);
834 }
803 835
804out: 836out:
805 list_del(&m->list); 837 list_del(&m->list);