diff options
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/dm-snap.c | 76 |
1 files changed, 30 insertions, 46 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index c5449f2504b6..d92980177b5c 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -609,26 +609,6 @@ static void error_bios(struct bio *bio) | |||
609 | } | 609 | } |
610 | } | 610 | } |
611 | 611 | ||
612 | static inline void error_snapshot_bios(struct pending_exception *pe) | ||
613 | { | ||
614 | error_bios(bio_list_get(&pe->snapshot_bios)); | ||
615 | } | ||
616 | |||
617 | static struct bio *__flush_bios(struct pending_exception *pe) | ||
618 | { | ||
619 | /* | ||
620 | * If this pe is involved in a write to the origin and | ||
621 | * it is the last sibling to complete then release | ||
622 | * the bios for the original write to the origin. | ||
623 | */ | ||
624 | |||
625 | if (pe->primary_pe && | ||
626 | atomic_dec_and_test(&pe->primary_pe->sibling_count)) | ||
627 | return bio_list_get(&pe->primary_pe->origin_bios); | ||
628 | |||
629 | return NULL; | ||
630 | } | ||
631 | |||
632 | static void __invalidate_snapshot(struct dm_snapshot *s, | 612 | static void __invalidate_snapshot(struct dm_snapshot *s, |
633 | struct pending_exception *pe, int err) | 613 | struct pending_exception *pe, int err) |
634 | { | 614 | { |
@@ -656,16 +636,15 @@ static void pending_complete(struct pending_exception *pe, int success) | |||
656 | struct exception *e; | 636 | struct exception *e; |
657 | struct pending_exception *primary_pe; | 637 | struct pending_exception *primary_pe; |
658 | struct dm_snapshot *s = pe->snap; | 638 | struct dm_snapshot *s = pe->snap; |
659 | struct bio *flush = NULL; | 639 | struct bio *origin_bios = NULL; |
640 | struct bio *snapshot_bios = NULL; | ||
641 | int error = 0; | ||
660 | 642 | ||
661 | if (!success) { | 643 | if (!success) { |
662 | /* Read/write error - snapshot is unusable */ | 644 | /* Read/write error - snapshot is unusable */ |
663 | down_write(&s->lock); | 645 | down_write(&s->lock); |
664 | __invalidate_snapshot(s, pe, -EIO); | 646 | __invalidate_snapshot(s, pe, -EIO); |
665 | flush = __flush_bios(pe); | 647 | error = 1; |
666 | up_write(&s->lock); | ||
667 | |||
668 | error_snapshot_bios(pe); | ||
669 | goto out; | 648 | goto out; |
670 | } | 649 | } |
671 | 650 | ||
@@ -673,42 +652,40 @@ static void pending_complete(struct pending_exception *pe, int success) | |||
673 | if (!e) { | 652 | if (!e) { |
674 | down_write(&s->lock); | 653 | down_write(&s->lock); |
675 | __invalidate_snapshot(s, pe, -ENOMEM); | 654 | __invalidate_snapshot(s, pe, -ENOMEM); |
676 | flush = __flush_bios(pe); | 655 | error = 1; |
677 | up_write(&s->lock); | ||
678 | |||
679 | error_snapshot_bios(pe); | ||
680 | goto out; | 656 | goto out; |
681 | } | 657 | } |
682 | *e = pe->e; | 658 | *e = pe->e; |
683 | 659 | ||
684 | /* | ||
685 | * Add a proper exception, and remove the | ||
686 | * in-flight exception from the list. | ||
687 | */ | ||
688 | down_write(&s->lock); | 660 | down_write(&s->lock); |
689 | if (!s->valid) { | 661 | if (!s->valid) { |
690 | flush = __flush_bios(pe); | ||
691 | up_write(&s->lock); | ||
692 | |||
693 | free_exception(e); | 662 | free_exception(e); |
694 | 663 | error = 1; | |
695 | error_snapshot_bios(pe); | ||
696 | goto out; | 664 | goto out; |
697 | } | 665 | } |
698 | 666 | ||
667 | /* | ||
668 | * Add a proper exception, and remove the | ||
669 | * in-flight exception from the list. | ||
670 | */ | ||
699 | insert_exception(&s->complete, e); | 671 | insert_exception(&s->complete, e); |
700 | remove_exception(&pe->e); | 672 | remove_exception(&pe->e); |
701 | flush = __flush_bios(pe); | ||
702 | |||
703 | up_write(&s->lock); | ||
704 | |||
705 | /* Submit any pending write bios */ | ||
706 | flush_bios(bio_list_get(&pe->snapshot_bios)); | ||
707 | 673 | ||
708 | out: | 674 | out: |
675 | snapshot_bios = bio_list_get(&pe->snapshot_bios); | ||
676 | |||
709 | primary_pe = pe->primary_pe; | 677 | primary_pe = pe->primary_pe; |
710 | 678 | ||
711 | /* | 679 | /* |
680 | * If this pe is involved in a write to the origin and | ||
681 | * it is the last sibling to complete then release | ||
682 | * the bios for the original write to the origin. | ||
683 | */ | ||
684 | if (primary_pe && | ||
685 | atomic_dec_and_test(&primary_pe->sibling_count)) | ||
686 | origin_bios = bio_list_get(&primary_pe->origin_bios); | ||
687 | |||
688 | /* | ||
712 | * Free the pe if it's not linked to an origin write or if | 689 | * Free the pe if it's not linked to an origin write or if |
713 | * it's not itself a primary pe. | 690 | * it's not itself a primary pe. |
714 | */ | 691 | */ |
@@ -721,8 +698,15 @@ static void pending_complete(struct pending_exception *pe, int success) | |||
721 | if (primary_pe && !atomic_read(&primary_pe->sibling_count)) | 698 | if (primary_pe && !atomic_read(&primary_pe->sibling_count)) |
722 | free_pending_exception(primary_pe); | 699 | free_pending_exception(primary_pe); |
723 | 700 | ||
724 | if (flush) | 701 | up_write(&s->lock); |
725 | flush_bios(flush); | 702 | |
703 | /* Submit any pending write bios */ | ||
704 | if (error) | ||
705 | error_bios(snapshot_bios); | ||
706 | else | ||
707 | flush_bios(snapshot_bios); | ||
708 | |||
709 | flush_bios(origin_bios); | ||
726 | } | 710 | } |
727 | 711 | ||
728 | static void commit_callback(void *context, int success) | 712 | static void commit_callback(void *context, int success) |