]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/md/dm.c
dm raid1: handle resync failures
[linux-2.6-omap-h63xx.git] / drivers / md / dm.c
index fe7c56e104359ce95ce8b34143542535d030c78c..f4f7d35561ab83753f03fe16a186514514916bf6 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;
 }
 
@@ -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;
@@ -325,22 +323,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 +496,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 +556,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 +670,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.
@@ -802,6 +800,15 @@ static int dm_request(request_queue_t *q, struct bio *bio)
        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]);
@@ -1012,7 +1019,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;
 
@@ -1116,7 +1123,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 +1243,7 @@ void dm_put(struct mapped_device *md)
                free_dev(md);
        }
 }
+EXPORT_SYMBOL_GPL(dm_put);
 
 /*
  * Process the deferred bios
@@ -1264,6 +1273,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 +1355,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 +1490,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);