Merge tag 'jfs-5.2' of git://github.com/kleikamp/linux-shaggy
[linux-2.6-microblaze.git] / drivers / md / dm-kcopyd.c
index 2fc4213..671c243 100644 (file)
@@ -56,15 +56,17 @@ struct dm_kcopyd_client {
        atomic_t nr_jobs;
 
 /*
- * We maintain three lists of jobs:
+ * We maintain four lists of jobs:
  *
  * i)   jobs waiting for pages
  * ii)  jobs that have pages, and are waiting for the io to be issued.
- * iii) jobs that have completed.
+ * iii) jobs that don't need to do any IO and just run a callback
+ * iv) jobs that have completed.
  *
- * All three of these are protected by job_lock.
+ * All four of these are protected by job_lock.
  */
        spinlock_t job_lock;
+       struct list_head callback_jobs;
        struct list_head complete_jobs;
        struct list_head io_jobs;
        struct list_head pages_jobs;
@@ -625,6 +627,7 @@ static void do_work(struct work_struct *work)
        struct dm_kcopyd_client *kc = container_of(work,
                                        struct dm_kcopyd_client, kcopyd_work);
        struct blk_plug plug;
+       unsigned long flags;
 
        /*
         * The order that these are called is *very* important.
@@ -633,6 +636,10 @@ static void do_work(struct work_struct *work)
         * list.  io jobs call wake when they complete and it all
         * starts again.
         */
+       spin_lock_irqsave(&kc->job_lock, flags);
+       list_splice_tail_init(&kc->callback_jobs, &kc->complete_jobs);
+       spin_unlock_irqrestore(&kc->job_lock, flags);
+
        blk_start_plug(&plug);
        process_jobs(&kc->complete_jobs, kc, run_complete_job);
        process_jobs(&kc->pages_jobs, kc, run_pages_job);
@@ -650,7 +657,7 @@ static void dispatch_job(struct kcopyd_job *job)
        struct dm_kcopyd_client *kc = job->kc;
        atomic_inc(&kc->nr_jobs);
        if (unlikely(!job->source.count))
-               push(&kc->complete_jobs, job);
+               push(&kc->callback_jobs, job);
        else if (job->pages == &zero_page_list)
                push(&kc->io_jobs, job);
        else
@@ -858,7 +865,7 @@ void dm_kcopyd_do_callback(void *j, int read_err, unsigned long write_err)
        job->read_err = read_err;
        job->write_err = write_err;
 
-       push(&kc->complete_jobs, job);
+       push(&kc->callback_jobs, job);
        wake(kc);
 }
 EXPORT_SYMBOL(dm_kcopyd_do_callback);
@@ -888,6 +895,7 @@ struct dm_kcopyd_client *dm_kcopyd_client_create(struct dm_kcopyd_throttle *thro
                return ERR_PTR(-ENOMEM);
 
        spin_lock_init(&kc->job_lock);
+       INIT_LIST_HEAD(&kc->callback_jobs);
        INIT_LIST_HEAD(&kc->complete_jobs);
        INIT_LIST_HEAD(&kc->io_jobs);
        INIT_LIST_HEAD(&kc->pages_jobs);
@@ -939,6 +947,7 @@ void dm_kcopyd_client_destroy(struct dm_kcopyd_client *kc)
        /* Wait for completion of all jobs submitted by this client. */
        wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs));
 
+       BUG_ON(!list_empty(&kc->callback_jobs));
        BUG_ON(!list_empty(&kc->complete_jobs));
        BUG_ON(!list_empty(&kc->io_jobs));
        BUG_ON(!list_empty(&kc->pages_jobs));