diff options
Diffstat (limited to 'drivers/md/dm-snap.c')
-rw-r--r-- | drivers/md/dm-snap.c | 84 |
1 files changed, 63 insertions, 21 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 9ecff5f3023..6f758870fc1 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -30,16 +30,6 @@ static const char dm_snapshot_merge_target_name[] = "snapshot-merge"; | |||
30 | ((ti)->type->name == dm_snapshot_merge_target_name) | 30 | ((ti)->type->name == dm_snapshot_merge_target_name) |
31 | 31 | ||
32 | /* | 32 | /* |
33 | * The percentage increment we will wake up users at | ||
34 | */ | ||
35 | #define WAKE_UP_PERCENT 5 | ||
36 | |||
37 | /* | ||
38 | * kcopyd priority of snapshot operations | ||
39 | */ | ||
40 | #define SNAPSHOT_COPY_PRIORITY 2 | ||
41 | |||
42 | /* | ||
43 | * The size of the mempool used to track chunks in use. | 33 | * The size of the mempool used to track chunks in use. |
44 | */ | 34 | */ |
45 | #define MIN_IOS 256 | 35 | #define MIN_IOS 256 |
@@ -180,6 +170,13 @@ struct dm_snap_pending_exception { | |||
180 | * kcopyd. | 170 | * kcopyd. |
181 | */ | 171 | */ |
182 | 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; | ||
183 | }; | 180 | }; |
184 | 181 | ||
185 | /* | 182 | /* |
@@ -1055,8 +1052,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1055 | 1052 | ||
1056 | s = kmalloc(sizeof(*s), GFP_KERNEL); | 1053 | s = kmalloc(sizeof(*s), GFP_KERNEL); |
1057 | if (!s) { | 1054 | if (!s) { |
1058 | ti->error = "Cannot allocate snapshot context private " | 1055 | ti->error = "Cannot allocate private snapshot structure"; |
1059 | "structure"; | ||
1060 | r = -ENOMEM; | 1056 | r = -ENOMEM; |
1061 | goto bad; | 1057 | goto bad; |
1062 | } | 1058 | } |
@@ -1380,6 +1376,7 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success) | |||
1380 | struct dm_snapshot *s = pe->snap; | 1376 | struct dm_snapshot *s = pe->snap; |
1381 | struct bio *origin_bios = NULL; | 1377 | struct bio *origin_bios = NULL; |
1382 | struct bio *snapshot_bios = NULL; | 1378 | struct bio *snapshot_bios = NULL; |
1379 | struct bio *full_bio = NULL; | ||
1383 | int error = 0; | 1380 | int error = 0; |
1384 | 1381 | ||
1385 | if (!success) { | 1382 | if (!success) { |
@@ -1415,10 +1412,15 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success) | |||
1415 | */ | 1412 | */ |
1416 | dm_insert_exception(&s->complete, e); | 1413 | dm_insert_exception(&s->complete, e); |
1417 | 1414 | ||
1418 | out: | 1415 | out: |
1419 | dm_remove_exception(&pe->e); | 1416 | dm_remove_exception(&pe->e); |
1420 | snapshot_bios = bio_list_get(&pe->snapshot_bios); | 1417 | snapshot_bios = bio_list_get(&pe->snapshot_bios); |
1421 | 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 | } | ||
1422 | free_pending_exception(pe); | 1424 | free_pending_exception(pe); |
1423 | 1425 | ||
1424 | increment_pending_exceptions_done_count(); | 1426 | increment_pending_exceptions_done_count(); |
@@ -1426,10 +1428,15 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success) | |||
1426 | up_write(&s->lock); | 1428 | up_write(&s->lock); |
1427 | 1429 | ||
1428 | /* Submit any pending write bios */ | 1430 | /* Submit any pending write bios */ |
1429 | if (error) | 1431 | if (error) { |
1432 | if (full_bio) | ||
1433 | bio_io_error(full_bio); | ||
1430 | error_bios(snapshot_bios); | 1434 | error_bios(snapshot_bios); |
1431 | else | 1435 | } else { |
1436 | if (full_bio) | ||
1437 | bio_endio(full_bio, 0); | ||
1432 | flush_bios(snapshot_bios); | 1438 | flush_bios(snapshot_bios); |
1439 | } | ||
1433 | 1440 | ||
1434 | retry_origin_bios(s, origin_bios); | 1441 | retry_origin_bios(s, origin_bios); |
1435 | } | 1442 | } |
@@ -1480,8 +1487,33 @@ static void start_copy(struct dm_snap_pending_exception *pe) | |||
1480 | dest.count = src.count; | 1487 | dest.count = src.count; |
1481 | 1488 | ||
1482 | /* Hand over to kcopyd */ | 1489 | /* Hand over to kcopyd */ |
1483 | dm_kcopyd_copy(s->kcopyd_client, | 1490 | dm_kcopyd_copy(s->kcopyd_client, &src, 1, &dest, 0, copy_callback, pe); |
1484 | &src, 1, &dest, 0, copy_callback, pe); | 1491 | } |
1492 | |||
1493 | static 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 | |||
1500 | static 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); | ||
1485 | } | 1517 | } |
1486 | 1518 | ||
1487 | static struct dm_snap_pending_exception * | 1519 | static struct dm_snap_pending_exception * |
@@ -1519,6 +1551,7 @@ __find_pending_exception(struct dm_snapshot *s, | |||
1519 | bio_list_init(&pe->origin_bios); | 1551 | bio_list_init(&pe->origin_bios); |
1520 | bio_list_init(&pe->snapshot_bios); | 1552 | bio_list_init(&pe->snapshot_bios); |
1521 | pe->started = 0; | 1553 | pe->started = 0; |
1554 | pe->full_bio = NULL; | ||
1522 | 1555 | ||
1523 | if (s->store->type->prepare_exception(s->store, &pe->e)) { | 1556 | if (s->store->type->prepare_exception(s->store, &pe->e)) { |
1524 | free_pending_exception(pe); | 1557 | free_pending_exception(pe); |
@@ -1612,10 +1645,19 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, | |||
1612 | } | 1645 | } |
1613 | 1646 | ||
1614 | remap_exception(s, &pe->e, bio, chunk); | 1647 | remap_exception(s, &pe->e, bio, chunk); |
1615 | bio_list_add(&pe->snapshot_bios, bio); | ||
1616 | 1648 | ||
1617 | r = DM_MAPIO_SUBMITTED; | 1649 | r = DM_MAPIO_SUBMITTED; |
1618 | 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 | |||
1619 | if (!pe->started) { | 1661 | if (!pe->started) { |
1620 | /* this is protected by snap->lock */ | 1662 | /* this is protected by snap->lock */ |
1621 | pe->started = 1; | 1663 | pe->started = 1; |
@@ -1628,9 +1670,9 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, | |||
1628 | map_context->ptr = track_chunk(s, chunk); | 1670 | map_context->ptr = track_chunk(s, chunk); |
1629 | } | 1671 | } |
1630 | 1672 | ||
1631 | out_unlock: | 1673 | out_unlock: |
1632 | up_write(&s->lock); | 1674 | up_write(&s->lock); |
1633 | out: | 1675 | out: |
1634 | return r; | 1676 | return r; |
1635 | } | 1677 | } |
1636 | 1678 | ||
@@ -1974,7 +2016,7 @@ static int __origin_write(struct list_head *snapshots, sector_t sector, | |||
1974 | pe_to_start_now = pe; | 2016 | pe_to_start_now = pe; |
1975 | } | 2017 | } |
1976 | 2018 | ||
1977 | next_snapshot: | 2019 | next_snapshot: |
1978 | up_write(&snap->lock); | 2020 | up_write(&snap->lock); |
1979 | 2021 | ||
1980 | if (pe_to_start_now) { | 2022 | if (pe_to_start_now) { |