aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlasdair G Kergon <agk@redhat.com>2006-03-27 04:17:42 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-03-27 11:44:58 -0500
commiteccf081799be8d83852f183838bf26e1ca099db4 (patch)
treeff6e2fa87a149f1122e5f0f854bf1707e962f3b8
parente4ccde33de202fae1b1e2a940604ee9e295450d9 (diff)
[PATCH] device-mapper snapshot: fix origin_write pending_exception submission
Say you have several snapshots of the same origin and then you issue a write to some place in the origin for the first time. Before the device-mapper snapshot target lets the write go through to the underlying device, it needs to make a copy of the data that is about to be overwritten. Each snapshot is independent, so it makes one copy for each snapshot. __origin_write() loops through each snapshot and checks to see whether a copy is needed for that snapshot. (A copy is only needed the first time that data changes.) If a copy is needed, the code allocates a 'pending_exception' structure holding the details. It links these together for all the snapshots, then works its way through this list and submits the copying requests to the kcopyd thread by calling start_copy(). When each request is completed, the original pending_exception structure gets freed in pending_complete(). If you're very unlucky, this structure can get freed *before* the submission process has finished walking the list. This patch: 1) Creates a new temporary list pe_queue to hold the pending exception structures; 2) Does all the bookkeeping up-front, then walks through the new list safely and calls start_copy() for each pending_exception that needed it; 3) Avoids attempting to add pe->siblings to the list if it's already connected. [NB This does not fix all the races in this code. More patches will follow.] 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.c41
1 files changed, 19 insertions, 22 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 7401540086df..874f145431d8 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -49,6 +49,11 @@ struct pending_exception {
49 struct bio_list snapshot_bios; 49 struct bio_list snapshot_bios;
50 50
51 /* 51 /*
52 * Short-term queue of pending exceptions prior to submission.
53 */
54 struct list_head list;
55
56 /*
52 * Other pending_exceptions that are processing this 57 * Other pending_exceptions that are processing this
53 * chunk. When this list is empty, we know we can 58 * chunk. When this list is empty, we know we can
54 * complete the origins. 59 * complete the origins.
@@ -930,8 +935,9 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
930 int r = 1, first = 1; 935 int r = 1, first = 1;
931 struct dm_snapshot *snap; 936 struct dm_snapshot *snap;
932 struct exception *e; 937 struct exception *e;
933 struct pending_exception *pe, *last = NULL; 938 struct pending_exception *pe, *next_pe, *last = NULL;
934 chunk_t chunk; 939 chunk_t chunk;
940 LIST_HEAD(pe_queue);
935 941
936 /* Do all the snapshots on this origin */ 942 /* Do all the snapshots on this origin */
937 list_for_each_entry (snap, snapshots, list) { 943 list_for_each_entry (snap, snapshots, list) {
@@ -965,12 +971,19 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
965 snap->valid = 0; 971 snap->valid = 0;
966 972
967 } else { 973 } else {
968 if (last) 974 if (first) {
975 bio_list_add(&pe->origin_bios, bio);
976 r = 0;
977 first = 0;
978 }
979 if (last && list_empty(&pe->siblings))
969 list_merge(&pe->siblings, 980 list_merge(&pe->siblings,
970 &last->siblings); 981 &last->siblings);
971 982 if (!pe->started) {
983 pe->started = 1;
984 list_add_tail(&pe->list, &pe_queue);
985 }
972 last = pe; 986 last = pe;
973 r = 0;
974 } 987 }
975 } 988 }
976 989
@@ -980,24 +993,8 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
980 /* 993 /*
981 * Now that we have a complete pe list we can start the copying. 994 * Now that we have a complete pe list we can start the copying.
982 */ 995 */
983 if (last) { 996 list_for_each_entry_safe(pe, next_pe, &pe_queue, list)
984 pe = last; 997 start_copy(pe);
985 do {
986 down_write(&pe->snap->lock);
987 if (first)
988 bio_list_add(&pe->origin_bios, bio);
989 if (!pe->started) {
990 pe->started = 1;
991 up_write(&pe->snap->lock);
992 start_copy(pe);
993 } else
994 up_write(&pe->snap->lock);
995 first = 0;
996 pe = list_entry(pe->siblings.next,
997 struct pending_exception, siblings);
998
999 } while (pe != last);
1000 }
1001 998
1002 return r; 999 return r;
1003} 1000}