From 962ac86ff1103bd4a30bc5d0fdf5f25bee2e6e70 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 10 Aug 2011 09:13:33 +1000 Subject: [PATCH] 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 Signed-off-by: Alasdair G Kergon --- drivers/md/dm-kcopyd.c | 31 ++++++++++++++++++++++++++----- 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 f82147029636..d3c1ab86fde3 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -66,6 +66,8 @@ struct dm_kcopyd_client { struct list_head pages_jobs; }; +static struct page_list zero_page_list; + static void wake(struct dm_kcopyd_client *kc) { queue_work(kc->kcopyd_wq, &kc->kcopyd_work); @@ -254,6 +256,9 @@ int __init dm_kcopyd_init(void) if (!_job_cache) return -ENOMEM; + zero_page_list.next = &zero_page_list; + zero_page_list.page = ZERO_PAGE(0); + return 0; } @@ -322,7 +327,7 @@ static int run_complete_job(struct kcopyd_job *job) dm_kcopyd_notify_fn fn = job->fn; struct dm_kcopyd_client *kc = job->kc; - if (job->pages) + if (job->pages && job->pages != &zero_page_list) kcopyd_put_pages(kc, job->pages); /* * If this is the master job, the sub jobs have already @@ -484,6 +489,8 @@ static void dispatch_job(struct kcopyd_job *job) atomic_inc(&kc->nr_jobs); if (unlikely(!job->source.count)) push(&kc->complete_jobs, job); + else if (job->pages == &zero_page_list) + push(&kc->io_jobs, job); else push(&kc->pages_jobs, job); wake(kc); @@ -592,14 +599,20 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from, job->flags = flags; job->read_err = 0; job->write_err = 0; - job->rw = READ; - - job->source = *from; job->num_dests = num_dests; memcpy(&job->dests, dests, sizeof(*dests) * num_dests); - job->pages = NULL; + if (from) { + job->source = *from; + job->pages = NULL; + job->rw = READ; + } else { + memset(&job->source, 0, sizeof job->source); + job->source.count = job->dests[0].count; + job->pages = &zero_page_list; + job->rw = WRITE; + } job->fn = fn; job->context = context; @@ -648,6 +661,14 @@ void dm_kcopyd_do_callback(void *j, int read_err, unsigned long write_err) } EXPORT_SYMBOL(dm_kcopyd_do_callback); +int dm_kcopyd_zero(struct dm_kcopyd_client *kc, + unsigned num_dests, struct dm_io_region *dests, + unsigned flags, dm_kcopyd_notify_fn fn, void *context) +{ + return dm_kcopyd_copy(kc, NULL, num_dests, dests, flags, fn, context); +} +EXPORT_SYMBOL(dm_kcopyd_zero); + /* * Cancels a kcopyd job, eg. someone might be deactivating a * mirror. 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, dm_kcopyd_notify_fn fn, void *context); void dm_kcopyd_do_callback(void *job, int read_err, unsigned long write_err); +int dm_kcopyd_zero(struct dm_kcopyd_client *kc, + unsigned num_dests, struct dm_io_region *dests, + unsigned flags, dm_kcopyd_notify_fn fn, void *context); + #endif /* __KERNEL__ */ #endif /* _LINUX_DM_KCOPYD_H */ -- 2.39.5