Commit cf222b37 authored by Alasdair G Kergon's avatar Alasdair G Kergon Committed by Linus Torvalds

[PATCH] device-mapper: fix deadlocks in core (prep)

Some code tidy-ups in preparation for the next patches.  Change
dm_table_pre/postsuspend_targets to accept NULL.  Use dm_suspended()
throughout.
Signed-Off-By: default avatarAlasdair G Kergon <agk@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 8c56ac3f
...@@ -869,11 +869,17 @@ static void suspend_targets(struct dm_table *t, unsigned postsuspend) ...@@ -869,11 +869,17 @@ static void suspend_targets(struct dm_table *t, unsigned postsuspend)
void dm_table_presuspend_targets(struct dm_table *t) void dm_table_presuspend_targets(struct dm_table *t)
{ {
if (!t)
return;
return suspend_targets(t, 0); return suspend_targets(t, 0);
} }
void dm_table_postsuspend_targets(struct dm_table *t) void dm_table_postsuspend_targets(struct dm_table *t)
{ {
if (!t)
return;
return suspend_targets(t, 1); return suspend_targets(t, 1);
} }
......
...@@ -610,7 +610,7 @@ static int dm_flush_all(request_queue_t *q, struct gendisk *disk, ...@@ -610,7 +610,7 @@ static int dm_flush_all(request_queue_t *q, struct gendisk *disk,
int ret = -ENXIO; int ret = -ENXIO;
if (map) { if (map) {
ret = dm_table_flush_all(md->map); ret = dm_table_flush_all(map);
dm_table_put(map); dm_table_put(map);
} }
...@@ -854,7 +854,7 @@ static int __bind(struct mapped_device *md, struct dm_table *t) ...@@ -854,7 +854,7 @@ static int __bind(struct mapped_device *md, struct dm_table *t)
write_unlock(&md->map_lock); write_unlock(&md->map_lock);
dm_table_get(t); dm_table_get(t);
dm_table_event_callback(md->map, event_callback, md); dm_table_event_callback(t, event_callback, md);
dm_table_set_restrictions(t, q); dm_table_set_restrictions(t, q);
return 0; return 0;
} }
...@@ -935,7 +935,7 @@ void dm_put(struct mapped_device *md) ...@@ -935,7 +935,7 @@ void dm_put(struct mapped_device *md)
struct dm_table *map = dm_get_table(md); struct dm_table *map = dm_get_table(md);
if (atomic_dec_and_test(&md->holders)) { if (atomic_dec_and_test(&md->holders)) {
if (!test_bit(DMF_SUSPENDED, &md->flags) && map) { if (!dm_suspended(md)) {
dm_table_presuspend_targets(map); dm_table_presuspend_targets(map);
dm_table_postsuspend_targets(map); dm_table_postsuspend_targets(map);
} }
...@@ -971,7 +971,7 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *table) ...@@ -971,7 +971,7 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *table)
down_write(&md->lock); down_write(&md->lock);
/* device must be suspended */ /* device must be suspended */
if (!test_bit(DMF_SUSPENDED, &md->flags)) if (!dm_suspended(md))
goto out; goto out;
__unbind(md); __unbind(md);
...@@ -988,7 +988,7 @@ out: ...@@ -988,7 +988,7 @@ out:
*/ */
static int __lock_fs(struct mapped_device *md) static int __lock_fs(struct mapped_device *md)
{ {
int error = -ENOMEM; int r = -ENOMEM;
if (test_and_set_bit(DMF_FS_LOCKED, &md->flags)) if (test_and_set_bit(DMF_FS_LOCKED, &md->flags))
return 0; return 0;
...@@ -1003,7 +1003,7 @@ static int __lock_fs(struct mapped_device *md) ...@@ -1003,7 +1003,7 @@ static int __lock_fs(struct mapped_device *md)
md->frozen_sb = freeze_bdev(md->frozen_bdev); md->frozen_sb = freeze_bdev(md->frozen_bdev);
if (IS_ERR(md->frozen_sb)) { if (IS_ERR(md->frozen_sb)) {
error = PTR_ERR(md->frozen_sb); r = PTR_ERR(md->frozen_sb);
goto out_bdput; goto out_bdput;
} }
...@@ -1019,7 +1019,7 @@ out_bdput: ...@@ -1019,7 +1019,7 @@ out_bdput:
md->frozen_bdev = NULL; md->frozen_bdev = NULL;
out: out:
clear_bit(DMF_FS_LOCKED, &md->flags); clear_bit(DMF_FS_LOCKED, &md->flags);
return error; return r;
} }
static void __unlock_fs(struct mapped_device *md) static void __unlock_fs(struct mapped_device *md)
...@@ -1045,20 +1045,20 @@ int dm_suspend(struct mapped_device *md) ...@@ -1045,20 +1045,20 @@ int dm_suspend(struct mapped_device *md)
{ {
struct dm_table *map; struct dm_table *map;
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
int error = -EINVAL; int r = -EINVAL;
/* Flush I/O to the device. */
down_read(&md->lock); down_read(&md->lock);
if (test_bit(DMF_BLOCK_IO, &md->flags)) if (test_bit(DMF_BLOCK_IO, &md->flags))
goto out_read_unlock; goto out_read_unlock;
map = dm_get_table(md); map = dm_get_table(md);
if (map)
/* This does not get reverted if there's an error later. */
dm_table_presuspend_targets(map);
error = __lock_fs(md); /* This does not get reverted if there's an error later. */
if (error) { dm_table_presuspend_targets(map);
/* Flush I/O to the device. */
r = __lock_fs(md);
if (r) {
dm_table_put(map); dm_table_put(map);
goto out_read_unlock; goto out_read_unlock;
} }
...@@ -1071,7 +1071,7 @@ int dm_suspend(struct mapped_device *md) ...@@ -1071,7 +1071,7 @@ int dm_suspend(struct mapped_device *md)
* If the flag is already set we know another thread is trying to * 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. * suspend as well, so we leave the fs locked for this thread.
*/ */
error = -EINVAL; r = -EINVAL;
down_write(&md->lock); down_write(&md->lock);
if (test_and_set_bit(DMF_BLOCK_IO, &md->flags)) { if (test_and_set_bit(DMF_BLOCK_IO, &md->flags)) {
if (map) if (map)
...@@ -1106,15 +1106,14 @@ int dm_suspend(struct mapped_device *md) ...@@ -1106,15 +1106,14 @@ int dm_suspend(struct mapped_device *md)
remove_wait_queue(&md->wait, &wait); remove_wait_queue(&md->wait, &wait);
/* were we interrupted ? */ /* were we interrupted ? */
error = -EINTR; r = -EINTR;
if (atomic_read(&md->pending)) if (atomic_read(&md->pending))
goto out_unfreeze; goto out_unfreeze;
set_bit(DMF_SUSPENDED, &md->flags); set_bit(DMF_SUSPENDED, &md->flags);
map = dm_get_table(md); map = dm_get_table(md);
if (map) dm_table_postsuspend_targets(map);
dm_table_postsuspend_targets(map);
dm_table_put(map); dm_table_put(map);
up_write(&md->lock); up_write(&md->lock);
...@@ -1125,25 +1124,29 @@ out_unfreeze: ...@@ -1125,25 +1124,29 @@ out_unfreeze:
clear_bit(DMF_BLOCK_IO, &md->flags); clear_bit(DMF_BLOCK_IO, &md->flags);
out_write_unlock: out_write_unlock:
up_write(&md->lock); up_write(&md->lock);
return error; return r;
out_read_unlock: out_read_unlock:
up_read(&md->lock); up_read(&md->lock);
return error; return r;
} }
int dm_resume(struct mapped_device *md) int dm_resume(struct mapped_device *md)
{ {
int r = -EINVAL;
struct bio *def; struct bio *def;
struct dm_table *map = dm_get_table(md); struct dm_table *map = NULL;
down_write(&md->lock); down_write(&md->lock);
if (!map || if (!dm_suspended(md)) {
!test_bit(DMF_SUSPENDED, &md->flags) ||
!dm_table_get_size(map)) {
up_write(&md->lock); up_write(&md->lock);
dm_table_put(map); goto out;
return -EINVAL; }
map = dm_get_table(md);
if (!map || !dm_table_get_size(map)) {
up_write(&md->lock);
goto out;
} }
dm_table_resume_targets(map); dm_table_resume_targets(map);
...@@ -1155,9 +1158,11 @@ int dm_resume(struct mapped_device *md) ...@@ -1155,9 +1158,11 @@ int dm_resume(struct mapped_device *md)
up_write(&md->lock); up_write(&md->lock);
__unlock_fs(md); __unlock_fs(md);
dm_table_unplug_all(map); dm_table_unplug_all(map);
dm_table_put(map);
return 0; r = 0;
out:
dm_table_put(map);
return r;
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment