Blackfin: don't walk VMAs when oopsing
[safe/jmp/linux-2.6] / drivers / md / dm-snap.c
index 974916b..3a3ba46 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/workqueue.h>
 
 #include "dm-exception-store.h"
-#include "dm-bio-list.h"
 
 #define DM_MSG_PREFIX "snapshots"
 
@@ -70,9 +69,6 @@ struct dm_snapshot {
        /* Origin writes don't trigger exceptions until this is set */
        int active;
 
-       /* Used for display of table */
-       char type;
-
        mempool_t *pending_pool;
 
        atomic_t pending_exceptions_count;
@@ -300,6 +296,7 @@ static void __insert_origin(struct origin *o)
  */
 static int register_snapshot(struct dm_snapshot *snap)
 {
+       struct dm_snapshot *l;
        struct origin *o, *new_o;
        struct block_device *bdev = snap->origin->bdev;
 
@@ -323,7 +320,11 @@ static int register_snapshot(struct dm_snapshot *snap)
                __insert_origin(o);
        }
 
-       list_add_tail(&snap->list, &o->snapshots);
+       /* Sort the list according to chunk size, largest-first smallest-last */
+       list_for_each_entry(l, &o->snapshots, list)
+               if (l->store->chunk_size < snap->store->chunk_size)
+                       break;
+       list_add_tail(&snap->list, &l->list);
 
        up_write(&_origins_lock);
        return 0;
@@ -672,6 +673,11 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        bio_list_init(&s->queued_bios);
        INIT_WORK(&s->queued_bios_work, flush_queued_bios);
 
+       if (!s->store->chunk_size) {
+               ti->error = "Chunk size not set";
+               goto bad_load_and_register;
+       }
+
        /* Add snapshot to the list of snapshots for this origin */
        /* Exceptions aren't triggered till snapshot_resume() is called */
        if (register_snapshot(s)) {
@@ -682,6 +688,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
 
        ti->private = s;
        ti->split_io = s->store->chunk_size;
+       ti->num_flush_requests = 1;
 
        return 0;
 
@@ -954,7 +961,7 @@ static void start_copy(struct dm_snap_pending_exception *pe)
 
        src.bdev = bdev;
        src.sector = chunk_to_sector(s->store, pe->e.old_chunk);
-       src.count = min(s->store->chunk_size, dev_size - src.sector);
+       src.count = min((sector_t)s->store->chunk_size, dev_size - src.sector);
 
        dest.bdev = s->store->cow->bdev;
        dest.sector = chunk_to_sector(s->store, pe->e.new_chunk);
@@ -1034,6 +1041,11 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
        chunk_t chunk;
        struct dm_snap_pending_exception *pe = NULL;
 
+       if (unlikely(bio_empty_barrier(bio))) {
+               bio->bi_bdev = s->store->cow->bdev;
+               return DM_MAPIO_REMAPPED;
+       }
+
        chunk = sector_to_chunk(s->store, bio->bi_sector);
 
        /* Full snapshots are not usable */
@@ -1140,6 +1152,8 @@ static int snapshot_status(struct dm_target *ti, status_type_t type,
        unsigned sz = 0;
        struct dm_snapshot *snap = ti->private;
 
+       down_write(&snap->lock);
+
        switch (type) {
        case STATUSTYPE_INFO:
                if (!snap->valid)
@@ -1166,15 +1180,25 @@ static int snapshot_status(struct dm_target *ti, status_type_t type,
                 * make sense.
                 */
                DMEMIT("%s", snap->origin->name);
-               DMEMIT(" %s %s %llu", snap->store->cow->name,
-                      snap->store->type->name,
-                      (unsigned long long)snap->store->chunk_size);
+               snap->store->type->status(snap->store, type, result + sz,
+                                         maxlen - sz);
                break;
        }
 
+       up_write(&snap->lock);
+
        return 0;
 }
 
+static int snapshot_iterate_devices(struct dm_target *ti,
+                                   iterate_devices_callout_fn fn, void *data)
+{
+       struct dm_snapshot *snap = ti->private;
+
+       return fn(ti, snap->origin, 0, ti->len, data);
+}
+
+
 /*-----------------------------------------------------------------
  * Origin methods
  *---------------------------------------------------------------*/
@@ -1343,6 +1367,8 @@ static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        }
 
        ti->private = dev;
+       ti->num_flush_requests = 1;
+
        return 0;
 }
 
@@ -1358,6 +1384,9 @@ static int origin_map(struct dm_target *ti, struct bio *bio,
        struct dm_dev *dev = ti->private;
        bio->bi_bdev = dev->bdev;
 
+       if (unlikely(bio_empty_barrier(bio)))
+               return DM_MAPIO_REMAPPED;
+
        /* Only tell snapshots if this is a write */
        return (bio_rw(bio) == WRITE) ? do_origin(dev, bio) : DM_MAPIO_REMAPPED;
 }
@@ -1373,7 +1402,7 @@ static void origin_resume(struct dm_target *ti)
        struct dm_dev *dev = ti->private;
        struct dm_snapshot *snap;
        struct origin *o;
-       chunk_t chunk_size = 0;
+       unsigned chunk_size = 0;
 
        down_read(&_origins_lock);
        o = __lookup_origin(dev->bdev);
@@ -1404,20 +1433,29 @@ static int origin_status(struct dm_target *ti, status_type_t type, char *result,
        return 0;
 }
 
+static int origin_iterate_devices(struct dm_target *ti,
+                                 iterate_devices_callout_fn fn, void *data)
+{
+       struct dm_dev *dev = ti->private;
+
+       return fn(ti, dev, 0, ti->len, data);
+}
+
 static struct target_type origin_target = {
        .name    = "snapshot-origin",
-       .version = {1, 6, 0},
+       .version = {1, 7, 0},
        .module  = THIS_MODULE,
        .ctr     = origin_ctr,
        .dtr     = origin_dtr,
        .map     = origin_map,
        .resume  = origin_resume,
        .status  = origin_status,
+       .iterate_devices = origin_iterate_devices,
 };
 
 static struct target_type snapshot_target = {
        .name    = "snapshot",
-       .version = {1, 6, 0},
+       .version = {1, 7, 0},
        .module  = THIS_MODULE,
        .ctr     = snapshot_ctr,
        .dtr     = snapshot_dtr,
@@ -1425,6 +1463,7 @@ static struct target_type snapshot_target = {
        .end_io  = snapshot_end_io,
        .resume  = snapshot_resume,
        .status  = snapshot_status,
+       .iterate_devices = snapshot_iterate_devices,
 };
 
 static int __init dm_snapshot_init(void)
@@ -1440,7 +1479,7 @@ static int __init dm_snapshot_init(void)
        r = dm_register_target(&snapshot_target);
        if (r) {
                DMERR("snapshot target register failed %d", r);
-               return r;
+               goto bad_register_snapshot_target;
        }
 
        r = dm_register_target(&origin_target);
@@ -1497,6 +1536,9 @@ bad2:
        dm_unregister_target(&origin_target);
 bad1:
        dm_unregister_target(&snapshot_target);
+
+bad_register_snapshot_target:
+       dm_exception_store_exit();
        return r;
 }