diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 83f53a46c2d4..f6b03957efc7 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1048,20 +1048,16 @@ int dm_suspend(struct mapped_device *md) { struct dm_table *map; DECLARE_WAITQUEUE(wait, current); - int error; + 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; error = __lock_fs(md); - if (error) { - up_read(&md->lock); - return error; - } + if (error) + goto out_read_unlock; map = dm_get_table(md); if (map) @@ -1075,15 +1071,14 @@ int dm_suspend(struct mapped_device *md) * 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)) { - up_write(&md->lock); + if (test_and_set_bit(DMF_BLOCK_IO, &md->flags)) { if (map) dm_table_put(map); - return -EINVAL; + goto out_write_unlock; } - set_bit(DMF_BLOCK_IO, &md->flags); add_wait_queue(&md->wait, &wait); up_write(&md->lock); @@ -1111,13 +1106,9 @@ int dm_suspend(struct mapped_device *md) remove_wait_queue(&md->wait, &wait); /* were we interrupted ? */ - if (atomic_read(&md->pending)) { - /* FIXME Undo the presuspend_targets */ - __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); @@ -1128,6 +1119,18 @@ int dm_suspend(struct mapped_device *md) up_write(&md->lock); return 0; + +out_unfreeze: + /* FIXME Undo dm_table_presuspend_targets */ + __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)