[TG3]: Update driver version and reldate.
[powerpc.git] / drivers / md / dm.c
index 9687a08..54fabbf 100644 (file)
@@ -384,7 +384,7 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
                /* error the io and bail out */
                struct dm_io *io = tio->io;
                free_tio(tio->io->md, tio);
-               dec_pending(io, -EIO);
+               dec_pending(io, r);
                bio_put(clone);
        }
 }
@@ -966,23 +966,20 @@ static void __flush_deferred_io(struct mapped_device *md, struct bio *c)
  */
 int dm_swap_table(struct mapped_device *md, struct dm_table *table)
 {
-       int r;
+       int r = -EINVAL;
 
        down_write(&md->lock);
 
        /* device must be suspended */
-       if (!test_bit(DMF_SUSPENDED, &md->flags)) {
-               up_write(&md->lock);
-               return -EPERM;
-       }
+       if (!test_bit(DMF_SUSPENDED, &md->flags))
+               goto out;
 
        __unbind(md);
        r = __bind(md, table);
-       if (r)
-               return r;
 
+out:
        up_write(&md->lock);
-       return 0;
+       return r;
 }
 
 /*
@@ -1048,37 +1045,40 @@ int dm_suspend(struct mapped_device *md)
 {
        struct dm_table *map;
        DECLARE_WAITQUEUE(wait, current);
+       int error = -EINVAL;
 
        /* Flush I/O to the device. */
        down_read(&md->lock);
-       if (test_bit(DMF_BLOCK_IO, &md->flags)) {
-               up_read(&md->lock);
-               return -EINVAL;
-       }
+       if (test_bit(DMF_BLOCK_IO, &md->flags))
+               goto out_read_unlock;
 
        map = dm_get_table(md);
        if (map)
+               /* This does not get reverted if there's an error later. */
                dm_table_presuspend_targets(map);
-       __lock_fs(md);
+
+       error = __lock_fs(md);
+       if (error) {
+               dm_table_put(map);
+               goto out_read_unlock;
+       }
 
        up_read(&md->lock);
 
        /*
-        * First we set the BLOCK_IO flag so no more ios will be
-        * mapped.
+        * First we set the BLOCK_IO flag so no more ios will be mapped.
+        *
+        * If the flag is already set we know another thread is trying to
+        * suspend as well, so we leave the fs locked for this thread.
         */
+       error = -EINVAL;
        down_write(&md->lock);
-       if (test_bit(DMF_BLOCK_IO, &md->flags)) {
-               /*
-                * If we get here we know another thread is
-                * trying to suspend as well, so we leave the fs
-                * locked for this thread.
-                */
-               up_write(&md->lock);
-               return -EINVAL;
+       if (test_and_set_bit(DMF_BLOCK_IO, &md->flags)) {
+               if (map)
+                       dm_table_put(map);
+               goto out_write_unlock;
        }
 
-       set_bit(DMF_BLOCK_IO, &md->flags);
        add_wait_queue(&md->wait, &wait);
        up_write(&md->lock);
 
@@ -1106,12 +1106,9 @@ int dm_suspend(struct mapped_device *md)
        remove_wait_queue(&md->wait, &wait);
 
        /* were we interrupted ? */
-       if (atomic_read(&md->pending)) {
-               __unlock_fs(md);
-               clear_bit(DMF_BLOCK_IO, &md->flags);
-               up_write(&md->lock);
-               return -EINTR;
-       }
+       error = -EINTR;
+       if (atomic_read(&md->pending))
+               goto out_unfreeze;
 
        set_bit(DMF_SUSPENDED, &md->flags);
 
@@ -1122,6 +1119,17 @@ int dm_suspend(struct mapped_device *md)
        up_write(&md->lock);
 
        return 0;
+
+out_unfreeze:
+       __unlock_fs(md);
+       clear_bit(DMF_BLOCK_IO, &md->flags);
+out_write_unlock:
+       up_write(&md->lock);
+       return error;
+
+out_read_unlock:
+       up_read(&md->lock);
+       return error;
 }
 
 int dm_resume(struct mapped_device *md)