dm kcopyd: add dm_kcopyd_zero to zero an area
authorMikulas Patocka <mpatocka@redhat.com>
Mon, 31 Oct 2011 20:18:58 +0000 (20:18 +0000)
committerAlasdair G Kergon <agk@redhat.com>
Mon, 31 Oct 2011 20:18:58 +0000 (20:18 +0000)
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>
drivers/md/dm-kcopyd.c
include/linux/dm-kcopyd.h

index 32ac70861d66c9827518f723b2b1d8d4138493f9..bed444c93d8d49e03757fdf88c8facb7d98f07dc 100644 (file)
@@ -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;
@@ -617,6 +630,14 @@ int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
 }
 EXPORT_SYMBOL(dm_kcopyd_copy);
 
+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);
+
 void *dm_kcopyd_prepare_callback(struct dm_kcopyd_client *kc,
                                 dm_kcopyd_notify_fn fn, void *context)
 {
index 5e54458e920f36466a29d83ccbe913a03f347a01..47d9d376e4e7a9e0cecb609065b3d735825cfdb9 100644 (file)
@@ -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 */