diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/md/dm-kcopyd.c | 31 | ||||
| -rw-r--r-- | drivers/md/dm-snap.c | 60 |
2 files changed, 88 insertions, 3 deletions
diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index 98725e119324..f82147029636 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c | |||
| @@ -617,6 +617,37 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from, | |||
| 617 | } | 617 | } |
| 618 | EXPORT_SYMBOL(dm_kcopyd_copy); | 618 | EXPORT_SYMBOL(dm_kcopyd_copy); |
| 619 | 619 | ||
| 620 | void *dm_kcopyd_prepare_callback(struct dm_kcopyd_client *kc, | ||
| 621 | dm_kcopyd_notify_fn fn, void *context) | ||
| 622 | { | ||
| 623 | struct kcopyd_job *job; | ||
| 624 | |||
| 625 | job = mempool_alloc(kc->job_pool, GFP_NOIO); | ||
| 626 | |||
| 627 | memset(job, 0, sizeof(struct kcopyd_job)); | ||
| 628 | job->kc = kc; | ||
| 629 | job->fn = fn; | ||
| 630 | job->context = context; | ||
| 631 | |||
| 632 | atomic_inc(&kc->nr_jobs); | ||
| 633 | |||
| 634 | return job; | ||
| 635 | } | ||
| 636 | EXPORT_SYMBOL(dm_kcopyd_prepare_callback); | ||
| 637 | |||
| 638 | void dm_kcopyd_do_callback(void *j, int read_err, unsigned long write_err) | ||
| 639 | { | ||
| 640 | struct kcopyd_job *job = j; | ||
| 641 | struct dm_kcopyd_client *kc = job->kc; | ||
| 642 | |||
| 643 | job->read_err = read_err; | ||
| 644 | job->write_err = write_err; | ||
| 645 | |||
| 646 | push(&kc->complete_jobs, job); | ||
| 647 | wake(kc); | ||
| 648 | } | ||
| 649 | EXPORT_SYMBOL(dm_kcopyd_do_callback); | ||
| 650 | |||
| 620 | /* | 651 | /* |
| 621 | * Cancels a kcopyd job, eg. someone might be deactivating a | 652 | * Cancels a kcopyd job, eg. someone might be deactivating a |
| 622 | * mirror. | 653 | * mirror. |
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 | ||
| 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); | ||
| 1517 | } | ||
| 1518 | |||
| 1475 | static struct dm_snap_pending_exception * | 1519 | static 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; |
