aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlasdair G Kergon <agk@redhat.com>2006-10-03 04:15:30 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-03 11:04:14 -0400
commit4b832e8de22726206eb886f6dbff47a0f3fe5168 (patch)
tree279cf60137cc08f4f4ae17f04940d69d68262b10
parentca3a931fd33b841cbcc5932f8eac7c43e0909242 (diff)
[PATCH] dm snapshot: tidy pe ref counting
Rename sibling_count to ref_count and introduce get and put functions. Signed-off-by: Alasdair G Kergon <agk@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/md/dm-snap.c83
1 files changed, 48 insertions, 35 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 1c6485404db4..638c8d90da0e 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -59,7 +59,7 @@ struct pending_exception {
59 59
60 /* 60 /*
61 * The primary pending_exception is the one that holds 61 * The primary pending_exception is the one that holds
62 * the sibling_count and the list of origin_bios for a 62 * the ref_count and the list of origin_bios for a
63 * group of pending_exceptions. It is always last to get freed. 63 * group of pending_exceptions. It is always last to get freed.
64 * These fields get set up when writing to the origin. 64 * These fields get set up when writing to the origin.
65 */ 65 */
@@ -72,7 +72,7 @@ struct pending_exception {
72 * the sibling concerned and not pe->primary_pe->snap->lock unless 72 * the sibling concerned and not pe->primary_pe->snap->lock unless
73 * they are the same. 73 * they are the same.
74 */ 74 */
75 atomic_t sibling_count; 75 atomic_t ref_count;
76 76
77 /* Pointer back to snapshot context */ 77 /* Pointer back to snapshot context */
78 struct dm_snapshot *snap; 78 struct dm_snapshot *snap;
@@ -653,10 +653,46 @@ static void __invalidate_snapshot(struct dm_snapshot *s,
653 dm_table_event(s->table); 653 dm_table_event(s->table);
654} 654}
655 655
656static void get_pending_exception(struct pending_exception *pe)
657{
658 atomic_inc(&pe->ref_count);
659}
660
661static struct bio *put_pending_exception(struct pending_exception *pe)
662{
663 struct pending_exception *primary_pe;
664 struct bio *origin_bios = NULL;
665
666 primary_pe = pe->primary_pe;
667
668 /*
669 * If this pe is involved in a write to the origin and
670 * it is the last sibling to complete then release
671 * the bios for the original write to the origin.
672 */
673 if (primary_pe &&
674 atomic_dec_and_test(&primary_pe->ref_count))
675 origin_bios = bio_list_get(&primary_pe->origin_bios);
676
677 /*
678 * Free the pe if it's not linked to an origin write or if
679 * it's not itself a primary pe.
680 */
681 if (!primary_pe || primary_pe != pe)
682 free_pending_exception(pe);
683
684 /*
685 * Free the primary pe if nothing references it.
686 */
687 if (primary_pe && !atomic_read(&primary_pe->ref_count))
688 free_pending_exception(primary_pe);
689
690 return origin_bios;
691}
692
656static void pending_complete(struct pending_exception *pe, int success) 693static void pending_complete(struct pending_exception *pe, int success)
657{ 694{
658 struct exception *e; 695 struct exception *e;
659 struct pending_exception *primary_pe;
660 struct dm_snapshot *s = pe->snap; 696 struct dm_snapshot *s = pe->snap;
661 struct bio *origin_bios = NULL; 697 struct bio *origin_bios = NULL;
662 struct bio *snapshot_bios = NULL; 698 struct bio *snapshot_bios = NULL;
@@ -695,30 +731,7 @@ static void pending_complete(struct pending_exception *pe, int success)
695 731
696 out: 732 out:
697 snapshot_bios = bio_list_get(&pe->snapshot_bios); 733 snapshot_bios = bio_list_get(&pe->snapshot_bios);
698 734 origin_bios = put_pending_exception(pe);
699 primary_pe = pe->primary_pe;
700
701 /*
702 * If this pe is involved in a write to the origin and
703 * it is the last sibling to complete then release
704 * the bios for the original write to the origin.
705 */
706 if (primary_pe &&
707 atomic_dec_and_test(&primary_pe->sibling_count))
708 origin_bios = bio_list_get(&primary_pe->origin_bios);
709
710 /*
711 * Free the pe if it's not linked to an origin write or if
712 * it's not itself a primary pe.
713 */
714 if (!primary_pe || primary_pe != pe)
715 free_pending_exception(pe);
716
717 /*
718 * Free the primary pe if nothing references it.
719 */
720 if (primary_pe && !atomic_read(&primary_pe->sibling_count))
721 free_pending_exception(primary_pe);
722 735
723 up_write(&s->lock); 736 up_write(&s->lock);
724 737
@@ -829,7 +842,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio)
829 bio_list_init(&pe->origin_bios); 842 bio_list_init(&pe->origin_bios);
830 bio_list_init(&pe->snapshot_bios); 843 bio_list_init(&pe->snapshot_bios);
831 pe->primary_pe = NULL; 844 pe->primary_pe = NULL;
832 atomic_set(&pe->sibling_count, 1); 845 atomic_set(&pe->ref_count, 0);
833 pe->snap = s; 846 pe->snap = s;
834 pe->started = 0; 847 pe->started = 0;
835 848
@@ -838,6 +851,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio)
838 return NULL; 851 return NULL;
839 } 852 }
840 853
854 get_pending_exception(pe);
841 insert_exception(&s->pending, &pe->e); 855 insert_exception(&s->pending, &pe->e);
842 856
843 out: 857 out:
@@ -1012,7 +1026,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
1012 * is already remapped in this snapshot 1026 * is already remapped in this snapshot
1013 * and trigger an exception if not. 1027 * and trigger an exception if not.
1014 * 1028 *
1015 * sibling_count is initialised to 1 so pending_complete() 1029 * ref_count is initialised to 1 so pending_complete()
1016 * won't destroy the primary_pe while we're inside this loop. 1030 * won't destroy the primary_pe while we're inside this loop.
1017 */ 1031 */
1018 e = lookup_exception(&snap->complete, chunk); 1032 e = lookup_exception(&snap->complete, chunk);
@@ -1043,8 +1057,8 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
1043 } 1057 }
1044 1058
1045 if (!pe->primary_pe) { 1059 if (!pe->primary_pe) {
1046 atomic_inc(&primary_pe->sibling_count);
1047 pe->primary_pe = primary_pe; 1060 pe->primary_pe = primary_pe;
1061 get_pending_exception(primary_pe);
1048 } 1062 }
1049 1063
1050 if (!pe->started) { 1064 if (!pe->started) {
@@ -1057,20 +1071,20 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
1057 } 1071 }
1058 1072
1059 if (!primary_pe) 1073 if (!primary_pe)
1060 goto out; 1074 return r;
1061 1075
1062 /* 1076 /*
1063 * If this is the first time we're processing this chunk and 1077 * If this is the first time we're processing this chunk and
1064 * sibling_count is now 1 it means all the pending exceptions 1078 * ref_count is now 1 it means all the pending exceptions
1065 * got completed while we were in the loop above, so it falls to 1079 * got completed while we were in the loop above, so it falls to
1066 * us here to remove the primary_pe and submit any origin_bios. 1080 * us here to remove the primary_pe and submit any origin_bios.
1067 */ 1081 */
1068 1082
1069 if (first && atomic_dec_and_test(&primary_pe->sibling_count)) { 1083 if (first && atomic_dec_and_test(&primary_pe->ref_count)) {
1070 flush_bios(bio_list_get(&primary_pe->origin_bios)); 1084 flush_bios(bio_list_get(&primary_pe->origin_bios));
1071 free_pending_exception(primary_pe); 1085 free_pending_exception(primary_pe);
1072 /* If we got here, pe_queue is necessarily empty. */ 1086 /* If we got here, pe_queue is necessarily empty. */
1073 goto out; 1087 return r;
1074 } 1088 }
1075 1089
1076 /* 1090 /*
@@ -1079,7 +1093,6 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
1079 list_for_each_entry_safe(pe, next_pe, &pe_queue, list) 1093 list_for_each_entry_safe(pe, next_pe, &pe_queue, list)
1080 start_copy(pe); 1094 start_copy(pe);
1081 1095
1082 out:
1083 return r; 1096 return r;
1084} 1097}
1085 1098