]> sourceware.org Git - dm.git/commitdiff
Snapshot fixes (sync with bk).
authorAlasdair Kergon <agk@redhat.com>
Mon, 20 May 2002 14:11:34 +0000 (14:11 +0000)
committerAlasdair Kergon <agk@redhat.com>
Mon, 20 May 2002 14:11:34 +0000 (14:11 +0000)
12 files changed:
kernel/VERSION
kernel/common/device-mapper.h
kernel/common/dm-exception-store.c
kernel/common/dm-linear.c
kernel/common/dm-snapshot.c
kernel/common/dm-snapshot.h
kernel/common/dm-stripe.c
kernel/common/dm-target.c
kernel/common/dm.c.in
kernel/common/kcopyd.c
kernel/common/kcopyd.h
kernel/ioctl/dm-ioctl.c

index 7584a019feb2d15815c62c2855c8fc92c300a754..e4008f9980163a33c35807c33ac9d3649c6e9e14 100644 (file)
@@ -1 +1 @@
-0.94.10-cvs (2002-04-23)
+0.94.11-cvs (2002-05-20)
index e982191a03be7ea24ed18bc37a319341b92bcb7b..8e1ff90dabe6dda09b20d23d9c06c42be7940019 100644 (file)
@@ -28,8 +28,8 @@ typedef int (*dm_ctr_fn) (struct dm_table *t, offset_t b, offset_t l,
 typedef void (*dm_dtr_fn) (struct dm_table *t, void *c);
 typedef int (*dm_map_fn) (struct buffer_head *bh, int rw, void *context);
 typedef int (*dm_err_fn) (struct buffer_head *bh, int rw, void *context);
-typedef int (*dm_sts_fn) (status_type_t sts_type, char *, int maxlen,
-                         void *context);
+typedef int (*dm_status_fn) (status_type_t status_type, char *result,
+                            int maxlen, void *context);
 typedef int (*dm_wait_fn) (void *context, wait_queue_t *wq, int add);
 
 void dm_error(const char *message);
@@ -52,7 +52,7 @@ struct target_type {
        dm_dtr_fn dtr;
        dm_map_fn map;
        dm_err_fn err;
-       dm_sts_fn sts;
+       dm_status_fn status;
        dm_wait_fn wait;
 };
 
index ae47e4ec54ea2dd80d621ad653c173929fb73d43..87a007698e4aab0530743db75bc166a5b99ead89 100644 (file)
@@ -9,6 +9,7 @@
 #include "dm-snapshot.h"
 #include "kcopyd.h"
 #include <linux/mm.h>
+#include <linux/pagemap.h>
 
 #define SECTOR_SIZE 512
 #define SECTOR_SHIFT 9
  * the start of a fresh COW device before calling the snapshot
  * constructor.
  *
- * The very first metadata block, which is also the first chunk
- * on the COW device, will include a header struct followed by
- * exception info.  All other metadata chunks will solely consist
- * of exception info.  All on disk structures are in
- * little-endian format.  The end of the exceptions info is
- * indicated by an exception with a new_chunk of 0.
+ * The first chunk of the COW device just contains the header.
+ * After this there is a chunk filled with exception metadata,
+ * followed by as many exception chunks as can fit in the
+ * metadata areas.
+ *
+ * All on disk structures are in little-endian format.  The end
+ * of the exceptions info is indicated by an exception with a
+ * new_chunk of 0, which is invalid since it would point to the
+ * header chunk.
  */
 
 /*
@@ -49,7 +53,6 @@
  */
 #define SNAPSHOT_DISK_VERSION 1
 
-#if 0
 struct disk_header {
        uint32_t magic;
 
@@ -68,18 +71,23 @@ struct disk_header {
        /* In sectors */
        uint32_t chunk_size;
 };
-#endif
 
 struct disk_exception {
        uint64_t old_chunk;
        uint64_t new_chunk;
 };
 
+struct commit_callback {
+       void (*callback)(void *, int success);
+       void *context;
+};
+
 /*
  * The top level structure for a persistent exception store.
  */
 struct pstore {
        struct dm_snapshot *snap;       /* up pointer to my snapshot */
+       int version;
        int valid;
        uint32_t chunk_size;
        uint32_t exceptions_per_area;
@@ -108,6 +116,10 @@ struct pstore {
         * metadata area.
         */
        uint32_t current_committed;
+
+       atomic_t pending_count;
+       uint32_t callback_count;
+       struct commit_callback *callbacks;
 };
 
 /*
@@ -134,6 +146,7 @@ static int do_io(int rw, struct kcopyd_region *where, struct kiobuf *iobuf)
                iobuf->blocks[i] = start++;
 
        iobuf->length = where->count << 9;
+       iobuf->locked = 1;
 
        status = brw_kiovec(rw, 1, &iobuf, where->dev, iobuf->blocks,
                            blocksize);
@@ -143,6 +156,7 @@ static int do_io(int rw, struct kcopyd_region *where, struct kiobuf *iobuf)
        return 0;
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 4, 19)
 /*
  * FIXME: Remove once 2.4.19 has been released.
  */
@@ -166,13 +180,14 @@ struct page *vmalloc_to_page(void *vmalloc_addr)
        }
        return page;
 }
+#endif
 
 static int allocate_iobuf(struct pstore *ps)
 {
-       size_t i, r, len, nr_pages;
+       size_t i, r = -ENOMEM, len, nr_pages;
        struct page *page;
 
-       len = ps->chunk_size * SECTOR_SIZE;
+       len = ps->chunk_size << SECTOR_SHIFT;
 
        /*
         * Allocate the chunk_size block of memory that will hold
@@ -180,37 +195,43 @@ static int allocate_iobuf(struct pstore *ps)
         */
        ps->area = vmalloc(len);
        if (!ps->area)
-               return -ENOMEM;
+               return r;
 
-       if (alloc_kiovec(1, &ps->iobuf)) {
-               vfree(ps->area);
-               return -ENOMEM;
-       }
+       if (alloc_kiovec(1, &ps->iobuf))
+               goto bad;
+
+       if (alloc_kiobuf_bhs(ps->iobuf))
+               goto bad;
 
        nr_pages = ps->chunk_size / (PAGE_SIZE / SECTOR_SIZE);
        r = expand_kiobuf(ps->iobuf, nr_pages);
-       if (r) {
-               vfree(ps->area);
-               return -ENOMEM;
-       }
+       if (r)
+               goto bad;
 
        /*
         * We lock the pages for ps->area into memory since they'll be
         * doing a lot of io.
-        *
-        * FIXME: Check that there's no race, ie. the pages can't
-        * be swapped out before we lock them, we may have to
-        * allocate them as seperate pages after all :(
         */
-       for (i = 0; i < len; i += PAGE_SIZE) {
-               page = vmalloc_to_page(ps->area + i);
+       for (i = 0; i < nr_pages; i++) {
+               page = vmalloc_to_page(ps->area + (i * PAGE_SIZE));
                LockPage(page);
                ps->iobuf->maplist[i] = page;
                ps->iobuf->nr_pages++;
        }
 
+       ps->iobuf->nr_pages = nr_pages;
        ps->iobuf->offset = 0;
+
        return 0;
+
+      bad:
+       if (ps->iobuf)
+               free_kiovec(1, &ps->iobuf);
+
+       if (ps->area)
+               vfree(ps->area);
+       ps->iobuf = NULL;
+       return r;
 }
 
 static void free_iobuf(struct pstore *ps)
@@ -219,24 +240,44 @@ static void free_iobuf(struct pstore *ps)
 
        for (i = 0; i < ps->iobuf->nr_pages; i++)
                UnlockPage(ps->iobuf->maplist[i]);
+       ps->iobuf->locked = 0;
 
        free_kiovec(1, &ps->iobuf);
        vfree(ps->area);
 }
 
 /*
- * Read or write a metadata area.
+ * Read or write a chunk aligned and sized block of data from a device.
  */
-static int area_io(struct pstore *ps, uint32_t area, int rw)
+static int chunk_io(struct pstore *ps, uint32_t chunk, int rw)
 {
        int r;
        struct kcopyd_region where;
 
        where.dev = ps->snap->cow->dev;
-       where.sector = ((ps->exceptions_per_area + 1) * ps->chunk_size) * area;
+       where.sector = ps->chunk_size * chunk;
        where.count = ps->chunk_size;
 
-       r = do_io(rw, &where, ps->area);
+       r = do_io(rw, &where, ps->iobuf);
+       if (r)
+               return r;
+
+       return 0;
+}
+
+/*
+ * Read or write a metadata area.  Remembering to skip the first
+ * chunk which holds the header.
+ */
+static int area_io(struct pstore *ps, uint32_t area, int rw)
+{
+       int r;
+       uint32_t chunk;
+
+       /* convert a metadata area index to a chunk index */
+       chunk = 1 + ((ps->exceptions_per_area + 1) * area);
+
+       r = chunk_io(ps, chunk, rw);
        if (r)
                return r;
 
@@ -246,16 +287,59 @@ static int area_io(struct pstore *ps, uint32_t area, int rw)
 
 static int zero_area(struct pstore *ps, uint32_t area)
 {
-       memset(ps, 0, ps->chunk_size);
+       memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT);
        return area_io(ps, area, WRITE);
 }
 
+static int read_header(struct pstore *ps, int *new_snapshot)
+{
+       int r;
+       struct disk_header *dh;
+
+       r = chunk_io(ps, 0, READ);
+       if (r)
+               return r;
+
+       dh = (struct disk_header *) ps->area;
+
+       if (dh->magic == 0) {
+               *new_snapshot = 1;
+
+       } else if (dh->magic == SNAP_MAGIC) {
+               *new_snapshot = 0;
+               ps->valid = dh->valid;
+               ps->version = dh->version;
+               ps->chunk_size = dh->chunk_size;
+
+       } else {
+               DMWARN("Invalid/corrupt snapshot");
+               r = -ENXIO;
+       }
+
+       return r;
+}
+
+static int write_header(struct pstore *ps)
+{
+       struct disk_header *dh;
+
+       memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT);
+
+       dh = (struct disk_header *) ps->area;
+       dh->magic = SNAP_MAGIC;
+       dh->valid = ps->valid;
+       dh->version = ps->version;
+       dh->chunk_size = ps->chunk_size;
+
+       return chunk_io(ps, 0, WRITE);
+}
+
 /*
  * Access functions for the disk exceptions, these do the endian conversions.
  */
 static struct disk_exception *get_exception(struct pstore *ps, uint32_t index)
 {
-       if (index > ps->exceptions_per_area)
+       if (index >= ps->exceptions_per_area)
                return NULL;
 
        return ((struct disk_exception *) ps->area) + index;
@@ -271,10 +355,8 @@ static int read_exception(struct pstore *ps,
                return -EINVAL;
 
        /* copy it */
-       memcpy(result, e, sizeof(&result));
-
-       result->old_chunk = le64_to_cpu(result->old_chunk);
-       result->new_chunk = le64_to_cpu(result->new_chunk);
+       result->old_chunk = le64_to_cpu(e->old_chunk);
+       result->new_chunk = le64_to_cpu(e->new_chunk);
 
        return 0;
 }
@@ -289,8 +371,8 @@ static int write_exception(struct pstore *ps,
                return -EINVAL;
 
        /* copy it */
-       e->old_chunk = cpu_to_le64(e->old_chunk);
-       e->new_chunk = cpu_to_le64(e->new_chunk);
+       e->old_chunk = cpu_to_le64(de->old_chunk);
+       e->new_chunk = cpu_to_le64(de->new_chunk);
 
        return 0;
 }
@@ -318,9 +400,9 @@ static int insert_exceptions(struct pstore *ps, int *full)
                 * If the new_chunk is pointing at the start of
                 * the COW device, where the first metadata area
                 * is we know that we've hit the end of the
-                * exceptions.  Therefor the area is not full.
+                * exceptions.  Therefore the area is not full.
                 */
-               if (de.new_chunk) {
+               if (de.new_chunk == 0LL) {
                        ps->current_committed = i;
                        *full = 0;
                        break;
@@ -346,13 +428,13 @@ static int insert_exceptions(struct pstore *ps, int *full)
 static int read_exceptions(struct pstore *ps)
 {
        uint32_t area;
-       int r, full = 0;
+       int r, full = 1;
 
        /*
         * Keeping reading chunks and inserting exceptions until
         * we find a partially full area.
         */
-       for (area = 0; !full; area++) {
+       for (area = 0; full; area++) {
                r = area_io(ps, area, READ);
                if (r)
                        return r;
@@ -372,12 +454,19 @@ static inline struct pstore *get_info(struct exception_store *store)
        return (struct pstore *) store->context;
 }
 
+static int persistent_percentfull(struct exception_store *store)
+{
+       struct pstore *ps = get_info(store);
+       return (ps->next_free * store->snap->chunk_size * 100) /
+           get_dev_size(store->snap->cow->dev);
+}
+
 static void persistent_destroy(struct exception_store *store)
 {
        struct pstore *ps = get_info(store);
 
+       vfree(ps->callbacks);
        free_iobuf(ps);
-       vfree(ps->area);
        kfree(ps);
 }
 
@@ -386,6 +475,11 @@ static int persistent_prepare(struct exception_store *store,
 {
        struct pstore *ps = get_info(store);
        uint32_t stride;
+       offset_t size = get_dev_size(store->snap->cow->dev);
+
+       /* Is there enough room ? */
+       if (size <= (ps->next_free * store->snap->chunk_size))
+               return -ENOSPC;
 
        e->new_chunk = ps->next_free;
 
@@ -397,6 +491,7 @@ static int persistent_prepare(struct exception_store *store,
        if (!(++ps->next_free % stride))
                ps->next_free++;
 
+       atomic_inc(&ps->pending_count);
        return 0;
 }
 
@@ -405,59 +500,67 @@ static void persistent_commit(struct exception_store *store,
                              void (*callback) (void *, int success),
                              void *callback_context)
 {
-       int r;
+       int r, i;
        struct pstore *ps = get_info(store);
        struct disk_exception de;
+       struct commit_callback *cb;
 
        de.old_chunk = e->old_chunk;
        de.new_chunk = e->new_chunk;
-       write_exception(ps, ps->current_committed, &de);
+       write_exception(ps, ps->current_committed++, &de);
 
        /*
-        * Write the whole area to the disk for now, later we'll
-        * try and defer the write.
+        * Add the callback to the back of the array.  This code
+        * is the only place where the callback array is
+        * manipulated, and we know that it will never be called
+        * multiple times concurrently.
         */
-       r = area_io(ps, ps->current_area, WRITE);
-       if (r)
-               goto bad;
+       cb = ps->callbacks + ps->callback_count++;
+       cb->callback = callback;
+       cb->context = callback_context;
 
        /*
-        * Notify the snapshot that the commit has actually
-        * happened.
+        * If there are no more exceptions in flight, or we have
+        * filled this metadata area we commit the exceptions to
+        * disk.
         */
-       callback(callback_context, 1);
+       if (atomic_dec_and_test(&ps->pending_count) ||
+           (ps->current_committed == ps->exceptions_per_area)) {
+               r = area_io(ps, ps->current_area, WRITE);
+               if (r)
+                       ps->valid = 0;
+
+               for (i = 0; i < ps->callback_count; i++) {
+                       cb = ps->callbacks + i;
+                       cb->callback(cb->context, r == 0 ? 1 : 0);
+               }
+
+               ps->callback_count = 0;
+       }
 
        /*
         * Have we completely filled the current area ?
         */
-       if (++ps->current_committed > ps->exceptions_per_area) {
+       if (ps->current_committed == ps->exceptions_per_area) {
                ps->current_committed = 0;
                r = zero_area(ps, ps->current_area + 1);
                if (r)
-                       goto bad;
+                       ps->valid = 0;
        }
-
-       return;
-
-      bad:
-       ps->valid = 0;
-       callback(callback_context, 0);
 }
 
 static void persistent_drop(struct exception_store *store)
 {
        struct pstore *ps = get_info(store);
 
-       /*
-        * FIXME: This function is pointless until we have the
-        * header.
-        */
        ps->valid = 0;
+       if (write_header(ps))
+               DMWARN("write header failed");
 }
 
-int persistent_init(struct exception_store *store, uint32_t chunk_size)
+int dm_create_persistent(struct exception_store *store, uint32_t chunk_size)
 {
-       int r;
+       int r, new_snapshot;
        struct pstore *ps;
 
        /* allocate the pstore */
@@ -465,34 +568,99 @@ int persistent_init(struct exception_store *store, uint32_t chunk_size)
        if (!ps)
                return -ENOMEM;
 
-       r = allocate_iobuf(ps);
-       if (r)
-               return r;
-
        ps->snap = store->snap;
        ps->valid = 1;
+       ps->version = SNAPSHOT_DISK_VERSION;
        ps->chunk_size = chunk_size;
        ps->exceptions_per_area = (chunk_size << SECTOR_SHIFT) /
            sizeof(struct disk_exception);
-       ps->next_free = 1;
+       ps->next_free = 2;      /* skipping the header and first area */
        ps->current_committed = 0;
 
+       r = allocate_iobuf(ps);
+       if (r)
+               goto bad;
+
        /*
-        * Read the metadata.
+        * Allocate space for all the callbacks.
         */
-       r = read_exceptions(ps);
-       if (r) {
-               free_iobuf(ps);
-               kfree(ps);
+       ps->callback_count = 0;
+       atomic_set(&ps->pending_count, 0);
+       ps->callbacks = vmalloc(sizeof(*ps->callbacks) *
+                               ps->exceptions_per_area);
+
+       if (!ps->callbacks)
+               goto bad;
+
+       /*
+        * Read the snapshot header.
+        */
+       r = read_header(ps, &new_snapshot);
+       if (r)
+               goto bad;
+
+       /*
+        * Do we need to setup a new snapshot ?
+        */
+       if (new_snapshot) {
+               r = write_header(ps);
+               if (r) {
+                       DMWARN("write_header failed");
+                       goto bad;
+               }
+
+               r = zero_area(ps, 0);
+               if (r) {
+                       DMWARN("zero_area(0) failed");
+                       goto bad;
+               }
+
+       } else {
+               /*
+                * Sanity checks.
+                */
+               if (ps->chunk_size != chunk_size) {
+                       DMWARN("chunk size for existing snapshot different "
+                              "from that requested");
+                       r = -EINVAL;
+                       goto bad;
+               }
+
+               if (ps->version != SNAPSHOT_DISK_VERSION) {
+                       DMWARN("unable to handle snapshot disk version %d",
+                              ps->version);
+                       r = -EINVAL;
+                       goto bad;
+               }
+
+               /*
+                * Read the metadata.
+                */
+               r = read_exceptions(ps);
+               if (r)
+                       goto bad;
        }
 
        store->destroy = persistent_destroy;
        store->prepare_exception = persistent_prepare;
        store->commit_exception = persistent_commit;
        store->drop_snapshot = persistent_drop;
+       store->percent_full = persistent_percentfull;
        store->context = ps;
 
        return r;
+
+      bad:
+       if (ps) {
+               if (ps->callbacks)
+                       vfree(ps->callbacks);
+
+               if (ps->iobuf)
+                       free_iobuf(ps);
+
+               kfree(ps);
+       }
+       return r;
 }
 
 /*-----------------------------------------------------------------
@@ -502,12 +670,12 @@ struct transient_c {
        offset_t next_free;
 };
 
-void destroy_transient(struct exception_store *store)
+void transient_destroy(struct exception_store *store)
 {
        kfree(store->context);
 }
 
-int prepare_transient(struct exception_store *store, struct exception *e)
+int transient_prepare(struct exception_store *store, struct exception *e)
 {
        struct transient_c *tc = (struct transient_c *) store->context;
        offset_t size = get_dev_size(store->snap->cow->dev);
@@ -521,7 +689,7 @@ int prepare_transient(struct exception_store *store, struct exception *e)
        return 0;
 }
 
-void commit_transient(struct exception_store *store,
+void transient_commit(struct exception_store *store,
                      struct exception *e,
                      void (*callback) (void *, int success),
                      void *callback_context)
@@ -530,7 +698,7 @@ void commit_transient(struct exception_store *store,
        callback(callback_context, 1);
 }
 
-int percentfull_transient(struct exception_store *store)
+static int transient_percentfull(struct exception_store *store)
 {
        struct transient_c *tc = (struct transient_c *) store->context;
        return (tc->next_free * 100) / get_dev_size(store->snap->cow->dev);
@@ -542,10 +710,10 @@ int dm_create_transient(struct exception_store *store,
        struct transient_c *tc;
 
        memset(store, 0, sizeof(*store));
-       store->destroy = destroy_transient;
-       store->prepare_exception = prepare_transient;
-       store->commit_exception = commit_transient;
-       store->percent_full = percentfull_transient;
+       store->destroy = transient_destroy;
+       store->prepare_exception = transient_prepare;
+       store->commit_exception = transient_commit;
+       store->percent_full = transient_percentfull;
        store->snap = s;
 
        tc = kmalloc(sizeof(struct transient_c), GFP_KERNEL);
index ba10296755f9968fad3fc72c9acbbae084b04cbd..2a69b4e5418c53252544797b6041e3f3db26b455 100644 (file)
@@ -79,12 +79,12 @@ static int linear_map(struct buffer_head *bh, int rw, void *context)
        return 1;
 }
 
-static int linear_sts(status_type_t sts_type, char *result, int maxlen,
-                     void *context)
+static int linear_status(status_type_t type, char *result, int maxlen,
+                        void *context)
 {
        struct linear_c *lc = (struct linear_c *) context;
 
-       switch (sts_type) {
+       switch (type) {
        case STATUSTYPE_INFO:
                result[0] = '\0';
                break;
@@ -103,7 +103,7 @@ static struct target_type linear_target = {
        ctr:    linear_ctr,
        dtr:    linear_dtr,
        map:    linear_map,
-       sts:    linear_sts,
+       status: linear_status,
        wait:   NULL,           /* No wait function */
 };
 
index c1bd3818b264a7a288afe9275d416323d68ccfe0..8168101ed525a0d05f7db666365677f779d01e08 100644 (file)
@@ -504,6 +504,7 @@ static int snapshot_ctr(struct dm_table *t, offset_t b, offset_t l,
        init_waitqueue_head(&s->waitq);
        s->chunk_size = chunk_size;
        s->chunk_mask = chunk_size - 1;
+       s->type = *persistent;
        for (s->chunk_shift = 0; chunk_size;
             s->chunk_shift++, chunk_size >>= 1)
                ;
@@ -524,12 +525,11 @@ static int snapshot_ctr(struct dm_table *t, offset_t b, offset_t l,
         * Check the persistent flag - done here because we need the iobuf
         * to check the LV header
         */
-#if 0
+       s->store.snap = s;
+
        if ((*persistent & 0x5f) == 'P')
-               r = dm_create_persistent(&s->store, s, blocksize,
-                                        extent_size, context);
+               r = dm_create_persistent(&s->store, s->chunk_size);
        else
-#endif
                r = dm_create_transient(&s->store, s, blocksize, context);
 
        if (r) {
@@ -554,6 +554,7 @@ static int snapshot_ctr(struct dm_table *t, offset_t b, offset_t l,
 #if LVM_VFS_ENHANCEMENT
        unlockfs(s->origin->dev);
 #endif
+       kcopyd_inc_client_count();
 
        *context = s;
        return 0;
@@ -593,6 +594,8 @@ static void snapshot_dtr(struct dm_table *t, void *context)
        dm_table_put_device(t, s->origin);
        dm_table_put_device(t, s->cow);
        kfree(s);
+
+       kcopyd_dec_client_count();
 }
 
 /*
@@ -620,7 +623,6 @@ static void flush_buffers(struct buffer_head *bh)
                bh = n;
        }
 
-       /* FIXME: not sure we can this from this context. */
        run_task_queue(&tq_disk);
 }
 
@@ -873,6 +875,20 @@ static int snapshot_map(struct buffer_head *bh, int rw, void *context)
        return r;
 }
 
+static void list_merge(struct list_head *l1, struct list_head *l2)
+{
+       struct list_head *l1_n, *l2_p;
+
+       l1_n = l1->next;
+       l2_p = l2->prev;
+
+       l1->next = l2;
+       l2->prev = l1;
+
+       l2_p->next = l1_n;
+       l1_n->prev = l2_p;
+}
+
 static int __origin_write(struct list_head *snapshots, struct buffer_head *bh)
 {
        int r = 1;
@@ -912,8 +928,8 @@ static int __origin_write(struct list_head *snapshots, struct buffer_head *bh)
 
                        } else {
                                if (last)
-                                       list_splice(&pe->siblings,
-                                                   &last->siblings);
+                                       list_merge(&pe->siblings,
+                                                  &last->siblings);
 
                                last = pe;
                                r = 0;
@@ -942,14 +958,14 @@ static int __origin_write(struct list_head *snapshots, struct buffer_head *bh)
        return r;
 }
 
-static int snapshot_sts(status_type_t sts_type, char *result,
-                       int maxlen, void *context)
+static int snapshot_status(status_type_t type, char *result,
+                          int maxlen, void *context)
 {
        struct dm_snapshot *snap = (struct dm_snapshot *) context;
-       char cowdevname[PATH_MAX];
-       char orgdevname[PATH_MAX];
+       char cow[16];
+       char org[16];
 
-       switch (sts_type) {
+       switch (type) {
        case STATUSTYPE_INFO:
                if (!snap->valid)
                        snprintf(result, maxlen, "Invalid");
@@ -964,13 +980,15 @@ static int snapshot_sts(status_type_t sts_type, char *result,
                break;
 
        case STATUSTYPE_TABLE:
-               /* kdevname returns a static pointer so we
-                  need to make private copies if the output is to make sense */
-               strcpy(cowdevname, kdevname(snap->cow->dev));
-               strcpy(orgdevname, kdevname(snap->origin->dev));
-               snprintf(result, maxlen, "%s %s %c %ld", orgdevname, cowdevname,
-                        'N',   /* TODO persistent snaps */
-                        snap->chunk_size);
+               /*
+                * kdevname returns a static pointer so we need
+                * to make private copies if the output is to
+                * make sense.
+                */
+               strncpy(cow, kdevname(snap->cow->dev), sizeof(cow));
+               strncpy(org, kdevname(snap->origin->dev), sizeof(org));
+               snprintf(result, maxlen, "%s %s %c %ld", org, cow,
+                        snap->type, snap->chunk_size);
                break;
        }
 
@@ -1054,12 +1072,12 @@ static int origin_map(struct buffer_head *bh, int rw, void *context)
        return (rw == WRITE) ? do_origin(dev, bh) : 1;
 }
 
-static int origin_sts(status_type_t sts_type, char *result,
-                     int maxlen, void *context)
+static int origin_status(status_type_t type, char *result,
+                        int maxlen, void *context)
 {
        struct dm_dev *dev = (struct dm_dev *) context;
 
-       switch (sts_type) {
+       switch (type) {
        case STATUSTYPE_INFO:
                result[0] = '\0';
                break;
@@ -1078,7 +1096,7 @@ static struct target_type origin_target = {
        ctr:    origin_ctr,
        dtr:    origin_dtr,
        map:    origin_map,
-       sts:    origin_sts,
+       status: origin_status,
        wait:   NULL,
        err:    NULL
 };
@@ -1089,7 +1107,7 @@ static struct target_type snapshot_target = {
        ctr:    snapshot_ctr,
        dtr:    snapshot_dtr,
        map:    snapshot_map,
-       sts:    snapshot_sts,
+       status: snapshot_status,
        wait:   snapshot_wait,
        err:    NULL
 };
index 6741f96ae9228af075422c438b88dcdfa70ff85d..e72ae595c69716c609930405c3880502e2f371b0 100644 (file)
@@ -94,6 +94,9 @@ struct dm_snapshot {
        /* You can't use a snapshot if this is 0 (e.g. if full) */
        int valid;
 
+       /* Used for display of table */
+       char type;
+
        /* The last percentage we notified */
        int last_percent;
 
@@ -114,9 +117,7 @@ int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new);
  * Constructor and destructor for the default persistent
  * store.
  */
-int dm_create_persistent(struct exception_store *store,
-                        struct dm_snapshot *s,
-                        int blocksize, offset_t extent_size, void **error);
+int dm_create_persistent(struct exception_store *store, uint32_t chunk_size);
 
 int dm_create_transient(struct exception_store *store,
                        struct dm_snapshot *s, int blocksize, void **error);
index a0ae1d64f605c93b96e67ceea00e4031f7f08d3c..337aea2e21901ffecc3277f807618109aa781999 100644 (file)
@@ -173,14 +173,14 @@ static int stripe_map(struct buffer_head *bh, int rw, void *context)
        return 1;
 }
 
-static int stripe_sts(status_type_t sts_type, char *result, int maxlen,
-                     void *context)
+static int stripe_status(status_type_t type, char *result, int maxlen,
+                        void *context)
 {
        struct stripe_c *sc = (struct stripe_c *) context;
        int offset;
        int i;
 
-       switch (sts_type) {
+       switch (type) {
        case STATUSTYPE_INFO:
                result[0] = '\0';
                break;
@@ -206,7 +206,7 @@ static struct target_type stripe_target = {
        ctr:    stripe_ctr,
        dtr:    stripe_dtr,
        map:    stripe_map,
-       sts:    stripe_sts,
+       status: stripe_status,
        wait:   NULL,
 };
 
index cb6094843dbbd6d86a021278045326585e71ae9c..fc5c64098bd2dabf35eee8b8e1763baf678530a1 100644 (file)
@@ -224,8 +224,8 @@ static struct target_type error_target = {
        ctr:    io_err_ctr,
        dtr:    io_err_dtr,
        map:    io_err_map,
-       sts:    NULL,
-       wait:   NULL,
+       status: NULL,
+       wait:   NULL,
 };
 
 int dm_target_init(void)
index d3385dc497f27d497a4c0ccbd3290c4bb3b13257..c59fbc4c365ceb3533cc5793ab34d8153a89c7de 100644 (file)
@@ -272,7 +272,6 @@ static struct {
        xx(dm_target)
        xx(dm_linear)
        xx(dm_stripe)
-       xx(kcopyd)
        xx(dm_snapshot)
        xx(dm_interface)
 #undef xx
index 64372e17d1f1589b3339f27940658cf08129d70a..cc50b75a8e09caa2eb27d97ebca0103d22135fa2 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/device-mapper.h>
 #include <linux/mempool.h>
 #include <asm/atomic.h>
+#include <linux/pagemap.h>
+#include <linux/locks.h>
 
 #include "kcopyd.h"
 
@@ -25,7 +27,8 @@
  */
 #define SECTOR_SIZE 512
 #define SECTOR_SHIFT 9
-static int wake_kcopyd(void);
+
+static void wake_kcopyd(void);
 
 /*-----------------------------------------------------------------
  * We reserve our own pool of preallocated pages that are
@@ -40,8 +43,9 @@ static int wake_kcopyd(void);
 static DECLARE_MUTEX(_pages_lock);
 static int _num_free_pages;
 static struct page *_pages_array[NUM_PAGES];
+static DECLARE_MUTEX(start_lock);
 
-static __init int init_pages(void)
+static int init_pages(void)
 {
        int i;
        struct page *p;
@@ -123,7 +127,7 @@ static spinlock_t _buffer_lock = SPIN_LOCK_UNLOCKED;
 static struct buffer_head *_all_buffers;
 static struct buffer_head *_free_buffers;
 
-static __init int init_buffers(void)
+static int init_buffers(void)
 {
        int i;
        struct buffer_head *buffers;
@@ -215,7 +219,7 @@ static LIST_HEAD(_complete_jobs);
 static LIST_HEAD(_io_jobs);
 static LIST_HEAD(_pages_jobs);
 
-static __init int init_jobs(void)
+static int init_jobs(void)
 {
        INIT_LIST_HEAD(&_complete_jobs);
        INIT_LIST_HEAD(&_io_jobs);
@@ -458,24 +462,23 @@ static void do_work(void)
 /*-----------------------------------------------------------------
  * The daemon
  *---------------------------------------------------------------*/
-static struct task_struct *_kcopyd_task;
 static atomic_t _kcopyd_must_die;
 static DECLARE_MUTEX(_run_lock);
 static DECLARE_WAIT_QUEUE_HEAD(_job_queue);
 
-static int kcopyd(void *start_lock)
+static int kcopyd(void *arg)
 {
        DECLARE_WAITQUEUE(wq, current);
 
        daemonize();
        strcpy(current->comm, "kcopyd");
-       _kcopyd_task = current;
        atomic_set(&_kcopyd_must_die, 0);
-       down(&_run_lock);
-       up((struct semaphore *) start_lock);
 
        add_wait_queue(&_job_queue, &wq);
 
+       down(&_run_lock);
+       up(&start_lock);
+
        while (1) {
                set_current_state(TASK_INTERRUPTIBLE);
 
@@ -490,17 +493,17 @@ static int kcopyd(void *start_lock)
        remove_wait_queue(&_job_queue, &wq);
 
        up(&_run_lock);
-       DMINFO("kcopyd shutting down");
+
        return 0;
 }
 
 static int start_daemon(void)
 {
        static pid_t pid = 0;
-       DECLARE_MUTEX(start_lock);
 
        down(&start_lock);
-       pid = kernel_thread(kcopyd, &start_lock, 0);
+
+       pid = kernel_thread(kcopyd, NULL, 0);
        if (pid <= 0) {
                DMERR("Failed to start kcopyd thread");
                return -EAGAIN;
@@ -510,34 +513,24 @@ static int start_daemon(void)
         * wait for the daemon to up this mutex.
         */
        down(&start_lock);
-       DMINFO("Started kcopyd thread");
+       up(&start_lock);
 
        return 0;
 }
 
 static int stop_daemon(void)
 {
-       if (_kcopyd_task) {
-               atomic_set(&_kcopyd_must_die, 1);
-               wake_kcopyd();
-               down(&_run_lock);
-       }
+       atomic_set(&_kcopyd_must_die, 1);
+       wake_kcopyd();
+       down(&_run_lock);
+       up(&_run_lock);
 
        return 0;
 }
 
-static int wake_kcopyd(void)
+static void wake_kcopyd(void)
 {
-       int r = 0;
-
-       /* Start the thread if we don't have one already */
-       if (!_kcopyd_task)
-               r = start_daemon();
-
-       if (!r)
-               wake_up_interruptible(&_job_queue);
-
-       return r;
+       wake_up_interruptible(&_job_queue);
 }
 
 static int calc_shift(unsigned int n)
@@ -584,7 +577,7 @@ struct copy_info {
 static kmem_cache_t *_copy_cache = NULL;
 static mempool_t *_copy_pool = NULL;
 
-static __init int init_copier(void)
+static int init_copier(void)
 {
        _copy_cache = kmem_cache_create("kcopyd-info",
                                        sizeof(struct copy_info),
@@ -636,7 +629,6 @@ void copy_complete(struct kcopyd_job *job)
 
 /*
  * These callback functions implement the state machine that copies regions.
- * FIXME: handle large regions.
  */
 void copy_write(struct kcopyd_job *job)
 {
@@ -717,24 +709,22 @@ static struct {
 #undef xx
 };
 
-static int _has_initialised = 0;
+static int _client_count = 0;
+static DECLARE_MUTEX(_client_count_sem);
 
-int __init kcopyd_init(void)
+static int kcopyd_init(void)
 {
        const int count = sizeof(_inits) / sizeof(*_inits);
 
        int r, i;
 
-       if (_has_initialised)
-               return 0;
-
        for (i = 0; i < count; i++) {
                r = _inits[i].init();
                if (r)
                        goto bad;
        }
 
-       _has_initialised = 1;
+       start_daemon();
        return 0;
 
       bad:
@@ -744,7 +734,7 @@ int __init kcopyd_init(void)
        return r;
 }
 
-void kcopyd_exit(void)
+static void kcopyd_exit(void)
 {
        int i = sizeof(_inits) / sizeof(*_inits);
 
@@ -753,6 +743,28 @@ void kcopyd_exit(void)
 
        while (i--)
                _inits[i].exit();
+}
+
+void kcopyd_inc_client_count(void)
+{
+       /*
+        * What I need here is an atomic_test_and_inc that returns
+        * the previous value of the atomic...  In its absence I lock
+        * an int with a semaphore. :-(
+        */
+       down(&_client_count_sem);
+       if (_client_count == 0)
+               kcopyd_init();
+       _client_count++;
+
+       up(&_client_count_sem);
+}
+
+void kcopyd_dec_client_count(void)
+{
+       down(&_client_count_sem);
+       if (--_client_count == 0)
+               kcopyd_exit();
 
-       _has_initialised = 0;
+       up(&_client_count_sem);
 }
index dcfdbae4a4e707ac677322069f34a4bb511e9883..be316f70aced661d6d4ccfff724f5472c3af1964 100644 (file)
@@ -66,7 +66,7 @@ struct kcopyd_job {
         * Set this to ensure you are notified when the job has
         * completed.  'context' is for callback to use.
         */
-       void (*callback) (struct kcopyd_job *job);
+       void (*callback)(struct kcopyd_job *job);
        void *context;
 };
 
@@ -82,15 +82,16 @@ int kcopyd_queue_job(struct kcopyd_job *job);
  * Submit a copy job to kcopyd.  This is built on top of the
  * previous three fns.
  */
-typedef void (*kcopyd_notify_fn) (int err, void *context);
+typedef void (*kcopyd_notify_fn)(int err, void *context);
 
-int kcopyd_copy(struct kcopyd_region *from,
-               struct kcopyd_region *to, kcopyd_notify_fn fn, void *context);
+int kcopyd_copy(struct kcopyd_region *from, struct kcopyd_region *to,
+               kcopyd_notify_fn fn, void *context);
 
 /*
- * Setup/teardown.
+ * We only want kcopyd to reserve resources if someone is
+ * actually using it.
  */
-int kcopyd_init(void);
-void kcopyd_exit(void);
+void kcopyd_inc_client_count(void);
+void kcopyd_dec_client_count(void);
 
 #endif
index 41d582ec6c5dbd2f21a5635b8bb2e19502d1ccec..600162167f44520cde5dd8926167c61c10de0ef2 100644 (file)
@@ -283,7 +283,7 @@ static int __status(struct mapped_device *md, struct dm_ioctl *param,
 
                if (outptr - outbuf +
                    sizeof(struct dm_target_spec) > param->data_size)
-                       return -ENOMEM;
+                           return -ENOMEM;
 
                spec = (struct dm_target_spec *) outptr;
 
@@ -295,10 +295,10 @@ static int __status(struct mapped_device *md, struct dm_ioctl *param,
                outptr += sizeof(struct dm_target_spec);
 
                /* Get the status/table string from the target driver */
-               if (tt->sts)
-                       tt->sts(type, outptr,
-                               outbuf + param->data_size - outptr,
-                               md->map->targets[i].private);
+               if (tt->status)
+                       tt->status(type, outptr,
+                                  outbuf + param->data_size - outptr,
+                                  md->map->targets[i].private);
                else
                        outptr[0] = '\0';
 
@@ -331,7 +331,7 @@ static int __wait(struct mapped_device *md, struct dm_ioctl *param)
                /* Add ourself to the target's wait queue */
                if (tt->wait &&
                    (!tt->wait(md->map->targets[i].private, &waitq, 1)))
-                       waiting = 1;
+                           waiting = 1;
        }
 
        /* If at least one call succeeded then sleep */
@@ -525,7 +525,7 @@ static int create(struct dm_ioctl *param, struct dm_ioctl *user)
        }
 
        minor = (param->flags & DM_PERSISTENT_DEV_FLAG) ?
-               MINOR(to_kdev_t(param->dev)) : -1;
+           MINOR(to_kdev_t(param->dev)) : -1;
 
        ro = (param->flags & DM_READONLY_FLAG) ? 1 : 0;
 
This page took 0.063965 seconds and 5 git commands to generate.