dm snapshot: report merge failure in status
[safe/jmp/linux-2.6] / drivers / md / dm-kcopyd.c
index 0a225da..addf834 100644 (file)
@@ -297,7 +297,8 @@ static int run_complete_job(struct kcopyd_job *job)
        dm_kcopyd_notify_fn fn = job->fn;
        struct dm_kcopyd_client *kc = job->kc;
 
-       kcopyd_put_pages(kc, job->pages);
+       if (job->pages)
+               kcopyd_put_pages(kc, job->pages);
        mempool_free(job, kc->job_pool);
        fn(read_err, write_err, context);
 
@@ -449,7 +450,10 @@ static void dispatch_job(struct kcopyd_job *job)
 {
        struct dm_kcopyd_client *kc = job->kc;
        atomic_inc(&kc->nr_jobs);
-       push(&kc->pages_jobs, job);
+       if (unlikely(!job->source.count))
+               push(&kc->complete_jobs, job);
+       else
+               push(&kc->pages_jobs, job);
        wake(kc);
 }
 
@@ -461,6 +465,7 @@ static void segment_complete(int read_err, unsigned long write_err,
        sector_t progress = 0;
        sector_t count = 0;
        struct kcopyd_job *job = (struct kcopyd_job *) context;
+       struct dm_kcopyd_client *kc = job->kc;
 
        mutex_lock(&job->lock);
 
@@ -490,7 +495,7 @@ static void segment_complete(int read_err, unsigned long write_err,
 
        if (count) {
                int i;
-               struct kcopyd_job *sub_job = mempool_alloc(job->kc->job_pool,
+               struct kcopyd_job *sub_job = mempool_alloc(kc->job_pool,
                                                           GFP_NOIO);
 
                *sub_job = *job;
@@ -509,13 +514,16 @@ static void segment_complete(int read_err, unsigned long write_err,
        } else if (atomic_dec_and_test(&job->sub_jobs)) {
 
                /*
-                * To avoid a race we must keep the job around
-                * until after the notify function has completed.
-                * Otherwise the client may try and stop the job
-                * after we've completed.
+                * Queue the completion callback to the kcopyd thread.
+                *
+                * Some callers assume that all the completions are called
+                * from a single thread and don't race with each other.
+                *
+                * We must not call the callback directly here because this
+                * code may not be executing in the thread.
                 */
-               job->fn(read_err, write_err, job->context);
-               mempool_free(job, job->kc->job_pool);
+               push(&kc->complete_jobs, job);
+               wake(kc);
        }
 }
 
@@ -528,6 +536,8 @@ static void split_job(struct kcopyd_job *job)
 {
        int i;
 
+       atomic_inc(&job->kc->nr_jobs);
+
        atomic_set(&job->sub_jobs, SPLIT_COUNT);
        for (i = 0; i < SPLIT_COUNT; i++)
                segment_complete(0, 0u, job);