aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2009-12-10 18:52:30 -0500
committerAlasdair G Kergon <agk@redhat.com>2009-12-10 18:52:30 -0500
commit515ad66cc4c82f210d726340349c8f7c1ec6b125 (patch)
treee6ae5591a7906f3ce9ae0fb0a62419acffcdcbcd /drivers
parentd698aa4500aa3ca9559142060caf0f79da998744 (diff)
dm snapshot: rework writing to origin
To track the completion of exceptions relating to the same location on the device, the current code selects one exception as primary_pe, links the other exceptions to it and uses reference counting to wait until all the reallocations are complete. It is considered too complicated to extend this code to handle the new snapshot-merge target, where sets of non-overlapping chunks would also need to become linked. Instead, a simpler (but less efficient) approach is taken. Bios are linked to one exception. When it completes, bios are simply retried, and if other related exceptions are still outstanding, they'll get queued again to wait for another one. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/dm-snap.c155
1 files changed, 49 insertions, 106 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 446827f98236..c01e0dafec3c 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -142,28 +142,6 @@ struct dm_snap_pending_exception {
142 struct bio_list origin_bios; 142 struct bio_list origin_bios;
143 struct bio_list snapshot_bios; 143 struct bio_list snapshot_bios;
144 144
145 /*
146 * Short-term queue of pending exceptions prior to submission.
147 */
148 struct list_head list;
149
150 /*
151 * The primary pending_exception is the one that holds
152 * the ref_count and the list of origin_bios for a
153 * group of pending_exceptions. It is always last to get freed.
154 * These fields get set up when writing to the origin.
155 */
156 struct dm_snap_pending_exception *primary_pe;
157
158 /*
159 * Number of pending_exceptions processing this chunk.
160 * When this drops to zero we must complete the origin bios.
161 * If incrementing or decrementing this, hold pe->snap->lock for
162 * the sibling concerned and not pe->primary_pe->snap->lock unless
163 * they are the same.
164 */
165 atomic_t ref_count;
166
167 /* Pointer back to snapshot context */ 145 /* Pointer back to snapshot context */
168 struct dm_snapshot *snap; 146 struct dm_snapshot *snap;
169 147
@@ -1019,6 +997,26 @@ static void flush_queued_bios(struct work_struct *work)
1019 flush_bios(queued_bios); 997 flush_bios(queued_bios);
1020} 998}
1021 999
1000static int do_origin(struct dm_dev *origin, struct bio *bio);
1001
1002/*
1003 * Flush a list of buffers.
1004 */
1005static void retry_origin_bios(struct dm_snapshot *s, struct bio *bio)
1006{
1007 struct bio *n;
1008 int r;
1009
1010 while (bio) {
1011 n = bio->bi_next;
1012 bio->bi_next = NULL;
1013 r = do_origin(s->origin, bio);
1014 if (r == DM_MAPIO_REMAPPED)
1015 generic_make_request(bio);
1016 bio = n;
1017 }
1018}
1019
1022/* 1020/*
1023 * Error a list of buffers. 1021 * Error a list of buffers.
1024 */ 1022 */
@@ -1052,39 +1050,6 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err)
1052 dm_table_event(s->ti->table); 1050 dm_table_event(s->ti->table);
1053} 1051}
1054 1052
1055static void get_pending_exception(struct dm_snap_pending_exception *pe)
1056{
1057 atomic_inc(&pe->ref_count);
1058}
1059
1060static struct bio *put_pending_exception(struct dm_snap_pending_exception *pe)
1061{
1062 struct dm_snap_pending_exception *primary_pe;
1063 struct bio *origin_bios = NULL;
1064
1065 primary_pe = pe->primary_pe;
1066
1067 /*
1068 * If this pe is involved in a write to the origin and
1069 * it is the last sibling to complete then release
1070 * the bios for the original write to the origin.
1071 */
1072 if (primary_pe &&
1073 atomic_dec_and_test(&primary_pe->ref_count)) {
1074 origin_bios = bio_list_get(&primary_pe->origin_bios);
1075 free_pending_exception(primary_pe);
1076 }
1077
1078 /*
1079 * Free the pe if it's not linked to an origin write or if
1080 * it's not itself a primary pe.
1081 */
1082 if (!primary_pe || primary_pe != pe)
1083 free_pending_exception(pe);
1084
1085 return origin_bios;
1086}
1087
1088static void pending_complete(struct dm_snap_pending_exception *pe, int success) 1053static void pending_complete(struct dm_snap_pending_exception *pe, int success)
1089{ 1054{
1090 struct dm_exception *e; 1055 struct dm_exception *e;
@@ -1129,7 +1094,8 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success)
1129 out: 1094 out:
1130 dm_remove_exception(&pe->e); 1095 dm_remove_exception(&pe->e);
1131 snapshot_bios = bio_list_get(&pe->snapshot_bios); 1096 snapshot_bios = bio_list_get(&pe->snapshot_bios);
1132 origin_bios = put_pending_exception(pe); 1097 origin_bios = bio_list_get(&pe->origin_bios);
1098 free_pending_exception(pe);
1133 1099
1134 up_write(&s->lock); 1100 up_write(&s->lock);
1135 1101
@@ -1139,7 +1105,7 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success)
1139 else 1105 else
1140 flush_bios(snapshot_bios); 1106 flush_bios(snapshot_bios);
1141 1107
1142 flush_bios(origin_bios); 1108 retry_origin_bios(s, origin_bios);
1143} 1109}
1144 1110
1145static void commit_callback(void *context, int success) 1111static void commit_callback(void *context, int success)
@@ -1226,8 +1192,6 @@ __find_pending_exception(struct dm_snapshot *s,
1226 pe->e.old_chunk = chunk; 1192 pe->e.old_chunk = chunk;
1227 bio_list_init(&pe->origin_bios); 1193 bio_list_init(&pe->origin_bios);
1228 bio_list_init(&pe->snapshot_bios); 1194 bio_list_init(&pe->snapshot_bios);
1229 pe->primary_pe = NULL;
1230 atomic_set(&pe->ref_count, 0);
1231 pe->started = 0; 1195 pe->started = 0;
1232 1196
1233 if (s->store->type->prepare_exception(s->store, &pe->e)) { 1197 if (s->store->type->prepare_exception(s->store, &pe->e)) {
@@ -1235,7 +1199,6 @@ __find_pending_exception(struct dm_snapshot *s,
1235 return NULL; 1199 return NULL;
1236 } 1200 }
1237 1201
1238 get_pending_exception(pe);
1239 dm_insert_exception(&s->pending, &pe->e); 1202 dm_insert_exception(&s->pending, &pe->e);
1240 1203
1241 return pe; 1204 return pe;
@@ -1492,16 +1455,16 @@ static int snapshot_iterate_devices(struct dm_target *ti,
1492static int __origin_write(struct list_head *snapshots, sector_t sector, 1455static int __origin_write(struct list_head *snapshots, sector_t sector,
1493 struct bio *bio) 1456 struct bio *bio)
1494{ 1457{
1495 int r = DM_MAPIO_REMAPPED, first = 0; 1458 int r = DM_MAPIO_REMAPPED;
1496 struct dm_snapshot *snap; 1459 struct dm_snapshot *snap;
1497 struct dm_exception *e; 1460 struct dm_exception *e;
1498 struct dm_snap_pending_exception *pe, *next_pe, *primary_pe = NULL; 1461 struct dm_snap_pending_exception *pe;
1462 struct dm_snap_pending_exception *pe_to_start_now = NULL;
1463 struct dm_snap_pending_exception *pe_to_start_last = NULL;
1499 chunk_t chunk; 1464 chunk_t chunk;
1500 LIST_HEAD(pe_queue);
1501 1465
1502 /* Do all the snapshots on this origin */ 1466 /* Do all the snapshots on this origin */
1503 list_for_each_entry (snap, snapshots, list) { 1467 list_for_each_entry (snap, snapshots, list) {
1504
1505 down_write(&snap->lock); 1468 down_write(&snap->lock);
1506 1469
1507 /* Only deal with valid and active snapshots */ 1470 /* Only deal with valid and active snapshots */
@@ -1522,9 +1485,6 @@ static int __origin_write(struct list_head *snapshots, sector_t sector,
1522 * Check exception table to see if block 1485 * Check exception table to see if block
1523 * is already remapped in this snapshot 1486 * is already remapped in this snapshot
1524 * and trigger an exception if not. 1487 * and trigger an exception if not.
1525 *
1526 * ref_count is initialised to 1 so pending_complete()
1527 * won't destroy the primary_pe while we're inside this loop.
1528 */ 1488 */
1529 e = dm_lookup_exception(&snap->complete, chunk); 1489 e = dm_lookup_exception(&snap->complete, chunk);
1530 if (e) 1490 if (e)
@@ -1554,60 +1514,43 @@ static int __origin_write(struct list_head *snapshots, sector_t sector,
1554 } 1514 }
1555 } 1515 }
1556 1516
1557 if (!primary_pe) { 1517 r = DM_MAPIO_SUBMITTED;
1558 /*
1559 * Either every pe here has same
1560 * primary_pe or none has one yet.
1561 */
1562 if (pe->primary_pe)
1563 primary_pe = pe->primary_pe;
1564 else {
1565 primary_pe = pe;
1566 first = 1;
1567 }
1568
1569 if (bio)
1570 bio_list_add(&primary_pe->origin_bios, bio);
1571 1518
1572 r = DM_MAPIO_SUBMITTED; 1519 /*
1573 } 1520 * If an origin bio was supplied, queue it to wait for the
1521 * completion of this exception, and start this one last,
1522 * at the end of the function.
1523 */
1524 if (bio) {
1525 bio_list_add(&pe->origin_bios, bio);
1526 bio = NULL;
1574 1527
1575 if (!pe->primary_pe) { 1528 if (!pe->started) {
1576 pe->primary_pe = primary_pe; 1529 pe->started = 1;
1577 get_pending_exception(primary_pe); 1530 pe_to_start_last = pe;
1531 }
1578 } 1532 }
1579 1533
1580 if (!pe->started) { 1534 if (!pe->started) {
1581 pe->started = 1; 1535 pe->started = 1;
1582 list_add_tail(&pe->list, &pe_queue); 1536 pe_to_start_now = pe;
1583 } 1537 }
1584 1538
1585 next_snapshot: 1539 next_snapshot:
1586 up_write(&snap->lock); 1540 up_write(&snap->lock);
1587 }
1588 1541
1589 if (!primary_pe) 1542 if (pe_to_start_now) {
1590 return r; 1543 start_copy(pe_to_start_now);
1591 1544 pe_to_start_now = NULL;
1592 /* 1545 }
1593 * If this is the first time we're processing this chunk and
1594 * ref_count is now 1 it means all the pending exceptions
1595 * got completed while we were in the loop above, so it falls to
1596 * us here to remove the primary_pe and submit any origin_bios.
1597 */
1598
1599 if (first && atomic_dec_and_test(&primary_pe->ref_count)) {
1600 flush_bios(bio_list_get(&primary_pe->origin_bios));
1601 free_pending_exception(primary_pe);
1602 /* If we got here, pe_queue is necessarily empty. */
1603 return r;
1604 } 1546 }
1605 1547
1606 /* 1548 /*
1607 * Now that we have a complete pe list we can start the copying. 1549 * Submit the exception against which the bio is queued last,
1550 * to give the other exceptions a head start.
1608 */ 1551 */
1609 list_for_each_entry_safe(pe, next_pe, &pe_queue, list) 1552 if (pe_to_start_last)
1610 start_copy(pe); 1553 start_copy(pe_to_start_last);
1611 1554
1612 return r; 1555 return r;
1613} 1556}