aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-snap.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/dm-snap.c')
-rw-r--r--drivers/md/dm-snap.c60
1 files changed, 57 insertions, 3 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 94dee05dd28e..6f758870fc19 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -170,6 +170,13 @@ struct dm_snap_pending_exception {
170 * kcopyd. 170 * kcopyd.
171 */ 171 */
172 int started; 172 int started;
173
174 /*
175 * For writing a complete chunk, bypassing the copy.
176 */
177 struct bio *full_bio;
178 bio_end_io_t *full_bio_end_io;
179 void *full_bio_private;
173}; 180};
174 181
175/* 182/*
@@ -1369,6 +1376,7 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success)
1369 struct dm_snapshot *s = pe->snap; 1376 struct dm_snapshot *s = pe->snap;
1370 struct bio *origin_bios = NULL; 1377 struct bio *origin_bios = NULL;
1371 struct bio *snapshot_bios = NULL; 1378 struct bio *snapshot_bios = NULL;
1379 struct bio *full_bio = NULL;
1372 int error = 0; 1380 int error = 0;
1373 1381
1374 if (!success) { 1382 if (!success) {
@@ -1408,6 +1416,11 @@ out:
1408 dm_remove_exception(&pe->e); 1416 dm_remove_exception(&pe->e);
1409 snapshot_bios = bio_list_get(&pe->snapshot_bios); 1417 snapshot_bios = bio_list_get(&pe->snapshot_bios);
1410 origin_bios = bio_list_get(&pe->origin_bios); 1418 origin_bios = bio_list_get(&pe->origin_bios);
1419 full_bio = pe->full_bio;
1420 if (full_bio) {
1421 full_bio->bi_end_io = pe->full_bio_end_io;
1422 full_bio->bi_private = pe->full_bio_private;
1423 }
1411 free_pending_exception(pe); 1424 free_pending_exception(pe);
1412 1425
1413 increment_pending_exceptions_done_count(); 1426 increment_pending_exceptions_done_count();
@@ -1415,10 +1428,15 @@ out:
1415 up_write(&s->lock); 1428 up_write(&s->lock);
1416 1429
1417 /* Submit any pending write bios */ 1430 /* Submit any pending write bios */
1418 if (error) 1431 if (error) {
1432 if (full_bio)
1433 bio_io_error(full_bio);
1419 error_bios(snapshot_bios); 1434 error_bios(snapshot_bios);
1420 else 1435 } else {
1436 if (full_bio)
1437 bio_endio(full_bio, 0);
1421 flush_bios(snapshot_bios); 1438 flush_bios(snapshot_bios);
1439 }
1422 1440
1423 retry_origin_bios(s, origin_bios); 1441 retry_origin_bios(s, origin_bios);
1424} 1442}
@@ -1472,6 +1490,32 @@ static void start_copy(struct dm_snap_pending_exception *pe)
1472 dm_kcopyd_copy(s->kcopyd_client, &src, 1, &dest, 0, copy_callback, pe); 1490 dm_kcopyd_copy(s->kcopyd_client, &src, 1, &dest, 0, copy_callback, pe);
1473} 1491}
1474 1492
1493static void full_bio_end_io(struct bio *bio, int error)
1494{
1495 void *callback_data = bio->bi_private;
1496
1497 dm_kcopyd_do_callback(callback_data, 0, error ? 1 : 0);
1498}
1499
1500static void start_full_bio(struct dm_snap_pending_exception *pe,
1501 struct bio *bio)
1502{
1503 struct dm_snapshot *s = pe->snap;
1504 void *callback_data;
1505
1506 pe->full_bio = bio;
1507 pe->full_bio_end_io = bio->bi_end_io;
1508 pe->full_bio_private = bio->bi_private;
1509
1510 callback_data = dm_kcopyd_prepare_callback(s->kcopyd_client,
1511 copy_callback, pe);
1512
1513 bio->bi_end_io = full_bio_end_io;
1514 bio->bi_private = callback_data;
1515
1516 generic_make_request(bio);
1517}
1518
1475static struct dm_snap_pending_exception * 1519static struct dm_snap_pending_exception *
1476__lookup_pending_exception(struct dm_snapshot *s, chunk_t chunk) 1520__lookup_pending_exception(struct dm_snapshot *s, chunk_t chunk)
1477{ 1521{
@@ -1507,6 +1551,7 @@ __find_pending_exception(struct dm_snapshot *s,
1507 bio_list_init(&pe->origin_bios); 1551 bio_list_init(&pe->origin_bios);
1508 bio_list_init(&pe->snapshot_bios); 1552 bio_list_init(&pe->snapshot_bios);
1509 pe->started = 0; 1553 pe->started = 0;
1554 pe->full_bio = NULL;
1510 1555
1511 if (s->store->type->prepare_exception(s->store, &pe->e)) { 1556 if (s->store->type->prepare_exception(s->store, &pe->e)) {
1512 free_pending_exception(pe); 1557 free_pending_exception(pe);
@@ -1600,10 +1645,19 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
1600 } 1645 }
1601 1646
1602 remap_exception(s, &pe->e, bio, chunk); 1647 remap_exception(s, &pe->e, bio, chunk);
1603 bio_list_add(&pe->snapshot_bios, bio);
1604 1648
1605 r = DM_MAPIO_SUBMITTED; 1649 r = DM_MAPIO_SUBMITTED;
1606 1650
1651 if (!pe->started &&
1652 bio->bi_size == (s->store->chunk_size << SECTOR_SHIFT)) {
1653 pe->started = 1;
1654 up_write(&s->lock);
1655 start_full_bio(pe, bio);
1656 goto out;
1657 }
1658
1659 bio_list_add(&pe->snapshot_bios, bio);
1660
1607 if (!pe->started) { 1661 if (!pe->started) {
1608 /* this is protected by snap->lock */ 1662 /* this is protected by snap->lock */
1609 pe->started = 1; 1663 pe->started = 1;