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 */ |