Merge git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 25 Apr 2008 19:33:49 +0000 (12:33 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 25 Apr 2008 19:33:49 +0000 (12:33 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm: (24 commits)
  dm crypt: add documentation
  dm: remove md argument from specific_minor
  dm table: remove unused dm_create_error_table
  dm table: drop void suspend_targets return
  dm: unplug queues in threads
  dm raid1: use timer
  dm: move include files
  dm kcopyd: rename
  dm: expose macros
  dm kcopyd: remove redundant client counting
  dm kcopyd: private mempool
  dm kcopyd: per device
  dm log: make module use tracking internal
  dm log: move register functions
  dm log: clean interface
  dm kcopyd: clean interface
  dm io: clean interface
  dm io: rename error to error_bits
  dm snapshot: store pointer to target instance
  dm log: move dirty region log code into separate module
  ...

17 files changed:
Documentation/device-mapper/dm-crypt.txt [new file with mode: 0644]
drivers/md/Makefile
drivers/md/dm-exception-store.c
drivers/md/dm-io.c
drivers/md/dm-kcopyd.c [moved from drivers/md/kcopyd.c with 71% similarity]
drivers/md/dm-log.c
drivers/md/dm-raid1.c
drivers/md/dm-snap.c
drivers/md/dm-snap.h
drivers/md/dm-table.c
drivers/md/dm.c
drivers/md/dm.h
drivers/md/kcopyd.h [deleted file]
include/linux/device-mapper.h
include/linux/dm-dirty-log.h [moved from drivers/md/dm-log.h with 53% similarity]
include/linux/dm-io.h [moved from drivers/md/dm-io.h with 84% similarity]
include/linux/dm-kcopyd.h [new file with mode: 0644]

diff --git a/Documentation/device-mapper/dm-crypt.txt b/Documentation/device-mapper/dm-crypt.txt
new file mode 100644 (file)
index 0000000..6680cab
--- /dev/null
@@ -0,0 +1,52 @@
+dm-crypt
+=========
+
+Device-Mapper's "crypt" target provides transparent encryption of block devices
+using the kernel crypto API.
+
+Parameters: <cipher> <key> <iv_offset> <device path> <offset>
+
+<cipher>
+    Encryption cipher and an optional IV generation mode.
+    (In format cipher-chainmode-ivopts:ivmode).
+    Examples:
+       des
+       aes-cbc-essiv:sha256
+       twofish-ecb
+
+    /proc/crypto contains supported crypto modes
+
+<key>
+    Key used for encryption. It is encoded as a hexadecimal number.
+    You can only use key sizes that are valid for the selected cipher.
+
+<iv_offset>
+    The IV offset is a sector count that is added to the sector number
+    before creating the IV.
+
+<device path>
+    This is the device that is going to be used as backend and contains the
+    encrypted data.  You can specify it as a path like /dev/xxx or a device
+    number <major>:<minor>.
+
+<offset>
+    Starting sector within the device where the encrypted data begins.
+
+Example scripts
+===============
+LUKS (Linux Unified Key Setup) is now the preferred way to set up disk
+encryption with dm-crypt using the 'cryptsetup' utility, see
+http://luks.endorphin.org/
+
+[[
+#!/bin/sh
+# Create a crypt device using dmsetup
+dmsetup create crypt1 --table "0 `blockdev --getsize $1` crypt aes-cbc-essiv:sha256 babebabebabebabebabebabebabebabe 0 $1 0"
+]]
+
+[[
+#!/bin/sh
+# Create a crypt device using cryptsetup and LUKS header with default cipher
+cryptsetup luksFormat $1
+cryptsetup luksOpen $1 crypt1
+]]
index d9aa7ed..7be09ee 100644 (file)
@@ -3,10 +3,10 @@
 #
 
 dm-mod-objs    := dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
-                  dm-ioctl.o dm-io.o kcopyd.o
+                  dm-ioctl.o dm-io.o dm-kcopyd.o
 dm-multipath-objs := dm-hw-handler.o dm-path-selector.o dm-mpath.o
 dm-snapshot-objs := dm-snap.o dm-exception-store.o
-dm-mirror-objs := dm-log.o dm-raid1.o
+dm-mirror-objs := dm-raid1.o
 dm-rdac-objs   := dm-mpath-rdac.o
 dm-hp-sw-objs  := dm-mpath-hp-sw.o
 md-mod-objs     := md.o bitmap.o
@@ -39,7 +39,7 @@ obj-$(CONFIG_DM_MULTIPATH_EMC)        += dm-emc.o
 obj-$(CONFIG_DM_MULTIPATH_HP)  += dm-hp-sw.o
 obj-$(CONFIG_DM_MULTIPATH_RDAC)        += dm-rdac.o
 obj-$(CONFIG_DM_SNAPSHOT)      += dm-snapshot.o
-obj-$(CONFIG_DM_MIRROR)                += dm-mirror.o
+obj-$(CONFIG_DM_MIRROR)                += dm-mirror.o dm-log.o
 obj-$(CONFIG_DM_ZERO)          += dm-zero.o
 
 quiet_cmd_unroll = UNROLL  $@
index 5bbce29..41f4080 100644 (file)
@@ -9,13 +9,13 @@
 
 #include "dm.h"
 #include "dm-snap.h"
-#include "dm-io.h"
-#include "kcopyd.h"
 
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <linux/dm-io.h>
+#include <linux/dm-kcopyd.h>
 
 #define DM_MSG_PREFIX "snapshots"
 #define DM_CHUNK_SIZE_DEFAULT_SECTORS 32       /* 16KB */
@@ -131,7 +131,7 @@ struct pstore {
 
 static unsigned sectors_to_pages(unsigned sectors)
 {
-       return sectors / (PAGE_SIZE >> 9);
+       return DIV_ROUND_UP(sectors, PAGE_SIZE >> 9);
 }
 
 static int alloc_area(struct pstore *ps)
@@ -159,7 +159,7 @@ static void free_area(struct pstore *ps)
 }
 
 struct mdata_req {
-       struct io_region *where;
+       struct dm_io_region *where;
        struct dm_io_request *io_req;
        struct work_struct work;
        int result;
@@ -177,7 +177,7 @@ static void do_metadata(struct work_struct *work)
  */
 static int chunk_io(struct pstore *ps, uint32_t chunk, int rw, int metadata)
 {
-       struct io_region where = {
+       struct dm_io_region where = {
                .bdev = ps->snap->cow->bdev,
                .sector = ps->snap->chunk_size * chunk,
                .count = ps->snap->chunk_size,
index 8f25f62..4789c42 100644 (file)
@@ -5,13 +5,14 @@
  * This file is released under the GPL.
  */
 
-#include "dm-io.h"
+#include "dm.h"
 
 #include <linux/bio.h>
 #include <linux/mempool.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/dm-io.h>
 
 struct dm_io_client {
        mempool_t *pool;
@@ -20,7 +21,7 @@ struct dm_io_client {
 
 /* FIXME: can we shrink this ? */
 struct io {
-       unsigned long error;
+       unsigned long error_bits;
        atomic_t count;
        struct task_struct *sleeper;
        struct dm_io_client *client;
@@ -107,14 +108,14 @@ static inline unsigned bio_get_region(struct bio *bio)
 static void dec_count(struct io *io, unsigned int region, int error)
 {
        if (error)
-               set_bit(region, &io->error);
+               set_bit(region, &io->error_bits);
 
        if (atomic_dec_and_test(&io->count)) {
                if (io->sleeper)
                        wake_up_process(io->sleeper);
 
                else {
-                       unsigned long r = io->error;
+                       unsigned long r = io->error_bits;
                        io_notify_fn fn = io->callback;
                        void *context = io->context;
 
@@ -271,7 +272,7 @@ static void km_dp_init(struct dpages *dp, void *data)
 /*-----------------------------------------------------------------
  * IO routines that accept a list of pages.
  *---------------------------------------------------------------*/
-static void do_region(int rw, unsigned int region, struct io_region *where,
+static void do_region(int rw, unsigned region, struct dm_io_region *where,
                      struct dpages *dp, struct io *io)
 {
        struct bio *bio;
@@ -320,7 +321,7 @@ static void do_region(int rw, unsigned int region, struct io_region *where,
 }
 
 static void dispatch_io(int rw, unsigned int num_regions,
-                       struct io_region *where, struct dpages *dp,
+                       struct dm_io_region *where, struct dpages *dp,
                        struct io *io, int sync)
 {
        int i;
@@ -347,17 +348,17 @@ static void dispatch_io(int rw, unsigned int num_regions,
 }
 
 static int sync_io(struct dm_io_client *client, unsigned int num_regions,
-                  struct io_region *where, int rw, struct dpages *dp,
+                  struct dm_io_region *where, int rw, struct dpages *dp,
                   unsigned long *error_bits)
 {
        struct io io;
 
-       if (num_regions > 1 && rw != WRITE) {
+       if (num_regions > 1 && (rw & RW_MASK) != WRITE) {
                WARN_ON(1);
                return -EIO;
        }
 
-       io.error = 0;
+       io.error_bits = 0;
        atomic_set(&io.count, 1); /* see dispatch_io() */
        io.sleeper = current;
        io.client = client;
@@ -378,25 +379,25 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions,
                return -EINTR;
 
        if (error_bits)
-               *error_bits = io.error;
+               *error_bits = io.error_bits;
 
-       return io.error ? -EIO : 0;
+       return io.error_bits ? -EIO : 0;
 }
 
 static int async_io(struct dm_io_client *client, unsigned int num_regions,
-                   struct io_region *where, int rw, struct dpages *dp,
+                   struct dm_io_region *where, int rw, struct dpages *dp,
                    io_notify_fn fn, void *context)
 {
        struct io *io;
 
-       if (num_regions > 1 && rw != WRITE) {
+       if (num_regions > 1 && (rw & RW_MASK) != WRITE) {
                WARN_ON(1);
                fn(1, context);
                return -EIO;
        }
 
        io = mempool_alloc(client->pool, GFP_NOIO);
-       io->error = 0;
+       io->error_bits = 0;
        atomic_set(&io->count, 1); /* see dispatch_io() */
        io->sleeper = NULL;
        io->client = client;
@@ -435,10 +436,15 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp)
 }
 
 /*
- * New collapsed (a)synchronous interface
+ * New collapsed (a)synchronous interface.
+ *
+ * If the IO is asynchronous (i.e. it has notify.fn), you must either unplug
+ * the queue with blk_unplug() some time later or set the BIO_RW_SYNC bit in
+ * io_req->bi_rw. If you fail to do one of these, the IO will be submitted to
+ * the disk after q->unplug_delay, which defaults to 3ms in blk-settings.c.
  */
 int dm_io(struct dm_io_request *io_req, unsigned num_regions,
-         struct io_region *where, unsigned long *sync_error_bits)
+         struct dm_io_region *where, unsigned long *sync_error_bits)
 {
        int r;
        struct dpages dp;
similarity index 71%
rename from drivers/md/kcopyd.c
rename to drivers/md/dm-kcopyd.c
index e76b52a..996802b 100644 (file)
@@ -9,9 +9,8 @@
  * completion notification.
  */
 
-#include <asm/types.h>
+#include <linux/types.h>
 #include <asm/atomic.h>
-
 #include <linux/blkdev.h>
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/vmalloc.h>
 #include <linux/workqueue.h>
 #include <linux/mutex.h>
+#include <linux/dm-kcopyd.h>
 
-#include "kcopyd.h"
-
-static struct workqueue_struct *_kcopyd_wq;
-static struct work_struct _kcopyd_work;
-
-static void wake(void)
-{
-       queue_work(_kcopyd_wq, &_kcopyd_work);
-}
+#include "dm.h"
 
 /*-----------------------------------------------------------------
  * Each kcopyd client has its own little pool of preallocated
  * pages for kcopyd io.
  *---------------------------------------------------------------*/
-struct kcopyd_client {
-       struct list_head list;
-
+struct dm_kcopyd_client {
        spinlock_t lock;
        struct page_list *pages;
        unsigned int nr_pages;
@@ -50,8 +40,32 @@ struct kcopyd_client {
 
        wait_queue_head_t destroyq;
        atomic_t nr_jobs;
+
+       mempool_t *job_pool;
+
+       struct workqueue_struct *kcopyd_wq;
+       struct work_struct kcopyd_work;
+
+/*
+ * We maintain three 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.
+ *
+ * All three of these are protected by job_lock.
+ */
+       spinlock_t job_lock;
+       struct list_head complete_jobs;
+       struct list_head io_jobs;
+       struct list_head pages_jobs;
 };
 
+static void wake(struct dm_kcopyd_client *kc)
+{
+       queue_work(kc->kcopyd_wq, &kc->kcopyd_work);
+}
+
 static struct page_list *alloc_pl(void)
 {
        struct page_list *pl;
@@ -75,7 +89,7 @@ static void free_pl(struct page_list *pl)
        kfree(pl);
 }
 
-static int kcopyd_get_pages(struct kcopyd_client *kc,
+static int kcopyd_get_pages(struct dm_kcopyd_client *kc,
                            unsigned int nr, struct page_list **pages)
 {
        struct page_list *pl;
@@ -98,7 +112,7 @@ static int kcopyd_get_pages(struct kcopyd_client *kc,
        return 0;
 }
 
-static void kcopyd_put_pages(struct kcopyd_client *kc, struct page_list *pl)
+static void kcopyd_put_pages(struct dm_kcopyd_client *kc, struct page_list *pl)
 {
        struct page_list *cursor;
 
@@ -126,7 +140,7 @@ static void drop_pages(struct page_list *pl)
        }
 }
 
-static int client_alloc_pages(struct kcopyd_client *kc, unsigned int nr)
+static int client_alloc_pages(struct dm_kcopyd_client *kc, unsigned int nr)
 {
        unsigned int i;
        struct page_list *pl = NULL, *next;
@@ -147,7 +161,7 @@ static int client_alloc_pages(struct kcopyd_client *kc, unsigned int nr)
        return 0;
 }
 
-static void client_free_pages(struct kcopyd_client *kc)
+static void client_free_pages(struct dm_kcopyd_client *kc)
 {
        BUG_ON(kc->nr_free_pages != kc->nr_pages);
        drop_pages(kc->pages);
@@ -161,7 +175,7 @@ static void client_free_pages(struct kcopyd_client *kc)
  * ever having to do io (which could cause a deadlock).
  *---------------------------------------------------------------*/
 struct kcopyd_job {
-       struct kcopyd_client *kc;
+       struct dm_kcopyd_client *kc;
        struct list_head list;
        unsigned long flags;
 
@@ -175,13 +189,13 @@ struct kcopyd_job {
         * Either READ or WRITE
         */
        int rw;
-       struct io_region source;
+       struct dm_io_region source;
 
        /*
         * The destinations for the transfer.
         */
        unsigned int num_dests;
-       struct io_region dests[KCOPYD_MAX_REGIONS];
+       struct dm_io_region dests[DM_KCOPYD_MAX_REGIONS];
 
        sector_t offset;
        unsigned int nr_pages;
@@ -191,7 +205,7 @@ struct kcopyd_job {
         * Set this to ensure you are notified when the job has
         * completed.  'context' is for callback to use.
         */
-       kcopyd_notify_fn fn;
+       dm_kcopyd_notify_fn fn;
        void *context;
 
        /*
@@ -207,47 +221,19 @@ struct kcopyd_job {
 #define MIN_JOBS 512
 
 static struct kmem_cache *_job_cache;
-static mempool_t *_job_pool;
 
-/*
- * We maintain three 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.
- *
- * All three of these are protected by job_lock.
- */
-static DEFINE_SPINLOCK(_job_lock);
-
-static LIST_HEAD(_complete_jobs);
-static LIST_HEAD(_io_jobs);
-static LIST_HEAD(_pages_jobs);
-
-static int jobs_init(void)
+int __init dm_kcopyd_init(void)
 {
        _job_cache = KMEM_CACHE(kcopyd_job, 0);
        if (!_job_cache)
                return -ENOMEM;
 
-       _job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache);
-       if (!_job_pool) {
-               kmem_cache_destroy(_job_cache);
-               return -ENOMEM;
-       }
-
        return 0;
 }
 
-static void jobs_exit(void)
+void dm_kcopyd_exit(void)
 {
-       BUG_ON(!list_empty(&_complete_jobs));
-       BUG_ON(!list_empty(&_io_jobs));
-       BUG_ON(!list_empty(&_pages_jobs));
-
-       mempool_destroy(_job_pool);
        kmem_cache_destroy(_job_cache);
-       _job_pool = NULL;
        _job_cache = NULL;
 }
 
@@ -255,18 +241,19 @@ static void jobs_exit(void)
  * Functions to push and pop a job onto the head of a given job
  * list.
  */
-static struct kcopyd_job *pop(struct list_head *jobs)
+static struct kcopyd_job *pop(struct list_head *jobs,
+                             struct dm_kcopyd_client *kc)
 {
        struct kcopyd_job *job = NULL;
        unsigned long flags;
 
-       spin_lock_irqsave(&_job_lock, flags);
+       spin_lock_irqsave(&kc->job_lock, flags);
 
        if (!list_empty(jobs)) {
                job = list_entry(jobs->next, struct kcopyd_job, list);
                list_del(&job->list);
        }
-       spin_unlock_irqrestore(&_job_lock, flags);
+       spin_unlock_irqrestore(&kc->job_lock, flags);
 
        return job;
 }
@@ -274,10 +261,11 @@ static struct kcopyd_job *pop(struct list_head *jobs)
 static void push(struct list_head *jobs, struct kcopyd_job *job)
 {
        unsigned long flags;
+       struct dm_kcopyd_client *kc = job->kc;
 
-       spin_lock_irqsave(&_job_lock, flags);
+       spin_lock_irqsave(&kc->job_lock, flags);
        list_add_tail(&job->list, jobs);
-       spin_unlock_irqrestore(&_job_lock, flags);
+       spin_unlock_irqrestore(&kc->job_lock, flags);
 }
 
 /*
@@ -294,11 +282,11 @@ static int run_complete_job(struct kcopyd_job *job)
        void *context = job->context;
        int read_err = job->read_err;
        unsigned long write_err = job->write_err;
-       kcopyd_notify_fn fn = job->fn;
-       struct kcopyd_client *kc = job->kc;
+       dm_kcopyd_notify_fn fn = job->fn;
+       struct dm_kcopyd_client *kc = job->kc;
 
        kcopyd_put_pages(kc, job->pages);
-       mempool_free(job, _job_pool);
+       mempool_free(job, kc->job_pool);
        fn(read_err, write_err, context);
 
        if (atomic_dec_and_test(&kc->nr_jobs))
@@ -310,6 +298,7 @@ static int run_complete_job(struct kcopyd_job *job)
 static void complete_io(unsigned long error, void *context)
 {
        struct kcopyd_job *job = (struct kcopyd_job *) context;
+       struct dm_kcopyd_client *kc = job->kc;
 
        if (error) {
                if (job->rw == WRITE)
@@ -317,22 +306,22 @@ static void complete_io(unsigned long error, void *context)
                else
                        job->read_err = 1;
 
-               if (!test_bit(KCOPYD_IGNORE_ERROR, &job->flags)) {
-                       push(&_complete_jobs, job);
-                       wake();
+               if (!test_bit(DM_KCOPYD_IGNORE_ERROR, &job->flags)) {
+                       push(&kc->complete_jobs, job);
+                       wake(kc);
                        return;
                }
        }
 
        if (job->rw == WRITE)
-               push(&_complete_jobs, job);
+               push(&kc->complete_jobs, job);
 
        else {
                job->rw = WRITE;
-               push(&_io_jobs, job);
+               push(&kc->io_jobs, job);
        }
 
-       wake();
+       wake(kc);
 }
 
 /*
@@ -343,7 +332,7 @@ static int run_io_job(struct kcopyd_job *job)
 {
        int r;
        struct dm_io_request io_req = {
-               .bi_rw = job->rw,
+               .bi_rw = job->rw | (1 << BIO_RW_SYNC),
                .mem.type = DM_IO_PAGE_LIST,
                .mem.ptr.pl = job->pages,
                .mem.offset = job->offset,
@@ -369,7 +358,7 @@ static int run_pages_job(struct kcopyd_job *job)
        r = kcopyd_get_pages(job->kc, job->nr_pages, &job->pages);
        if (!r) {
                /* this job is ready for io */
-               push(&_io_jobs, job);
+               push(&job->kc->io_jobs, job);
                return 0;
        }
 
@@ -384,12 +373,13 @@ static int run_pages_job(struct kcopyd_job *job)
  * Run through a list for as long as possible.  Returns the count
  * of successful jobs.
  */
-static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *))
+static int process_jobs(struct list_head *jobs, struct dm_kcopyd_client *kc,
+                       int (*fn) (struct kcopyd_job *))
 {
        struct kcopyd_job *job;
        int r, count = 0;
 
-       while ((job = pop(jobs))) {
+       while ((job = pop(jobs, kc))) {
 
                r = fn(job);
 
@@ -399,7 +389,7 @@ static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *))
                                job->write_err = (unsigned long) -1L;
                        else
                                job->read_err = 1;
-                       push(&_complete_jobs, job);
+                       push(&kc->complete_jobs, job);
                        break;
                }
 
@@ -421,8 +411,11 @@ static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *))
 /*
  * kcopyd does this every time it's woken up.
  */
-static void do_work(struct work_struct *ignored)
+static void do_work(struct work_struct *work)
 {
+       struct dm_kcopyd_client *kc = container_of(work,
+                                       struct dm_kcopyd_client, kcopyd_work);
+
        /*
         * The order that these are called is *very* important.
         * complete jobs can free some pages for pages jobs.
@@ -430,9 +423,9 @@ static void do_work(struct work_struct *ignored)
         * list.  io jobs call wake when they complete and it all
         * starts again.
         */
-       process_jobs(&_complete_jobs, run_complete_job);
-       process_jobs(&_pages_jobs, run_pages_job);
-       process_jobs(&_io_jobs, run_io_job);
+       process_jobs(&kc->complete_jobs, kc, run_complete_job);
+       process_jobs(&kc->pages_jobs, kc, run_pages_job);
+       process_jobs(&kc->io_jobs, kc, run_io_job);
 }
 
 /*
@@ -442,9 +435,10 @@ static void do_work(struct work_struct *ignored)
  */
 static void dispatch_job(struct kcopyd_job *job)
 {
-       atomic_inc(&job->kc->nr_jobs);
-       push(&_pages_jobs, job);
-       wake();
+       struct dm_kcopyd_client *kc = job->kc;
+       atomic_inc(&kc->nr_jobs);
+       push(&kc->pages_jobs, job);
+       wake(kc);
 }
 
 #define SUB_JOB_SIZE 128
@@ -469,7 +463,7 @@ static void segment_complete(int read_err, unsigned long write_err,
         * Only dispatch more work if there hasn't been an error.
         */
        if ((!job->read_err && !job->write_err) ||
-           test_bit(KCOPYD_IGNORE_ERROR, &job->flags)) {
+           test_bit(DM_KCOPYD_IGNORE_ERROR, &job->flags)) {
                /* get the next chunk of work */
                progress = job->progress;
                count = job->source.count - progress;
@@ -484,7 +478,8 @@ static void segment_complete(int read_err, unsigned long write_err,
 
        if (count) {
                int i;
-               struct kcopyd_job *sub_job = mempool_alloc(_job_pool, GFP_NOIO);
+               struct kcopyd_job *sub_job = mempool_alloc(job->kc->job_pool,
+                                                          GFP_NOIO);
 
                *sub_job = *job;
                sub_job->source.sector += progress;
@@ -508,7 +503,7 @@ static void segment_complete(int read_err, unsigned long write_err,
                 * after we've completed.
                 */
                job->fn(read_err, write_err, job->context);
-               mempool_free(job, _job_pool);
+               mempool_free(job, job->kc->job_pool);
        }
 }
 
@@ -526,16 +521,16 @@ static void split_job(struct kcopyd_job *job)
                segment_complete(0, 0u, job);
 }
 
-int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from,
-               unsigned int num_dests, struct io_region *dests,
-               unsigned int flags, kcopyd_notify_fn fn, void *context)
+int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
+                  unsigned int num_dests, struct dm_io_region *dests,
+                  unsigned int flags, dm_kcopyd_notify_fn fn, void *context)
 {
        struct kcopyd_job *job;
 
        /*
         * Allocate a new job.
         */
-       job = mempool_alloc(_job_pool, GFP_NOIO);
+       job = mempool_alloc(kc->job_pool, GFP_NOIO);
 
        /*
         * set up for the read.
@@ -569,6 +564,7 @@ int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from,
 
        return 0;
 }
+EXPORT_SYMBOL(dm_kcopyd_copy);
 
 /*
  * Cancels a kcopyd job, eg. someone might be deactivating a
@@ -583,126 +579,76 @@ int kcopyd_cancel(struct kcopyd_job *job, int block)
 #endif  /*  0  */
 
 /*-----------------------------------------------------------------
- * Unit setup
+ * Client setup
  *---------------------------------------------------------------*/
-static DEFINE_MUTEX(_client_lock);
-static LIST_HEAD(_clients);
-
-static void client_add(struct kcopyd_client *kc)
+int dm_kcopyd_client_create(unsigned int nr_pages,
+                           struct dm_kcopyd_client **result)
 {
-       mutex_lock(&_client_lock);
-       list_add(&kc->list, &_clients);
-       mutex_unlock(&_client_lock);
-}
-
-static void client_del(struct kcopyd_client *kc)
-{
-       mutex_lock(&_client_lock);
-       list_del(&kc->list);
-       mutex_unlock(&_client_lock);
-}
-
-static DEFINE_MUTEX(kcopyd_init_lock);
-static int kcopyd_clients = 0;
+       int r = -ENOMEM;
+       struct dm_kcopyd_client *kc;
 
-static int kcopyd_init(void)
-{
-       int r;
-
-       mutex_lock(&kcopyd_init_lock);
-
-       if (kcopyd_clients) {
-               /* Already initialized. */
-               kcopyd_clients++;
-               mutex_unlock(&kcopyd_init_lock);
-               return 0;
-       }
-
-       r = jobs_init();
-       if (r) {
-               mutex_unlock(&kcopyd_init_lock);
-               return r;
-       }
-
-       _kcopyd_wq = create_singlethread_workqueue("kcopyd");
-       if (!_kcopyd_wq) {
-               jobs_exit();
-               mutex_unlock(&kcopyd_init_lock);
+       kc = kmalloc(sizeof(*kc), GFP_KERNEL);
+       if (!kc)
                return -ENOMEM;
-       }
-
-       kcopyd_clients++;
-       INIT_WORK(&_kcopyd_work, do_work);
-       mutex_unlock(&kcopyd_init_lock);
-       return 0;
-}
 
-static void kcopyd_exit(void)
-{
-       mutex_lock(&kcopyd_init_lock);
-       kcopyd_clients--;
-       if (!kcopyd_clients) {
-               jobs_exit();
-               destroy_workqueue(_kcopyd_wq);
-               _kcopyd_wq = NULL;
-       }
-       mutex_unlock(&kcopyd_init_lock);
-}
-
-int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
-{
-       int r = 0;
-       struct kcopyd_client *kc;
+       spin_lock_init(&kc->lock);
+       spin_lock_init(&kc->job_lock);
+       INIT_LIST_HEAD(&kc->complete_jobs);
+       INIT_LIST_HEAD(&kc->io_jobs);
+       INIT_LIST_HEAD(&kc->pages_jobs);
 
-       r = kcopyd_init();
-       if (r)
-               return r;
+       kc->job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache);
+       if (!kc->job_pool)
+               goto bad_slab;
 
-       kc = kmalloc(sizeof(*kc), GFP_KERNEL);
-       if (!kc) {
-               kcopyd_exit();
-               return -ENOMEM;
-       }
+       INIT_WORK(&kc->kcopyd_work, do_work);
+       kc->kcopyd_wq = create_singlethread_workqueue("kcopyd");
+       if (!kc->kcopyd_wq)
+               goto bad_workqueue;
 
-       spin_lock_init(&kc->lock);
        kc->pages = NULL;
        kc->nr_pages = kc->nr_free_pages = 0;
        r = client_alloc_pages(kc, nr_pages);
-       if (r) {
-               kfree(kc);
-               kcopyd_exit();
-               return r;
-       }
+       if (r)
+               goto bad_client_pages;
 
        kc->io_client = dm_io_client_create(nr_pages);
        if (IS_ERR(kc->io_client)) {
                r = PTR_ERR(kc->io_client);
-               client_free_pages(kc);
-               kfree(kc);
-               kcopyd_exit();
-               return r;
+               goto bad_io_client;
        }
 
        init_waitqueue_head(&kc->destroyq);
        atomic_set(&kc->nr_jobs, 0);
 
-       client_add(kc);
        *result = kc;
        return 0;
+
+bad_io_client:
+       client_free_pages(kc);
+bad_client_pages:
+       destroy_workqueue(kc->kcopyd_wq);
+bad_workqueue:
+       mempool_destroy(kc->job_pool);
+bad_slab:
+       kfree(kc);
+
+       return r;
 }
+EXPORT_SYMBOL(dm_kcopyd_client_create);
 
-void kcopyd_client_destroy(struct kcopyd_client *kc)
+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->complete_jobs));
+       BUG_ON(!list_empty(&kc->io_jobs));
+       BUG_ON(!list_empty(&kc->pages_jobs));
+       destroy_workqueue(kc->kcopyd_wq);
        dm_io_client_destroy(kc->io_client);
        client_free_pages(kc);
-       client_del(kc);
+       mempool_destroy(kc->job_pool);
        kfree(kc);
-       kcopyd_exit();
 }
-
-EXPORT_SYMBOL(kcopyd_client_create);
-EXPORT_SYMBOL(kcopyd_client_destroy);
-EXPORT_SYMBOL(kcopyd_copy);
+EXPORT_SYMBOL(dm_kcopyd_client_destroy);
index 2a74b21..67a6f31 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2003 Sistina Software
+ * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
  *
  * This file is released under the LGPL.
  */
@@ -8,64 +9,58 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
+#include <linux/dm-io.h>
+#include <linux/dm-dirty-log.h>
 
-#include "dm-log.h"
-#include "dm-io.h"
+#include "dm.h"
 
-#define DM_MSG_PREFIX "mirror log"
+#define DM_MSG_PREFIX "dirty region log"
 
-static LIST_HEAD(_log_types);
-static DEFINE_SPINLOCK(_lock);
+struct dm_dirty_log_internal {
+       struct dm_dirty_log_type *type;
 
-int dm_register_dirty_log_type(struct dirty_log_type *type)
-{
-       spin_lock(&_lock);
-       type->use_count = 0;
-       list_add(&type->list, &_log_types);
-       spin_unlock(&_lock);
+       struct list_head list;
+       long use;
+};
 
-       return 0;
-}
+static LIST_HEAD(_log_types);
+static DEFINE_SPINLOCK(_lock);
 
-int dm_unregister_dirty_log_type(struct dirty_log_type *type)
+static struct dm_dirty_log_internal *__find_dirty_log_type(const char *name)
 {
-       spin_lock(&_lock);
-
-       if (type->use_count)
-               DMWARN("Attempt to unregister a log type that is still in use");
-       else
-               list_del(&type->list);
+       struct dm_dirty_log_internal *log_type;
 
-       spin_unlock(&_lock);
+       list_for_each_entry(log_type, &_log_types, list)
+               if (!strcmp(name, log_type->type->name))
+                       return log_type;
 
-       return 0;
+       return NULL;
 }
 
-static struct dirty_log_type *_get_type(const char *type_name)
+static struct dm_dirty_log_internal *_get_dirty_log_type(const char *name)
 {
-       struct dirty_log_type *type;
+       struct dm_dirty_log_internal *log_type;
 
        spin_lock(&_lock);
-       list_for_each_entry (type, &_log_types, list)
-               if (!strcmp(type_name, type->name)) {
-                       if (!type->use_count && !try_module_get(type->module)){
-                               spin_unlock(&_lock);
-                               return NULL;
-                       }
-                       type->use_count++;
-                       spin_unlock(&_lock);
-                       return type;
-               }
+
+       log_type = __find_dirty_log_type(name);
+       if (log_type) {
+               if (!log_type->use && !try_module_get(log_type->type->module))
+                       log_type = NULL;
+               else
+                       log_type->use++;
+       }
 
        spin_unlock(&_lock);
-       return NULL;
+
+       return log_type;
 }
 
 /*
  * get_type
  * @type_name
  *
- * Attempt to retrieve the dirty_log_type by name.  If not already
+ * Attempt to retrieve the dm_dirty_log_type by name.  If not already
  * available, attempt to load the appropriate module.
  *
  * Log modules are named "dm-log-" followed by the 'type_name'.
@@ -78,14 +73,17 @@ static struct dirty_log_type *_get_type(const char *type_name)
  *
  * Returns: dirty_log_type* on success, NULL on failure
  */
-static struct dirty_log_type *get_type(const char *type_name)
+static struct dm_dirty_log_type *get_type(const char *type_name)
 {
        char *p, *type_name_dup;
-       struct dirty_log_type *type;
+       struct dm_dirty_log_internal *log_type;
+
+       if (!type_name)
+               return NULL;
 
-       type = _get_type(type_name);
-       if (type)
-               return type;
+       log_type = _get_dirty_log_type(type_name);
+       if (log_type)
+               return log_type->type;
 
        type_name_dup = kstrdup(type_name, GFP_KERNEL);
        if (!type_name_dup) {
@@ -95,34 +93,106 @@ static struct dirty_log_type *get_type(const char *type_name)
        }
 
        while (request_module("dm-log-%s", type_name_dup) ||
-              !(type = _get_type(type_name))) {
+              !(log_type = _get_dirty_log_type(type_name))) {
                p = strrchr(type_name_dup, '-');
                if (!p)
                        break;
                p[0] = '\0';
        }
 
-       if (!type)
+       if (!log_type)
                DMWARN("Module for logging type \"%s\" not found.", type_name);
 
        kfree(type_name_dup);
 
-       return type;
+       return log_type ? log_type->type : NULL;
 }
 
-static void put_type(struct dirty_log_type *type)
+static void put_type(struct dm_dirty_log_type *type)
 {
+       struct dm_dirty_log_internal *log_type;
+
+       if (!type)
+               return;
+
        spin_lock(&_lock);
-       if (!--type->use_count)
+       log_type = __find_dirty_log_type(type->name);
+       if (!log_type)
+               goto out;
+
+       if (!--log_type->use)
                module_put(type->module);
+
+       BUG_ON(log_type->use < 0);
+
+out:
        spin_unlock(&_lock);
 }
 
-struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *ti,
-                                     unsigned int argc, char **argv)
+static struct dm_dirty_log_internal *_alloc_dirty_log_type(struct dm_dirty_log_type *type)
 {
-       struct dirty_log_type *type;
-       struct dirty_log *log;
+       struct dm_dirty_log_internal *log_type = kzalloc(sizeof(*log_type),
+                                                        GFP_KERNEL);
+
+       if (log_type)
+               log_type->type = type;
+
+       return log_type;
+}
+
+int dm_dirty_log_type_register(struct dm_dirty_log_type *type)
+{
+       struct dm_dirty_log_internal *log_type = _alloc_dirty_log_type(type);
+       int r = 0;
+
+       if (!log_type)
+               return -ENOMEM;
+
+       spin_lock(&_lock);
+       if (!__find_dirty_log_type(type->name))
+               list_add(&log_type->list, &_log_types);
+       else {
+               kfree(log_type);
+               r = -EEXIST;
+       }
+       spin_unlock(&_lock);
+
+       return r;
+}
+EXPORT_SYMBOL(dm_dirty_log_type_register);
+
+int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type)
+{
+       struct dm_dirty_log_internal *log_type;
+
+       spin_lock(&_lock);
+
+       log_type = __find_dirty_log_type(type->name);
+       if (!log_type) {
+               spin_unlock(&_lock);
+               return -EINVAL;
+       }
+
+       if (log_type->use) {
+               spin_unlock(&_lock);
+               return -ETXTBSY;
+       }
+
+       list_del(&log_type->list);
+
+       spin_unlock(&_lock);
+       kfree(log_type);
+
+       return 0;
+}
+EXPORT_SYMBOL(dm_dirty_log_type_unregister);
+
+struct dm_dirty_log *dm_dirty_log_create(const char *type_name,
+                                        struct dm_target *ti,
+                                        unsigned int argc, char **argv)
+{
+       struct dm_dirty_log_type *type;
+       struct dm_dirty_log *log;
 
        log = kmalloc(sizeof(*log), GFP_KERNEL);
        if (!log)
@@ -143,13 +213,15 @@ struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *t
 
        return log;
 }
+EXPORT_SYMBOL(dm_dirty_log_create);
 
-void dm_destroy_dirty_log(struct dirty_log *log)
+void dm_dirty_log_destroy(struct dm_dirty_log *log)
 {
        log->type->dtr(log);
        put_type(log->type);
        kfree(log);
 }
+EXPORT_SYMBOL(dm_dirty_log_destroy);
 
 /*-----------------------------------------------------------------
  * Persistent and core logs share a lot of their implementation.
@@ -207,7 +279,7 @@ struct log_c {
        struct dm_dev *log_dev;
        struct log_header header;
 
-       struct io_region header_location;
+       struct dm_io_region header_location;
        struct log_header *disk_header;
 };
 
@@ -215,7 +287,7 @@ struct log_c {
  * The touched member needs to be updated every time we access
  * one of the bitsets.
  */
-static  inline int log_test_bit(uint32_t *bs, unsigned bit)
+static inline int log_test_bit(uint32_t *bs, unsigned bit)
 {
        return ext2_test_bit(bit, (unsigned long *) bs) ? 1 : 0;
 }
@@ -302,7 +374,7 @@ static inline int write_header(struct log_c *log)
  * argv contains region_size followed optionally by [no]sync
  *--------------------------------------------------------------*/
 #define BYTE_SHIFT 3
-static int create_log_context(struct dirty_log *log, struct dm_target *ti,
+static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
                              unsigned int argc, char **argv,
                              struct dm_dev *dev)
 {
@@ -315,7 +387,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
        int r;
 
        if (argc < 1 || argc > 2) {
-               DMWARN("wrong number of arguments to mirror log");
+               DMWARN("wrong number of arguments to dirty region log");
                return -EINVAL;
        }
 
@@ -325,8 +397,8 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
                else if (!strcmp(argv[1], "nosync"))
                        sync = NOSYNC;
                else {
-                       DMWARN("unrecognised sync argument to mirror log: %s",
-                              argv[1]);
+                       DMWARN("unrecognised sync argument to "
+                              "dirty region log: %s", argv[1]);
                        return -EINVAL;
                }
        }
@@ -434,7 +506,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
        return 0;
 }
 
-static int core_ctr(struct dirty_log *log, struct dm_target *ti,
+static int core_ctr(struct dm_dirty_log *log, struct dm_target *ti,
                    unsigned int argc, char **argv)
 {
        return create_log_context(log, ti, argc, argv, NULL);
@@ -447,7 +519,7 @@ static void destroy_log_context(struct log_c *lc)
        kfree(lc);
 }
 
-static void core_dtr(struct dirty_log *log)
+static void core_dtr(struct dm_dirty_log *log)
 {
        struct log_c *lc = (struct log_c *) log->context;
 
@@ -460,14 +532,14 @@ static void core_dtr(struct dirty_log *log)
  *
  * argv contains log_device region_size followed optionally by [no]sync
  *--------------------------------------------------------------*/
-static int disk_ctr(struct dirty_log *log, struct dm_target *ti,
+static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti,
                    unsigned int argc, char **argv)
 {
        int r;
        struct dm_dev *dev;
 
        if (argc < 2 || argc > 3) {
-               DMWARN("wrong number of arguments to disk mirror log");
+               DMWARN("wrong number of arguments to disk dirty region log");
                return -EINVAL;
        }
 
@@ -485,7 +557,7 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti,
        return 0;
 }
 
-static void disk_dtr(struct dirty_log *log)
+static void disk_dtr(struct dm_dirty_log *log)
 {
        struct log_c *lc = (struct log_c *) log->context;
 
@@ -514,7 +586,7 @@ static void fail_log_device(struct log_c *lc)
        dm_table_event(lc->ti->table);
 }
 
-static int disk_resume(struct dirty_log *log)
+static int disk_resume(struct dm_dirty_log *log)
 {
        int r;
        unsigned i;
@@ -524,7 +596,7 @@ static int disk_resume(struct dirty_log *log)
        /* read the disk header */
        r = read_header(lc);
        if (r) {
-               DMWARN("%s: Failed to read header on mirror log device",
+               DMWARN("%s: Failed to read header on dirty region log device",
                       lc->log_dev->name);
                fail_log_device(lc);
                /*
@@ -562,7 +634,7 @@ static int disk_resume(struct dirty_log *log)
        /* write the new header */
        r = write_header(lc);
        if (r) {
-               DMWARN("%s: Failed to write header on mirror log device",
+               DMWARN("%s: Failed to write header on dirty region log device",
                       lc->log_dev->name);
                fail_log_device(lc);
        }
@@ -570,38 +642,38 @@ static int disk_resume(struct dirty_log *log)
        return r;
 }
 
-static uint32_t core_get_region_size(struct dirty_log *log)
+static uint32_t core_get_region_size(struct dm_dirty_log *log)
 {
        struct log_c *lc = (struct log_c *) log->context;
        return lc->region_size;
 }
 
-static int core_resume(struct dirty_log *log)
+static int core_resume(struct dm_dirty_log *log)
 {
        struct log_c *lc = (struct log_c *) log->context;
        lc->sync_search = 0;
        return 0;
 }
 
-static int core_is_clean(struct dirty_log *log, region_t region)
+static int core_is_clean(struct dm_dirty_log *log, region_t region)
 {
        struct log_c *lc = (struct log_c *) log->context;
        return log_test_bit(lc->clean_bits, region);
 }
 
-static int core_in_sync(struct dirty_log *log, region_t region, int block)
+static int core_in_sync(struct dm_dirty_log *log, region_t region, int block)
 {
        struct log_c *lc = (struct log_c *) log->context;
        return log_test_bit(lc->sync_bits, region);
 }
 
-static int core_flush(struct dirty_log *log)
+static int core_flush(struct dm_dirty_log *log)
 {
        /* no op */
        return 0;
 }
 
-static int disk_flush(struct dirty_log *log)
+static int disk_flush(struct dm_dirty_log *log)
 {
        int r;
        struct log_c *lc = (struct log_c *) log->context;
@@ -619,19 +691,19 @@ static int disk_flush(struct dirty_log *log)
        return r;
 }
 
-static void core_mark_region(struct dirty_log *log, region_t region)
+static void core_mark_region(struct dm_dirty_log *log, region_t region)
 {
        struct log_c *lc = (struct log_c *) log->context;
        log_clear_bit(lc, lc->clean_bits, region);
 }
 
-static void core_clear_region(struct dirty_log *log, region_t region)
+static void core_clear_region(struct dm_dirty_log *log, region_t region)
 {
        struct log_c *lc = (struct log_c *) log->context;
        log_set_bit(lc, lc->clean_bits, region);
 }
 
-static int core_get_resync_work(struct dirty_log *log, region_t *region)
+static int core_get_resync_work(struct dm_dirty_log *log, region_t *region)
 {
        struct log_c *lc = (struct log_c *) log->context;
 
@@ -654,7 +726,7 @@ static int core_get_resync_work(struct dirty_log *log, region_t *region)
        return 1;
 }
 
-static void core_set_region_sync(struct dirty_log *log, region_t region,
+static void core_set_region_sync(struct dm_dirty_log *log, region_t region,
                                 int in_sync)
 {
        struct log_c *lc = (struct log_c *) log->context;
@@ -669,7 +741,7 @@ static void core_set_region_sync(struct dirty_log *log, region_t region,
        }
 }
 
-static region_t core_get_sync_count(struct dirty_log *log)
+static region_t core_get_sync_count(struct dm_dirty_log *log)
 {
         struct log_c *lc = (struct log_c *) log->context;
 
@@ -680,7 +752,7 @@ static region_t core_get_sync_count(struct dirty_log *log)
        if (lc->sync != DEFAULTSYNC) \
                DMEMIT("%ssync ", lc->sync == NOSYNC ? "no" : "")
 
-static int core_status(struct dirty_log *log, status_type_t status,
+static int core_status(struct dm_dirty_log *log, status_type_t status,
                       char *result, unsigned int maxlen)
 {
        int sz = 0;
@@ -700,7 +772,7 @@ static int core_status(struct dirty_log *log, status_type_t status,
        return sz;
 }
 
-static int disk_status(struct dirty_log *log, status_type_t status,
+static int disk_status(struct dm_dirty_log *log, status_type_t status,
                       char *result, unsigned int maxlen)
 {
        int sz = 0;
@@ -722,7 +794,7 @@ static int disk_status(struct dirty_log *log, status_type_t status,
        return sz;
 }
 
-static struct dirty_log_type _core_type = {
+static struct dm_dirty_log_type _core_type = {
        .name = "core",
        .module = THIS_MODULE,
        .ctr = core_ctr,
@@ -740,7 +812,7 @@ static struct dirty_log_type _core_type = {
        .status = core_status,
 };
 
-static struct dirty_log_type _disk_type = {
+static struct dm_dirty_log_type _disk_type = {
        .name = "disk",
        .module = THIS_MODULE,
        .ctr = disk_ctr,
@@ -763,26 +835,28 @@ int __init dm_dirty_log_init(void)
 {
        int r;
 
-       r = dm_register_dirty_log_type(&_core_type);
+       r = dm_dirty_log_type_register(&_core_type);
        if (r)
                DMWARN("couldn't register core log");
 
-       r = dm_register_dirty_log_type(&_disk_type);
+       r = dm_dirty_log_type_register(&_disk_type);
        if (r) {
                DMWARN("couldn't register disk type");
-               dm_unregister_dirty_log_type(&_core_type);
+               dm_dirty_log_type_unregister(&_core_type);
        }
 
        return r;
 }
 
-void dm_dirty_log_exit(void)
+void __exit dm_dirty_log_exit(void)
 {
-       dm_unregister_dirty_log_type(&_disk_type);
-       dm_unregister_dirty_log_type(&_core_type);
+       dm_dirty_log_type_unregister(&_disk_type);
+       dm_dirty_log_type_unregister(&_core_type);
 }
 
-EXPORT_SYMBOL(dm_register_dirty_log_type);
-EXPORT_SYMBOL(dm_unregister_dirty_log_type);
-EXPORT_SYMBOL(dm_create_dirty_log);
-EXPORT_SYMBOL(dm_destroy_dirty_log);
+module_init(dm_dirty_log_init);
+module_exit(dm_dirty_log_exit);
+
+MODULE_DESCRIPTION(DM_NAME " dirty region log");
+MODULE_AUTHOR("Joe Thornber, Heinz Mauelshagen <dm-devel@redhat.com>");
+MODULE_LICENSE("GPL");
index 762cb08..ff05fe8 100644 (file)
@@ -7,9 +7,6 @@
 #include "dm.h"
 #include "dm-bio-list.h"
 #include "dm-bio-record.h"
-#include "dm-io.h"
-#include "dm-log.h"
-#include "kcopyd.h"
 
 #include <linux/ctype.h>
 #include <linux/init.h>
@@ -22,6 +19,9 @@
 #include <linux/workqueue.h>
 #include <linux/log2.h>
 #include <linux/hardirq.h>
+#include <linux/dm-io.h>
+#include <linux/dm-dirty-log.h>
+#include <linux/dm-kcopyd.h>
 
 #define DM_MSG_PREFIX "raid1"
 #define DM_IO_PAGES 64
@@ -74,7 +74,7 @@ struct region_hash {
        unsigned region_shift;
 
        /* holds persistent region state */
-       struct dirty_log *log;
+       struct dm_dirty_log *log;
 
        /* hash table */
        rwlock_t hash_lock;
@@ -133,7 +133,7 @@ struct mirror_set {
        struct dm_target *ti;
        struct list_head list;
        struct region_hash rh;
-       struct kcopyd_client *kcopyd_client;
+       struct dm_kcopyd_client *kcopyd_client;
        uint64_t features;
 
        spinlock_t lock;        /* protects the lists */
@@ -154,6 +154,9 @@ struct mirror_set {
 
        struct workqueue_struct *kmirrord_wq;
        struct work_struct kmirrord_work;
+       struct timer_list timer;
+       unsigned long timer_pending;
+
        struct work_struct trigger_event;
 
        unsigned int nr_mirrors;
@@ -178,13 +181,32 @@ static void wake(struct mirror_set *ms)
        queue_work(ms->kmirrord_wq, &ms->kmirrord_work);
 }
 
+static void delayed_wake_fn(unsigned long data)
+{
+       struct mirror_set *ms = (struct mirror_set *) data;
+
+       clear_bit(0, &ms->timer_pending);
+       wake(ms);
+}
+
+static void delayed_wake(struct mirror_set *ms)
+{
+       if (test_and_set_bit(0, &ms->timer_pending))
+               return;
+
+       ms->timer.expires = jiffies + HZ / 5;
+       ms->timer.data = (unsigned long) ms;
+       ms->timer.function = delayed_wake_fn;
+       add_timer(&ms->timer);
+}
+
 /* FIXME move this */
 static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw);
 
 #define MIN_REGIONS 64
 #define MAX_RECOVERY 1
 static int rh_init(struct region_hash *rh, struct mirror_set *ms,
-                  struct dirty_log *log, uint32_t region_size,
+                  struct dm_dirty_log *log, uint32_t region_size,
                   region_t nr_regions)
 {
        unsigned int nr_buckets, max_buckets;
@@ -249,7 +271,7 @@ static void rh_exit(struct region_hash *rh)
        }
 
        if (rh->log)
-               dm_destroy_dirty_log(rh->log);
+               dm_dirty_log_destroy(rh->log);
        if (rh->region_pool)
                mempool_destroy(rh->region_pool);
        vfree(rh->buckets);
@@ -405,24 +427,22 @@ static void rh_update_states(struct region_hash *rh)
        write_lock_irq(&rh->hash_lock);
        spin_lock(&rh->region_lock);
        if (!list_empty(&rh->clean_regions)) {
-               list_splice(&rh->clean_regions, &clean);
-               INIT_LIST_HEAD(&rh->clean_regions);
+               list_splice_init(&rh->clean_regions, &clean);
 
                list_for_each_entry(reg, &clean, list)
                        list_del(&reg->hash_list);
        }
 
        if (!list_empty(&rh->recovered_regions)) {
-               list_splice(&rh->recovered_regions, &recovered);
-               INIT_LIST_HEAD(&rh->recovered_regions);
+               list_splice_init(&rh->recovered_regions, &recovered);
 
                list_for_each_entry (reg, &recovered, list)
                        list_del(&reg->hash_list);
        }
 
        if (!list_empty(&rh->failed_recovered_regions)) {
-               list_splice(&rh->failed_recovered_regions, &failed_recovered);
-               INIT_LIST_HEAD(&rh->failed_recovered_regions);
+               list_splice_init(&rh->failed_recovered_regions,
+                                &failed_recovered);
 
                list_for_each_entry(reg, &failed_recovered, list)
                        list_del(&reg->hash_list);
@@ -790,7 +810,7 @@ static int recover(struct mirror_set *ms, struct region *reg)
 {
        int r;
        unsigned int i;
-       struct io_region from, to[KCOPYD_MAX_REGIONS], *dest;
+       struct dm_io_region from, to[DM_KCOPYD_MAX_REGIONS], *dest;
        struct mirror *m;
        unsigned long flags = 0;
 
@@ -822,9 +842,9 @@ static int recover(struct mirror_set *ms, struct region *reg)
        }
 
        /* hand to kcopyd */
-       set_bit(KCOPYD_IGNORE_ERROR, &flags);
-       r = kcopyd_copy(ms->kcopyd_client, &from, ms->nr_mirrors - 1, to, flags,
-                       recovery_complete, reg);
+       set_bit(DM_KCOPYD_IGNORE_ERROR, &flags);
+       r = dm_kcopyd_copy(ms->kcopyd_client, &from, ms->nr_mirrors - 1, to,
+                          flags, recovery_complete, reg);
 
        return r;
 }
@@ -833,7 +853,7 @@ static void do_recovery(struct mirror_set *ms)
 {
        int r;
        struct region *reg;
-       struct dirty_log *log = ms->rh.log;
+       struct dm_dirty_log *log = ms->rh.log;
 
        /*
         * Start quiescing some regions.
@@ -909,7 +929,7 @@ static void map_bio(struct mirror *m, struct bio *bio)
        bio->bi_sector = map_sector(m, bio);
 }
 
-static void map_region(struct io_region *io, struct mirror *m,
+static void map_region(struct dm_io_region *io, struct mirror *m,
                       struct bio *bio)
 {
        io->bdev = m->dev->bdev;
@@ -951,7 +971,7 @@ static void read_callback(unsigned long error, void *context)
 /* Asynchronous read. */
 static void read_async_bio(struct mirror *m, struct bio *bio)
 {
-       struct io_region io;
+       struct dm_io_region io;
        struct dm_io_request io_req = {
                .bi_rw = READ,
                .mem.type = DM_IO_BVEC,
@@ -1019,7 +1039,7 @@ static void __bio_mark_nosync(struct mirror_set *ms,
 {
        unsigned long flags;
        struct region_hash *rh = &ms->rh;
-       struct dirty_log *log = ms->rh.log;
+       struct dm_dirty_log *log = ms->rh.log;
        struct region *reg;
        region_t region = bio_to_region(rh, bio);
        int recovering = 0;
@@ -1107,7 +1127,7 @@ out:
 static void do_write(struct mirror_set *ms, struct bio *bio)
 {
        unsigned int i;
-       struct io_region io[ms->nr_mirrors], *dest = io;
+       struct dm_io_region io[ms->nr_mirrors], *dest = io;
        struct mirror *m;
        struct dm_io_request io_req = {
                .bi_rw = WRITE,
@@ -1182,6 +1202,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
                spin_lock_irq(&ms->lock);
                bio_list_merge(&ms->failures, &sync);
                spin_unlock_irq(&ms->lock);
+               wake(ms);
        } else
                while ((bio = bio_list_pop(&sync)))
                        do_write(ms, bio);
@@ -1241,7 +1262,7 @@ static void do_failures(struct mirror_set *ms, struct bio_list *failures)
        bio_list_merge(&ms->failures, failures);
        spin_unlock_irq(&ms->lock);
 
-       wake(ms);
+       delayed_wake(ms);
 }
 
 static void trigger_event(struct work_struct *work)
@@ -1255,7 +1276,7 @@ static void trigger_event(struct work_struct *work)
 /*-----------------------------------------------------------------
  * kmirrord
  *---------------------------------------------------------------*/
-static int _do_mirror(struct work_struct *work)
+static void do_mirror(struct work_struct *work)
 {
        struct mirror_set *ms =container_of(work, struct mirror_set,
                                            kmirrord_work);
@@ -1277,23 +1298,7 @@ static int _do_mirror(struct work_struct *work)
        do_writes(ms, &writes);
        do_failures(ms, &failures);
 
-       return (ms->failures.head) ? 1 : 0;
-}
-
-static void do_mirror(struct work_struct *work)
-{
-       /*
-        * If _do_mirror returns 1, we give it
-        * another shot.  This helps for cases like
-        * 'suspend' where we call flush_workqueue
-        * and expect all work to be finished.  If
-        * a failure happens during a suspend, we
-        * couldn't issue a 'wake' because it would
-        * not be honored.  Therefore, we return '1'
-        * from _do_mirror, and retry here.
-        */
-       while (_do_mirror(work))
-               schedule();
+       dm_table_unplug_all(ms->ti->table);
 }
 
 
@@ -1303,7 +1308,7 @@ static void do_mirror(struct work_struct *work)
 static struct mirror_set *alloc_context(unsigned int nr_mirrors,
                                        uint32_t region_size,
                                        struct dm_target *ti,
-                                       struct dirty_log *dl)
+                                       struct dm_dirty_log *dl)
 {
        size_t len;
        struct mirror_set *ms = NULL;
@@ -1403,12 +1408,12 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
 /*
  * Create dirty log: log_type #log_params <log_params>
  */
-static struct dirty_log *create_dirty_log(struct dm_target *ti,
+static struct dm_dirty_log *create_dirty_log(struct dm_target *ti,
                                          unsigned int argc, char **argv,
                                          unsigned int *args_used)
 {
        unsigned int param_count;
-       struct dirty_log *dl;
+       struct dm_dirty_log *dl;
 
        if (argc < 2) {
                ti->error = "Insufficient mirror log arguments";
@@ -1427,7 +1432,7 @@ static struct dirty_log *create_dirty_log(struct dm_target *ti,
                return NULL;
        }
 
-       dl = dm_create_dirty_log(argv[0], ti, param_count, argv + 2);
+       dl = dm_dirty_log_create(argv[0], ti, param_count, argv + 2);
        if (!dl) {
                ti->error = "Error creating mirror dirty log";
                return NULL;
@@ -1435,7 +1440,7 @@ static struct dirty_log *create_dirty_log(struct dm_target *ti,
 
        if (!_check_region_size(ti, dl->type->get_region_size(dl))) {
                ti->error = "Invalid region size";
-               dm_destroy_dirty_log(dl);
+               dm_dirty_log_destroy(dl);
                return NULL;
        }
 
@@ -1496,7 +1501,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        int r;
        unsigned int nr_mirrors, m, args_used;
        struct mirror_set *ms;
-       struct dirty_log *dl;
+       struct dm_dirty_log *dl;
 
        dl = create_dirty_log(ti, argc, argv, &args_used);
        if (!dl)
@@ -1506,9 +1511,9 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        argc -= args_used;
 
        if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 ||
-           nr_mirrors < 2 || nr_mirrors > KCOPYD_MAX_REGIONS + 1) {
+           nr_mirrors < 2 || nr_mirrors > DM_KCOPYD_MAX_REGIONS + 1) {
                ti->error = "Invalid number of mirrors";
-               dm_destroy_dirty_log(dl);
+               dm_dirty_log_destroy(dl);
                return -EINVAL;
        }
 
@@ -1516,13 +1521,13 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        if (argc < nr_mirrors * 2) {
                ti->error = "Too few mirror arguments";
-               dm_destroy_dirty_log(dl);
+               dm_dirty_log_destroy(dl);
                return -EINVAL;
        }
 
        ms = alloc_context(nr_mirrors, dl->type->get_region_size(dl), ti, dl);
        if (!ms) {
-               dm_destroy_dirty_log(dl);
+               dm_dirty_log_destroy(dl);
                return -ENOMEM;
        }
 
@@ -1547,6 +1552,8 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto err_free_context;
        }
        INIT_WORK(&ms->kmirrord_work, do_mirror);
+       init_timer(&ms->timer);
+       ms->timer_pending = 0;
        INIT_WORK(&ms->trigger_event, trigger_event);
 
        r = parse_features(ms, argc, argv, &args_used);
@@ -1571,7 +1578,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto err_destroy_wq;
        }
 
-       r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);
+       r = dm_kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);
        if (r)
                goto err_destroy_wq;
 
@@ -1589,8 +1596,9 @@ static void mirror_dtr(struct dm_target *ti)
 {
        struct mirror_set *ms = (struct mirror_set *) ti->private;
 
+       del_timer_sync(&ms->timer);
        flush_workqueue(ms->kmirrord_wq);
-       kcopyd_client_destroy(ms->kcopyd_client);
+       dm_kcopyd_client_destroy(ms->kcopyd_client);
        destroy_workqueue(ms->kmirrord_wq);
        free_context(ms, ti, ms->nr_mirrors);
 }
@@ -1734,7 +1742,7 @@ out:
 static void mirror_presuspend(struct dm_target *ti)
 {
        struct mirror_set *ms = (struct mirror_set *) ti->private;
-       struct dirty_log *log = ms->rh.log;
+       struct dm_dirty_log *log = ms->rh.log;
 
        atomic_set(&ms->suspend, 1);
 
@@ -1763,7 +1771,7 @@ static void mirror_presuspend(struct dm_target *ti)
 static void mirror_postsuspend(struct dm_target *ti)
 {
        struct mirror_set *ms = ti->private;
-       struct dirty_log *log = ms->rh.log;
+       struct dm_dirty_log *log = ms->rh.log;
 
        if (log->type->postsuspend && log->type->postsuspend(log))
                /* FIXME: need better error handling */
@@ -1773,7 +1781,7 @@ static void mirror_postsuspend(struct dm_target *ti)
 static void mirror_resume(struct dm_target *ti)
 {
        struct mirror_set *ms = ti->private;
-       struct dirty_log *log = ms->rh.log;
+       struct dm_dirty_log *log = ms->rh.log;
 
        atomic_set(&ms->suspend, 0);
        if (log->type->resume && log->type->resume(log))
@@ -1811,7 +1819,7 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
 {
        unsigned int m, sz = 0;
        struct mirror_set *ms = (struct mirror_set *) ti->private;
-       struct dirty_log *log = ms->rh.log;
+       struct dm_dirty_log *log = ms->rh.log;
        char buffer[ms->nr_mirrors + 1];
 
        switch (type) {
@@ -1864,15 +1872,9 @@ static int __init dm_mirror_init(void)
 {
        int r;
 
-       r = dm_dirty_log_init();
-       if (r)
-               return r;
-
        r = dm_register_target(&mirror_target);
-       if (r < 0) {
+       if (r < 0)
                DMERR("Failed to register mirror target");
-               dm_dirty_log_exit();
-       }
 
        return r;
 }
@@ -1884,8 +1886,6 @@ static void __exit dm_mirror_exit(void)
        r = dm_unregister_target(&mirror_target);
        if (r < 0)
                DMERR("unregister failed %d", r);
-
-       dm_dirty_log_exit();
 }
 
 /* Module hooks */
index 4dc8a43..1ba8a47 100644 (file)
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/log2.h>
+#include <linux/dm-kcopyd.h>
 
 #include "dm-snap.h"
 #include "dm-bio-list.h"
-#include "kcopyd.h"
 
 #define DM_MSG_PREFIX "snapshots"
 
@@ -36,9 +36,9 @@
 #define SNAPSHOT_COPY_PRIORITY 2
 
 /*
- * Each snapshot reserves this many pages for io
+ * Reserve 1MB for each snapshot initially (with minimum of 1 page).
  */
-#define SNAPSHOT_PAGES 256
+#define SNAPSHOT_PAGES (((1UL << 20) >> PAGE_SHIFT) ? : 1)
 
 static struct workqueue_struct *ksnapd;
 static void flush_queued_bios(struct work_struct *work);
@@ -536,7 +536,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        s->last_percent = 0;
        init_rwsem(&s->lock);
        spin_lock_init(&s->pe_lock);
-       s->table = ti->table;
+       s->ti = ti;
 
        /* Allocate hash table for COW data */
        if (init_hash_tables(s)) {
@@ -558,7 +558,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
                goto bad4;
        }
 
-       r = kcopyd_client_create(SNAPSHOT_PAGES, &s->kcopyd_client);
+       r = dm_kcopyd_client_create(SNAPSHOT_PAGES, &s->kcopyd_client);
        if (r) {
                ti->error = "Could not create kcopyd client";
                goto bad5;
@@ -591,7 +591,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        return 0;
 
  bad6:
-       kcopyd_client_destroy(s->kcopyd_client);
+       dm_kcopyd_client_destroy(s->kcopyd_client);
 
  bad5:
        s->store.destroy(&s->store);
@@ -613,7 +613,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
 static void __free_exceptions(struct dm_snapshot *s)
 {
-       kcopyd_client_destroy(s->kcopyd_client);
+       dm_kcopyd_client_destroy(s->kcopyd_client);
        s->kcopyd_client = NULL;
 
        exit_exception_table(&s->pending, pending_cache);
@@ -699,7 +699,7 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err)
 
        s->valid = 0;
 
-       dm_table_event(s->table);
+       dm_table_event(s->ti->table);
 }
 
 static void get_pending_exception(struct dm_snap_pending_exception *pe)
@@ -824,7 +824,7 @@ static void copy_callback(int read_err, unsigned long write_err, void *context)
 static void start_copy(struct dm_snap_pending_exception *pe)
 {
        struct dm_snapshot *s = pe->snap;
-       struct io_region src, dest;
+       struct dm_io_region src, dest;
        struct block_device *bdev = s->origin->bdev;
        sector_t dev_size;
 
@@ -839,7 +839,7 @@ static void start_copy(struct dm_snap_pending_exception *pe)
        dest.count = src.count;
 
        /* Hand over to kcopyd */
-       kcopyd_copy(s->kcopyd_client,
+       dm_kcopyd_copy(s->kcopyd_client,
                    &src, 1, &dest, 0, copy_callback, pe);
 }
 
@@ -1060,7 +1060,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
                        goto next_snapshot;
 
                /* Nothing to do if writing beyond end of snapshot */
-               if (bio->bi_sector >= dm_table_get_size(snap->table))
+               if (bio->bi_sector >= dm_table_get_size(snap->ti->table))
                        goto next_snapshot;
 
                /*
index 93bce5d..24f9fb7 100644 (file)
@@ -132,7 +132,7 @@ struct exception_store {
 
 struct dm_snapshot {
        struct rw_semaphore lock;
-       struct dm_table *table;
+       struct dm_target *ti;
 
        struct dm_dev *origin;
        struct dm_dev *cow;
@@ -169,7 +169,7 @@ struct dm_snapshot {
        /* The on disk metadata handler */
        struct exception_store store;
 
-       struct kcopyd_client *kcopyd_client;
+       struct dm_kcopyd_client *kcopyd_client;
 
        /* Queue of snapshot writes for ksnapd to flush */
        struct bio_list queued_bios;
index e75b143..51be533 100644 (file)
@@ -245,44 +245,6 @@ int dm_table_create(struct dm_table **result, int mode,
        return 0;
 }
 
-int dm_create_error_table(struct dm_table **result, struct mapped_device *md)
-{
-       struct dm_table *t;
-       sector_t dev_size = 1;
-       int r;
-
-       /*
-        * Find current size of device.
-        * Default to 1 sector if inactive.
-        */
-       t = dm_get_table(md);
-       if (t) {
-               dev_size = dm_table_get_size(t);
-               dm_table_put(t);
-       }
-
-       r = dm_table_create(&t, FMODE_READ, 1, md);
-       if (r)
-               return r;
-
-       r = dm_table_add_target(t, "error", 0, dev_size, NULL);
-       if (r)
-               goto out;
-
-       r = dm_table_complete(t);
-       if (r)
-               goto out;
-
-       *result = t;
-
-out:
-       if (r)
-               dm_table_put(t);
-
-       return r;
-}
-EXPORT_SYMBOL_GPL(dm_create_error_table);
-
 static void free_devices(struct list_head *devices)
 {
        struct list_head *tmp, *next;
@@ -954,7 +916,7 @@ void dm_table_presuspend_targets(struct dm_table *t)
        if (!t)
                return;
 
-       return suspend_targets(t, 0);
+       suspend_targets(t, 0);
 }
 
 void dm_table_postsuspend_targets(struct dm_table *t)
@@ -962,7 +924,7 @@ void dm_table_postsuspend_targets(struct dm_table *t)
        if (!t)
                return;
 
-       return suspend_targets(t, 1);
+       suspend_targets(t, 1);
 }
 
 int dm_table_resume_targets(struct dm_table *t)
index 6617ce4..372369b 100644 (file)
@@ -204,6 +204,7 @@ static int (*_inits[])(void) __initdata = {
        dm_target_init,
        dm_linear_init,
        dm_stripe_init,
+       dm_kcopyd_init,
        dm_interface_init,
 };
 
@@ -212,6 +213,7 @@ static void (*_exits[])(void) = {
        dm_target_exit,
        dm_linear_exit,
        dm_stripe_exit,
+       dm_kcopyd_exit,
        dm_interface_exit,
 };
 
@@ -922,7 +924,7 @@ static void free_minor(int minor)
 /*
  * See if the device with a specific minor # is free.
  */
-static int specific_minor(struct mapped_device *md, int minor)
+static int specific_minor(int minor)
 {
        int r, m;
 
@@ -955,7 +957,7 @@ out:
        return r;
 }
 
-static int next_free_minor(struct mapped_device *md, int *minor)
+static int next_free_minor(int *minor)
 {
        int r, m;
 
@@ -966,9 +968,8 @@ static int next_free_minor(struct mapped_device *md, int *minor)
        spin_lock(&_minor_lock);
 
        r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m);
-       if (r) {
+       if (r)
                goto out;
-       }
 
        if (m >= (1 << MINORBITS)) {
                idr_remove(&_minor_idr, m);
@@ -991,7 +992,7 @@ static struct block_device_operations dm_blk_dops;
 static struct mapped_device *alloc_dev(int minor)
 {
        int r;
-       struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL);
+       struct mapped_device *md = kzalloc(sizeof(*md), GFP_KERNEL);
        void *old_md;
 
        if (!md) {
@@ -1004,13 +1005,12 @@ static struct mapped_device *alloc_dev(int minor)
 
        /* get a minor number for the dev */
        if (minor == DM_ANY_MINOR)
-               r = next_free_minor(md, &minor);
+               r = next_free_minor(&minor);
        else
-               r = specific_minor(md, minor);
+               r = specific_minor(minor);
        if (r < 0)
                goto bad_minor;
 
-       memset(md, 0, sizeof(*md));
        init_rwsem(&md->io_lock);
        mutex_init(&md->suspend_lock);
        spin_lock_init(&md->pushback_lock);
index b4584a3..8c03b63 100644 (file)
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 
-#define DM_NAME "device-mapper"
-
-#define DMERR(f, arg...) \
-       printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
-#define DMERR_LIMIT(f, arg...) \
-       do { \
-               if (printk_ratelimit()) \
-                       printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " \
-                              f "\n", ## arg); \
-       } while (0)
-
-#define DMWARN(f, arg...) \
-       printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
-#define DMWARN_LIMIT(f, arg...) \
-       do { \
-               if (printk_ratelimit()) \
-                       printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " \
-                              f "\n", ## arg); \
-       } while (0)
-
-#define DMINFO(f, arg...) \
-       printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
-#define DMINFO_LIMIT(f, arg...) \
-       do { \
-               if (printk_ratelimit()) \
-                       printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f \
-                              "\n", ## arg); \
-       } while (0)
-
-#ifdef CONFIG_DM_DEBUG
-#  define DMDEBUG(f, arg...) \
-       printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX " DEBUG: " f "\n", ## arg)
-#  define DMDEBUG_LIMIT(f, arg...) \
-       do { \
-               if (printk_ratelimit()) \
-                       printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX ": " f \
-                              "\n", ## arg); \
-       } while (0)
-#else
-#  define DMDEBUG(f, arg...) do {} while (0)
-#  define DMDEBUG_LIMIT(f, arg...) do {} while (0)
-#endif
-
-#define DMEMIT(x...) sz += ((sz >= maxlen) ? \
-                         0 : scnprintf(result + sz, maxlen - sz, x))
-
-#define SECTOR_SHIFT 9
-
-/*
- * Definitions of return values from target end_io function.
- */
-#define DM_ENDIO_INCOMPLETE    1
-#define DM_ENDIO_REQUEUE       2
-
-/*
- * Definitions of return values from target map function.
- */
-#define DM_MAPIO_SUBMITTED     0
-#define DM_MAPIO_REMAPPED      1
-#define DM_MAPIO_REQUEUE       DM_ENDIO_REQUEUE
-
 /*
  * Suspend feature flags
  */
@@ -136,34 +75,6 @@ static inline int array_too_big(unsigned long fixed, unsigned long obj,
        return (num > (ULONG_MAX - fixed) / obj);
 }
 
-/*
- * Ceiling(n / sz)
- */
-#define dm_div_up(n, sz) (((n) + (sz) - 1) / (sz))
-
-#define dm_sector_div_up(n, sz) ( \
-{ \
-       sector_t _r = ((n) + (sz) - 1); \
-       sector_div(_r, (sz)); \
-       _r; \
-} \
-)
-
-/*
- * ceiling(n / size) * size
- */
-#define dm_round_up(n, sz) (dm_div_up((n), (sz)) * (sz))
-
-static inline sector_t to_sector(unsigned long n)
-{
-       return (n >> 9);
-}
-
-static inline unsigned long to_bytes(sector_t n)
-{
-       return (n << 9);
-}
-
 int dm_split_args(int *argc, char ***argvp, char *input);
 
 /*
@@ -189,4 +100,13 @@ int dm_lock_for_deletion(struct mapped_device *md);
 
 void dm_kobject_uevent(struct mapped_device *md);
 
+/*
+ * Dirty log
+ */
+int dm_dirty_log_init(void);
+void dm_dirty_log_exit(void);
+
+int dm_kcopyd_init(void);
+void dm_kcopyd_exit(void);
+
 #endif
diff --git a/drivers/md/kcopyd.h b/drivers/md/kcopyd.h
deleted file mode 100644 (file)
index 4845f2a..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2001 Sistina Software
- *
- * This file is released under the GPL.
- *
- * Kcopyd provides a simple interface for copying an area of one
- * block-device to one or more other block-devices, with an asynchronous
- * completion notification.
- */
-
-#ifndef DM_KCOPYD_H
-#define DM_KCOPYD_H
-
-#include "dm-io.h"
-
-/* FIXME: make this configurable */
-#define KCOPYD_MAX_REGIONS 8
-
-#define KCOPYD_IGNORE_ERROR 1
-
-/*
- * To use kcopyd you must first create a kcopyd client object.
- */
-struct kcopyd_client;
-int kcopyd_client_create(unsigned int num_pages, struct kcopyd_client **result);
-void kcopyd_client_destroy(struct kcopyd_client *kc);
-
-/*
- * Submit a copy job to kcopyd.  This is built on top of the
- * previous three fns.
- *
- * read_err is a boolean,
- * write_err is a bitset, with 1 bit for each destination region
- */
-typedef void (*kcopyd_notify_fn)(int read_err, unsigned long write_err,
-                                void *context);
-
-int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from,
-               unsigned int num_dests, struct io_region *dests,
-               unsigned int flags, kcopyd_notify_fn fn, void *context);
-
-#endif
index cb78457..ad3b787 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001 Sistina Software (UK) Limited.
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
  *
  * This file is released under the LGPL.
  */
@@ -10,6 +10,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/bio.h>
+
 struct dm_target;
 struct dm_table;
 struct dm_dev;
@@ -250,11 +252,97 @@ void dm_table_event(struct dm_table *t);
  */
 int dm_swap_table(struct mapped_device *md, struct dm_table *t);
 
+/*-----------------------------------------------------------------
+ * Macros.
+ *---------------------------------------------------------------*/
+#define DM_NAME "device-mapper"
+
+#define DMERR(f, arg...) \
+       printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
+#define DMERR_LIMIT(f, arg...) \
+       do { \
+               if (printk_ratelimit()) \
+                       printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " \
+                              f "\n", ## arg); \
+       } while (0)
+
+#define DMWARN(f, arg...) \
+       printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
+#define DMWARN_LIMIT(f, arg...) \
+       do { \
+               if (printk_ratelimit()) \
+                       printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " \
+                              f "\n", ## arg); \
+       } while (0)
+
+#define DMINFO(f, arg...) \
+       printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
+#define DMINFO_LIMIT(f, arg...) \
+       do { \
+               if (printk_ratelimit()) \
+                       printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f \
+                              "\n", ## arg); \
+       } while (0)
+
+#ifdef CONFIG_DM_DEBUG
+#  define DMDEBUG(f, arg...) \
+       printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX " DEBUG: " f "\n", ## arg)
+#  define DMDEBUG_LIMIT(f, arg...) \
+       do { \
+               if (printk_ratelimit()) \
+                       printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX ": " f \
+                              "\n", ## arg); \
+       } while (0)
+#else
+#  define DMDEBUG(f, arg...) do {} while (0)
+#  define DMDEBUG_LIMIT(f, arg...) do {} while (0)
+#endif
+
+#define DMEMIT(x...) sz += ((sz >= maxlen) ? \
+                         0 : scnprintf(result + sz, maxlen - sz, x))
+
+#define SECTOR_SHIFT 9
+
+/*
+ * Definitions of return values from target end_io function.
+ */
+#define DM_ENDIO_INCOMPLETE    1
+#define DM_ENDIO_REQUEUE       2
+
+/*
+ * Definitions of return values from target map function.
+ */
+#define DM_MAPIO_SUBMITTED     0
+#define DM_MAPIO_REMAPPED      1
+#define DM_MAPIO_REQUEUE       DM_ENDIO_REQUEUE
+
+/*
+ * Ceiling(n / sz)
+ */
+#define dm_div_up(n, sz) (((n) + (sz) - 1) / (sz))
+
+#define dm_sector_div_up(n, sz) ( \
+{ \
+       sector_t _r = ((n) + (sz) - 1); \
+       sector_div(_r, (sz)); \
+       _r; \
+} \
+)
+
 /*
- * Prepare a table for a device that will error all I/O.
- * To make it active, call dm_suspend(), dm_swap_table() then dm_resume().
+ * ceiling(n / size) * size
  */
-int dm_create_error_table(struct dm_table **result, struct mapped_device *md);
+#define dm_round_up(n, sz) (dm_div_up((n), (sz)) * (sz))
+
+static inline sector_t to_sector(unsigned long n)
+{
+       return (n >> SECTOR_SHIFT);
+}
+
+static inline unsigned long to_bytes(sector_t n)
+{
+       return (n << SECTOR_SHIFT);
+}
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_DEVICE_MAPPER_H */
similarity index 53%
rename from drivers/md/dm-log.h
rename to include/linux/dm-dirty-log.h
index 3fae87e..600c5fb 100644 (file)
@@ -1,52 +1,56 @@
 /*
  * Copyright (C) 2003 Sistina Software
+ * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
+ *
+ * Device-Mapper dirty region log.
  *
  * This file is released under the LGPL.
  */
 
-#ifndef DM_DIRTY_LOG
-#define DM_DIRTY_LOG
+#ifndef _LINUX_DM_DIRTY_LOG
+#define _LINUX_DM_DIRTY_LOG
+
+#ifdef __KERNEL__
 
-#include "dm.h"
+#include <linux/types.h>
+#include <linux/device-mapper.h>
 
 typedef sector_t region_t;
 
-struct dirty_log_type;
+struct dm_dirty_log_type;
 
-struct dirty_log {
-       struct dirty_log_type *type;
+struct dm_dirty_log {
+       struct dm_dirty_log_type *type;
        void *context;
 };
 
-struct dirty_log_type {
-       struct list_head list;
+struct dm_dirty_log_type {
        const char *name;
        struct module *module;
-       unsigned int use_count;
 
-       int (*ctr)(struct dirty_log *log, struct dm_target *ti,
-                  unsigned int argc, char **argv);
-       void (*dtr)(struct dirty_log *log);
+       int (*ctr)(struct dm_dirty_log *log, struct dm_target *ti,
+                  unsigned argc, char **argv);
+       void (*dtr)(struct dm_dirty_log *log);
 
        /*
         * There are times when we don't want the log to touch
         * the disk.
         */
-       int (*presuspend)(struct dirty_log *log);
-       int (*postsuspend)(struct dirty_log *log);
-       int (*resume)(struct dirty_log *log);
+       int (*presuspend)(struct dm_dirty_log *log);
+       int (*postsuspend)(struct dm_dirty_log *log);
+       int (*resume)(struct dm_dirty_log *log);
 
        /*
         * Retrieves the smallest size of region that the log can
         * deal with.
         */
-       uint32_t (*get_region_size)(struct dirty_log *log);
+       uint32_t (*get_region_size)(struct dm_dirty_log *log);
 
-        /*
+       /*
         * A predicate to say whether a region is clean or not.
         * May block.
         */
-       int (*is_clean)(struct dirty_log *log, region_t region);
+       int (*is_clean)(struct dm_dirty_log *log, region_t region);
 
        /*
         *  Returns: 0, 1, -EWOULDBLOCK, < 0
@@ -59,13 +63,14 @@ struct dirty_log_type {
         * passed to a daemon to deal with, since a daemon is
         * allowed to block.
         */
-       int (*in_sync)(struct dirty_log *log, region_t region, int can_block);
+       int (*in_sync)(struct dm_dirty_log *log, region_t region,
+                      int can_block);
 
        /*
         * Flush the current log state (eg, to disk).  This
         * function may block.
         */
-       int (*flush)(struct dirty_log *log);
+       int (*flush)(struct dm_dirty_log *log);
 
        /*
         * Mark an area as clean or dirty.  These functions may
@@ -73,8 +78,8 @@ struct dirty_log_type {
         * be extremely rare (eg, allocating another chunk of
         * memory for some reason).
         */
-       void (*mark_region)(struct dirty_log *log, region_t region);
-       void (*clear_region)(struct dirty_log *log, region_t region);
+       void (*mark_region)(struct dm_dirty_log *log, region_t region);
+       void (*clear_region)(struct dm_dirty_log *log, region_t region);
 
        /*
         * Returns: <0 (error), 0 (no region), 1 (region)
@@ -88,44 +93,39 @@ struct dirty_log_type {
         * tells you if an area is synchronised, the other
         * assigns recovery work.
        */
-       int (*get_resync_work)(struct dirty_log *log, region_t *region);
+       int (*get_resync_work)(struct dm_dirty_log *log, region_t *region);
 
        /*
         * This notifies the log that the resync status of a region
         * has changed.  It also clears the region from the recovering
         * list (if present).
         */
-       void (*set_region_sync)(struct dirty_log *log,
+       void (*set_region_sync)(struct dm_dirty_log *log,
                                region_t region, int in_sync);
 
-        /*
+       /*
         * Returns the number of regions that are in sync.
-         */
-        region_t (*get_sync_count)(struct dirty_log *log);
+        */
+       region_t (*get_sync_count)(struct dm_dirty_log *log);
 
        /*
         * Support function for mirror status requests.
         */
-       int (*status)(struct dirty_log *log, status_type_t status_type,
-                     char *result, unsigned int maxlen);
+       int (*status)(struct dm_dirty_log *log, status_type_t status_type,
+                     char *result, unsigned maxlen);
 };
 
-int dm_register_dirty_log_type(struct dirty_log_type *type);
-int dm_unregister_dirty_log_type(struct dirty_log_type *type);
-
+int dm_dirty_log_type_register(struct dm_dirty_log_type *type);
+int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type);
 
 /*
  * Make sure you use these two functions, rather than calling
  * type->constructor/destructor() directly.
  */
-struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *ti,
-                                     unsigned int argc, char **argv);
-void dm_destroy_dirty_log(struct dirty_log *log);
-
-/*
- * init/exit functions.
- */
-int dm_dirty_log_init(void);
-void dm_dirty_log_exit(void);
+struct dm_dirty_log *dm_dirty_log_create(const char *type_name,
+                                        struct dm_target *ti,
+                                        unsigned argc, char **argv);
+void dm_dirty_log_destroy(struct dm_dirty_log *log);
 
-#endif
+#endif /* __KERNEL__ */
+#endif /* _LINUX_DM_DIRTY_LOG_H */
similarity index 84%
rename from drivers/md/dm-io.h
rename to include/linux/dm-io.h
index f647e2c..b6bf17e 100644 (file)
@@ -1,15 +1,20 @@
 /*
  * Copyright (C) 2003 Sistina Software
+ * Copyright (C) 2004 - 2008 Red Hat, Inc. All rights reserved.
+ *
+ * Device-Mapper low-level I/O.
  *
  * This file is released under the GPL.
  */
 
-#ifndef _DM_IO_H
-#define _DM_IO_H
+#ifndef _LINUX_DM_IO_H
+#define _LINUX_DM_IO_H
+
+#ifdef __KERNEL__
 
-#include "dm.h"
+#include <linux/types.h>
 
-struct io_region {
+struct dm_io_region {
        struct block_device *bdev;
        sector_t sector;
        sector_t count;         /* If this is zero the region is ignored. */
@@ -74,6 +79,7 @@ void dm_io_client_destroy(struct dm_io_client *client);
  * error occurred doing io to the corresponding region.
  */
 int dm_io(struct dm_io_request *io_req, unsigned num_regions,
-         struct io_region *region, unsigned long *sync_error_bits);
+         struct dm_io_region *region, unsigned long *sync_error_bits);
 
-#endif
+#endif /* __KERNEL__ */
+#endif /* _LINUX_DM_IO_H */
diff --git a/include/linux/dm-kcopyd.h b/include/linux/dm-kcopyd.h
new file mode 100644 (file)
index 0000000..5db2163
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2001 - 2003 Sistina Software
+ * Copyright (C) 2004 - 2008 Red Hat, Inc. All rights reserved.
+ *
+ * kcopyd provides a simple interface for copying an area of one
+ * block-device to one or more other block-devices, either synchronous
+ * or with an asynchronous completion notification.
+ *
+ * This file is released under the GPL.
+ */
+
+#ifndef _LINUX_DM_KCOPYD_H
+#define _LINUX_DM_KCOPYD_H
+
+#ifdef __KERNEL__
+
+#include <linux/dm-io.h>
+
+/* FIXME: make this configurable */
+#define DM_KCOPYD_MAX_REGIONS 8
+
+#define DM_KCOPYD_IGNORE_ERROR 1
+
+/*
+ * To use kcopyd you must first create a dm_kcopyd_client object.
+ */
+struct dm_kcopyd_client;
+int dm_kcopyd_client_create(unsigned num_pages,
+                           struct dm_kcopyd_client **result);
+void dm_kcopyd_client_destroy(struct dm_kcopyd_client *kc);
+
+/*
+ * Submit a copy job to kcopyd.  This is built on top of the
+ * previous three fns.
+ *
+ * read_err is a boolean,
+ * write_err is a bitset, with 1 bit for each destination region
+ */
+typedef void (*dm_kcopyd_notify_fn)(int read_err, unsigned long write_err,
+                                   void *context);
+
+int dm_kcopyd_copy(struct dm_kcopyd_client *kc, struct dm_io_region *from,
+                  unsigned num_dests, struct dm_io_region *dests,
+                  unsigned flags, dm_kcopyd_notify_fn fn, void *context);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_DM_KCOPYD_H */