aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2011-10-31 16:18:58 -0400
committerAlasdair G Kergon <agk@redhat.com>2011-10-31 16:18:58 -0400
commit7f06965390e4a10fb6906c886324bfd0a96961be (patch)
tree5a6fd96cd56fb9d80bf1a40110ebfcdb5a8a7aa3
parentfbdc86f3bd597e108fa03d998132d04fcfe1d669 (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.c31
-rw-r--r--include/linux/dm-kcopyd.h4
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
69static struct page_list zero_page_list;
70
69static void wake(struct dm_kcopyd_client *kc) 71static 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}
618EXPORT_SYMBOL(dm_kcopyd_copy); 631EXPORT_SYMBOL(dm_kcopyd_copy);
619 632
633int 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}
639EXPORT_SYMBOL(dm_kcopyd_zero);
640
620void *dm_kcopyd_prepare_callback(struct dm_kcopyd_client *kc, 641void *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);
58void dm_kcopyd_do_callback(void *job, int read_err, unsigned long write_err); 58void dm_kcopyd_do_callback(void *job, int read_err, unsigned long write_err);
59 59
60int 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 */