aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/md/dm-raid1.c25
-rw-r--r--include/linux/dm-dirty-log.h10
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
121int dm_dirty_log_type_register(struct dm_dirty_log_type *type); 131int dm_dirty_log_type_register(struct dm_dirty_log_type *type);