diff options
| author | Mikulas Patocka <mpatocka@redhat.com> | 2011-10-31 16:18:58 -0400 |
|---|---|---|
| committer | Alasdair G Kergon <agk@redhat.com> | 2011-10-31 16:18:58 -0400 |
| commit | 7f06965390e4a10fb6906c886324bfd0a96961be (patch) | |
| tree | 5a6fd96cd56fb9d80bf1a40110ebfcdb5a8a7aa3 | |
| parent | fbdc86f3bd597e108fa03d998132d04fcfe1d669 (diff) | |
dm kcopyd: add dm_kcopyd_zero to zero an area
This patch introduces dm_kcopyd_zero() to make it easy to use
kcopyd to write zeros into the requested areas instead
instead of copying. It is implemented by passing a NULL
copying source to dm_kcopyd_copy().
The forthcoming thin provisioning target uses this.
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
| -rw-r--r-- | drivers/md/dm-kcopyd.c | 31 | ||||
| -rw-r--r-- | include/linux/dm-kcopyd.h | 4 |
2 files changed, 30 insertions, 5 deletions
diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index 32ac70861d66..bed444c93d8d 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c | |||
| @@ -66,6 +66,8 @@ struct dm_kcopyd_client { | |||
| 66 | struct list_head pages_jobs; | 66 | struct list_head pages_jobs; |
| 67 | }; | 67 | }; |
| 68 | 68 | ||
| 69 | static struct page_list zero_page_list; | ||
| 70 | |||
| 69 | static void wake(struct dm_kcopyd_client *kc) | 71 | static void wake(struct dm_kcopyd_client *kc) |
| 70 | { | 72 | { |
| 71 | queue_work(kc->kcopyd_wq, &kc->kcopyd_work); | 73 | queue_work(kc->kcopyd_wq, &kc->kcopyd_work); |
| @@ -254,6 +256,9 @@ int __init dm_kcopyd_init(void) | |||
| 254 | if (!_job_cache) | 256 | if (!_job_cache) |
| 255 | return -ENOMEM; | 257 | return -ENOMEM; |
| 256 | 258 | ||
| 259 | zero_page_list.next = &zero_page_list; | ||
| 260 | zero_page_list.page = ZERO_PAGE(0); | ||
| 261 | |||
| 257 | return 0; | 262 | return 0; |
| 258 | } | 263 | } |
| 259 | 264 | ||
| @@ -322,7 +327,7 @@ static int run_complete_job(struct kcopyd_job *job) | |||
| 322 | dm_kcopyd_notify_fn fn = job->fn; | 327 | dm_kcopyd_notify_fn fn = job->fn; |
| 323 | struct dm_kcopyd_client *kc = job->kc; | 328 | struct dm_kcopyd_client *kc = job->kc; |
| 324 | 329 | ||
| 325 | if (job->pages) | 330 | if (job->pages && job->pages != &zero_page_list) |
| 326 | kcopyd_put_pages(kc, job->pages); | 331 | kcopyd_put_pages(kc, job->pages); |
| 327 | /* | 332 | /* |
| 328 | * If this is the master job, the sub jobs have already | 333 | * If this is the master job, the sub jobs have already |
| @@ -484,6 +489,8 @@ static void dispatch_job(struct kcopyd_job *job) | |||
| 484 | atomic_inc(&kc->nr_jobs); | 489 | atomic_inc(&kc->nr_jobs); |
| 485 | if (unlikely(!job->source.count)) | 490 | if (unlikely(!job->source.count)) |
| 486 | push(&kc->complete_jobs, job); | 491 | push(&kc->complete_jobs, job); |
| 492 | else if (job->pages == &zero_page_list) | ||
| 493 | push(&kc->io_jobs, job); | ||
| 487 | else | 494 | else |
| 488 | push(&kc->pages_jobs, job); | 495 | push(&kc->pages_jobs, job); |
| 489 | wake(kc); | 496 | wake(kc); |
| @@ -592,14 +599,20 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from, | |||
| 592 | job->flags = flags; | 599 | job->flags = flags; |
| 593 | job->read_err = 0; | 600 | job->read_err = 0; |
| 594 | job->write_err = 0; | 601 | job->write_err = 0; |
| 595 | job->rw = READ; | ||
| 596 | |||
| 597 | job->source = *from; | ||
| 598 | 602 | ||
| 599 | job->num_dests = num_dests; | 603 | job->num_dests = num_dests; |
| 600 | memcpy(&job->dests, dests, sizeof(*dests) * num_dests); | 604 | memcpy(&job->dests, dests, sizeof(*dests) * num_dests); |
| 601 | 605 | ||
| 602 | job->pages = NULL; | 606 | if (from) { |
| 607 | job->source = *from; | ||
| 608 | job->pages = NULL; | ||
| 609 | job->rw = READ; | ||
| 610 | } else { | ||
| 611 | memset(&job->source, 0, sizeof job->source); | ||
| 612 | job->source.count = job->dests[0].count; | ||
| 613 | job->pages = &zero_page_list; | ||
| 614 | job->rw = WRITE; | ||
| 615 | } | ||
| 603 | 616 | ||
| 604 | job->fn = fn; | 617 | job->fn = fn; |
| 605 | job->context = context; | 618 | job->context = context; |
| @@ -617,6 +630,14 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from, | |||
| 617 | } | 630 | } |
| 618 | EXPORT_SYMBOL(dm_kcopyd_copy); | 631 | EXPORT_SYMBOL(dm_kcopyd_copy); |
| 619 | 632 | ||
| 633 | int dm_kcopyd_zero(struct dm_kcopyd_client *kc, | ||
| 634 | unsigned num_dests, struct dm_io_region *dests, | ||
| 635 | unsigned flags, dm_kcopyd_notify_fn fn, void *context) | ||
| 636 | { | ||
| 637 | return dm_kcopyd_copy(kc, NULL, num_dests, dests, flags, fn, context); | ||
| 638 | } | ||
| 639 | EXPORT_SYMBOL(dm_kcopyd_zero); | ||
| 640 | |||
| 620 | void *dm_kcopyd_prepare_callback(struct dm_kcopyd_client *kc, | 641 | void *dm_kcopyd_prepare_callback(struct dm_kcopyd_client *kc, |
| 621 | dm_kcopyd_notify_fn fn, void *context) | 642 | dm_kcopyd_notify_fn fn, void *context) |
| 622 | { | 643 | { |
diff --git a/include/linux/dm-kcopyd.h b/include/linux/dm-kcopyd.h index 5e54458e920f..47d9d376e4e7 100644 --- a/include/linux/dm-kcopyd.h +++ b/include/linux/dm-kcopyd.h | |||
| @@ -57,5 +57,9 @@ void *dm_kcopyd_prepare_callback(struct dm_kcopyd_client *kc, | |||
| 57 | dm_kcopyd_notify_fn fn, void *context); | 57 | dm_kcopyd_notify_fn fn, void *context); |
| 58 | void dm_kcopyd_do_callback(void *job, int read_err, unsigned long write_err); | 58 | void dm_kcopyd_do_callback(void *job, int read_err, unsigned long write_err); |
| 59 | 59 | ||
| 60 | int dm_kcopyd_zero(struct dm_kcopyd_client *kc, | ||
| 61 | unsigned num_dests, struct dm_io_region *dests, | ||
| 62 | unsigned flags, dm_kcopyd_notify_fn fn, void *context); | ||
| 63 | |||
| 60 | #endif /* __KERNEL__ */ | 64 | #endif /* __KERNEL__ */ |
| 61 | #endif /* _LINUX_DM_KCOPYD_H */ | 65 | #endif /* _LINUX_DM_KCOPYD_H */ |
