aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2011-08-02 07:32:04 -0400
committerAlasdair G Kergon <agk@redhat.com>2011-08-02 07:32:04 -0400
commita6e50b409d3f9e0833e69c3c9cca822e8fa4adbb (patch)
tree82ca807c21156437270e6a1ed255b18ccf8b3672 /drivers/md
parentd5b9dd04bd74b774b8e8d93ced7a0d15ad403fa9 (diff)
dm snapshot: skip reading origin when overwriting complete chunk
If we write a full chunk in the snapshot, skip reading the origin device because the whole chunk will be overwritten anyway. This patch changes the snapshot write logic when a full chunk is written. In this case: 1. allocate the exception 2. dispatch the bio (but don't report the bio completion to device mapper) 3. write the exception record 4. report bio completed Callbacks must be done through the kcopyd thread, because callbacks must not race with each other. So we create two new functions: dm_kcopyd_prepare_callback: allocate a job structure and prepare the callback. (This function must not be called from interrupt context.) dm_kcopyd_do_callback: submit callback. (This function may be called from interrupt context.) Performance test (on snapshots with 4k chunk size): without the patch: non-direct-io sequential write (dd): 17.7MB/s direct-io sequential write (dd): 20.9MB/s non-direct-io random write (mkfs.ext2): 0.44s with the patch: non-direct-io sequential write (dd): 26.5MB/s direct-io sequential write (dd): 33.2MB/s non-direct-io random write (mkfs.ext2): 0.27s Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/dm-kcopyd.c31
-rw-r--r--drivers/md/dm-snap.c60
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}
618EXPORT_SYMBOL(dm_kcopyd_copy); 618EXPORT_SYMBOL(dm_kcopyd_copy);
619 619
620void *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}
636EXPORT_SYMBOL(dm_kcopyd_prepare_callback);
637
638void 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}
649EXPORT_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
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;