]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/md/dm.c
Merge git://git.infradead.org/battery-2.6
[linux-2.6-omap-h63xx.git] / drivers / md / dm.c
index fe7c56e104359ce95ce8b34143542535d030c78c..141ff9fa296e2a429436e1c402ef330df0c89cac 100644 (file)
@@ -45,7 +45,7 @@ struct dm_io {
  * One of these is allocated per target within a bio.  Hopefully
  * this will be simplified out one day.
  */
-struct target_io {
+struct dm_target_io {
        struct dm_io *io;
        struct dm_target *ti;
        union map_info info;
@@ -54,7 +54,7 @@ struct target_io {
 union map_info *dm_get_mapinfo(struct bio *bio)
 {
        if (bio && bio->bi_private)
-               return &((struct target_io *)bio->bi_private)->info;
+               return &((struct dm_target_io *)bio->bi_private)->info;
        return NULL;
 }
 
@@ -80,7 +80,7 @@ struct mapped_device {
 
        unsigned long flags;
 
-       request_queue_t *queue;
+       struct request_queue *queue;
        struct gendisk *disk;
        char name[16];
 
@@ -132,14 +132,12 @@ static int __init local_init(void)
        int r;
 
        /* allocate a slab for the dm_ios */
-       _io_cache = kmem_cache_create("dm_io",
-                                     sizeof(struct dm_io), 0, 0, NULL, NULL);
+       _io_cache = KMEM_CACHE(dm_io, 0);
        if (!_io_cache)
                return -ENOMEM;
 
        /* allocate a slab for the target ios */
-       _tio_cache = kmem_cache_create("dm_tio", sizeof(struct target_io),
-                                      0, 0, NULL, NULL);
+       _tio_cache = KMEM_CACHE(dm_target_io, 0);
        if (!_tio_cache) {
                kmem_cache_destroy(_io_cache);
                return -ENOMEM;
@@ -163,9 +161,7 @@ static void local_exit(void)
 {
        kmem_cache_destroy(_tio_cache);
        kmem_cache_destroy(_io_cache);
-
-       if (unregister_blkdev(_major, _name) < 0)
-               DMERR("unregister_blkdev failed");
+       unregister_blkdev(_major, _name);
 
        _major = 0;
 
@@ -325,22 +321,22 @@ out:
        return r;
 }
 
-static inline struct dm_io *alloc_io(struct mapped_device *md)
+static struct dm_io *alloc_io(struct mapped_device *md)
 {
        return mempool_alloc(md->io_pool, GFP_NOIO);
 }
 
-static inline void free_io(struct mapped_device *md, struct dm_io *io)
+static void free_io(struct mapped_device *md, struct dm_io *io)
 {
        mempool_free(io, md->io_pool);
 }
 
-static inline struct target_io *alloc_tio(struct mapped_device *md)
+static struct dm_target_io *alloc_tio(struct mapped_device *md)
 {
        return mempool_alloc(md->tio_pool, GFP_NOIO);
 }
 
-static inline void free_tio(struct mapped_device *md, struct target_io *tio)
+static void free_tio(struct mapped_device *md, struct dm_target_io *tio)
 {
        mempool_free(tio, md->tio_pool);
 }
@@ -498,7 +494,7 @@ static void dec_pending(struct dm_io *io, int error)
 static int clone_endio(struct bio *bio, unsigned int done, int error)
 {
        int r = 0;
-       struct target_io *tio = bio->bi_private;
+       struct dm_target_io *tio = bio->bi_private;
        struct mapped_device *md = tio->io->md;
        dm_endio_fn endio = tio->ti->type->end_io;
 
@@ -558,7 +554,7 @@ static sector_t max_io_len(struct mapped_device *md,
 }
 
 static void __map_bio(struct dm_target *ti, struct bio *clone,
-                     struct target_io *tio)
+                     struct dm_target_io *tio)
 {
        int r;
        sector_t sector;
@@ -672,7 +668,7 @@ static void __clone_and_map(struct clone_info *ci)
        struct bio *clone, *bio = ci->bio;
        struct dm_target *ti = dm_table_find_target(ci->map, ci->sector);
        sector_t len = 0, max = max_io_len(ci->md, ci->sector, ti);
-       struct target_io *tio;
+       struct dm_target_io *tio;
 
        /*
         * Allocate a target io object.
@@ -796,12 +792,21 @@ static void __split_bio(struct mapped_device *md, struct bio *bio)
  * The request function that just remaps the bio built up by
  * dm_merge_bvec.
  */
-static int dm_request(request_queue_t *q, struct bio *bio)
+static int dm_request(struct request_queue *q, struct bio *bio)
 {
        int r;
        int rw = bio_data_dir(bio);
        struct mapped_device *md = q->queuedata;
 
+       /*
+        * There is no use in forwarding any barrier request since we can't
+        * guarantee it is (or can be) handled by the targets correctly.
+        */
+       if (unlikely(bio_barrier(bio))) {
+               bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+               return 0;
+       }
+
        down_read(&md->io_lock);
 
        disk_stat_inc(dm_disk(md), ios[rw]);
@@ -839,7 +844,7 @@ static int dm_request(request_queue_t *q, struct bio *bio)
        return 0;
 }
 
-static int dm_flush_all(request_queue_t *q, struct gendisk *disk,
+static int dm_flush_all(struct request_queue *q, struct gendisk *disk,
                        sector_t *error_sector)
 {
        struct mapped_device *md = q->queuedata;
@@ -854,7 +859,7 @@ static int dm_flush_all(request_queue_t *q, struct gendisk *disk,
        return ret;
 }
 
-static void dm_unplug_all(request_queue_t *q)
+static void dm_unplug_all(struct request_queue *q)
 {
        struct mapped_device *md = q->queuedata;
        struct dm_table *map = dm_get_table(md);
@@ -1012,7 +1017,7 @@ static struct mapped_device *alloc_dev(int minor)
        if (!md->tio_pool)
                goto bad3;
 
-       md->bs = bioset_create(16, 16, 4);
+       md->bs = bioset_create(16, 16);
        if (!md->bs)
                goto bad_no_bioset;
 
@@ -1105,7 +1110,7 @@ static void __set_size(struct mapped_device *md, sector_t size)
 
 static int __bind(struct mapped_device *md, struct dm_table *t)
 {
-       request_queue_t *q = md->queue;
+       struct request_queue *q = md->queue;
        sector_t size;
 
        size = dm_table_get_size(t);
@@ -1116,7 +1121,8 @@ static int __bind(struct mapped_device *md, struct dm_table *t)
        if (size != get_capacity(md->disk))
                memset(&md->geometry, 0, sizeof(md->geometry));
 
-       __set_size(md, size);
+       if (md->suspended_bdev)
+               __set_size(md, size);
        if (size == 0)
                return 0;
 
@@ -1235,6 +1241,7 @@ void dm_put(struct mapped_device *md)
                free_dev(md);
        }
 }
+EXPORT_SYMBOL_GPL(dm_put);
 
 /*
  * Process the deferred bios
@@ -1264,6 +1271,11 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *table)
        if (!dm_suspended(md))
                goto out;
 
+       /* without bdev, the device size cannot be changed */
+       if (!md->suspended_bdev)
+               if (get_capacity(md->disk) != dm_table_get_size(table))
+                       goto out;
+
        __unbind(md);
        r = __bind(md, table);
 
@@ -1341,11 +1353,14 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
        /* This does not get reverted if there's an error later. */
        dm_table_presuspend_targets(map);
 
-       md->suspended_bdev = bdget_disk(md->disk, 0);
-       if (!md->suspended_bdev) {
-               DMWARN("bdget failed in dm_suspend");
-               r = -ENOMEM;
-               goto flush_and_out;
+       /* bdget() can stall if the pending I/Os are not flushed */
+       if (!noflush) {
+               md->suspended_bdev = bdget_disk(md->disk, 0);
+               if (!md->suspended_bdev) {
+                       DMWARN("bdget failed in dm_suspend");
+                       r = -ENOMEM;
+                       goto flush_and_out;
+               }
        }
 
        /*
@@ -1473,8 +1488,10 @@ int dm_resume(struct mapped_device *md)
 
        unlock_fs(md);
 
-       bdput(md->suspended_bdev);
-       md->suspended_bdev = NULL;
+       if (md->suspended_bdev) {
+               bdput(md->suspended_bdev);
+               md->suspended_bdev = NULL;
+       }
 
        clear_bit(DMF_SUSPENDED, &md->flags);