diff options
-rw-r--r-- | drivers/md/dm-raid1.c | 25 | ||||
-rw-r--r-- | include/linux/dm-dirty-log.h | 10 |
2 files changed, 33 insertions, 2 deletions
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 62d594889ac3..536ef0bef154 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c | |||
@@ -588,6 +588,9 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) | |||
588 | int state; | 588 | int state; |
589 | struct bio *bio; | 589 | struct bio *bio; |
590 | struct bio_list sync, nosync, recover, *this_list = NULL; | 590 | struct bio_list sync, nosync, recover, *this_list = NULL; |
591 | struct bio_list requeue; | ||
592 | struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh); | ||
593 | region_t region; | ||
591 | 594 | ||
592 | if (!writes->head) | 595 | if (!writes->head) |
593 | return; | 596 | return; |
@@ -598,10 +601,18 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) | |||
598 | bio_list_init(&sync); | 601 | bio_list_init(&sync); |
599 | bio_list_init(&nosync); | 602 | bio_list_init(&nosync); |
600 | bio_list_init(&recover); | 603 | bio_list_init(&recover); |
604 | bio_list_init(&requeue); | ||
601 | 605 | ||
602 | while ((bio = bio_list_pop(writes))) { | 606 | while ((bio = bio_list_pop(writes))) { |
603 | state = dm_rh_get_state(ms->rh, | 607 | region = dm_rh_bio_to_region(ms->rh, bio); |
604 | dm_rh_bio_to_region(ms->rh, bio), 1); | 608 | |
609 | if (log->type->is_remote_recovering && | ||
610 | log->type->is_remote_recovering(log, region)) { | ||
611 | bio_list_add(&requeue, bio); | ||
612 | continue; | ||
613 | } | ||
614 | |||
615 | state = dm_rh_get_state(ms->rh, region, 1); | ||
605 | switch (state) { | 616 | switch (state) { |
606 | case DM_RH_CLEAN: | 617 | case DM_RH_CLEAN: |
607 | case DM_RH_DIRTY: | 618 | case DM_RH_DIRTY: |
@@ -621,6 +632,16 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) | |||
621 | } | 632 | } |
622 | 633 | ||
623 | /* | 634 | /* |
635 | * Add bios that are delayed due to remote recovery | ||
636 | * back on to the write queue | ||
637 | */ | ||
638 | if (unlikely(requeue.head)) { | ||
639 | spin_lock_irq(&ms->lock); | ||
640 | bio_list_merge(&ms->writes, &requeue); | ||
641 | spin_unlock_irq(&ms->lock); | ||
642 | } | ||
643 | |||
644 | /* | ||
624 | * Increment the pending counts for any regions that will | 645 | * Increment the pending counts for any regions that will |
625 | * be written to (writes to recover regions are going to | 646 | * be written to (writes to recover regions are going to |
626 | * be delayed). | 647 | * be delayed). |
diff --git a/include/linux/dm-dirty-log.h b/include/linux/dm-dirty-log.h index 727602b686d4..5e8b11d88f6f 100644 --- a/include/linux/dm-dirty-log.h +++ b/include/linux/dm-dirty-log.h | |||
@@ -116,6 +116,16 @@ struct dm_dirty_log_type { | |||
116 | */ | 116 | */ |
117 | int (*status)(struct dm_dirty_log *log, status_type_t status_type, | 117 | int (*status)(struct dm_dirty_log *log, status_type_t status_type, |
118 | char *result, unsigned maxlen); | 118 | char *result, unsigned maxlen); |
119 | |||
120 | /* | ||
121 | * is_remote_recovering is necessary for cluster mirroring. It provides | ||
122 | * a way to detect recovery on another node, so we aren't writing | ||
123 | * concurrently. This function is likely to block (when a cluster log | ||
124 | * is used). | ||
125 | * | ||
126 | * Returns: 0, 1 | ||
127 | */ | ||
128 | int (*is_remote_recovering)(struct dm_dirty_log *log, region_t region); | ||
119 | }; | 129 | }; |
120 | 130 | ||
121 | int dm_dirty_log_type_register(struct dm_dirty_log_type *type); | 131 | int dm_dirty_log_type_register(struct dm_dirty_log_type *type); |