diff options
author | Hannes Reinecke <hare@suse.de> | 2013-07-10 18:41:15 -0400 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2013-07-10 18:41:15 -0400 |
commit | 6c182cd88d179cbbd06f4f8a8a19b6977940753f (patch) | |
tree | 27971aeafbdd2410699e77477565157c67d8ffea /drivers/md/dm.c | |
parent | 8bb495e3f02401ee6f76d1b1d77f3ac9f079e376 (diff) |
dm mpath: fix ioctl deadlock when no paths
When multipath needs to retry an ioctl the reference to the
current live table needs to be dropped. Otherwise a deadlock
occurs when all paths are down:
- dm_blk_ioctl takes a reference to the current table
and spins in multipath_ioctl().
- A new table is being loaded, but upon resume the process
hangs in dm_table_destroy() waiting for references to
drop to zero.
With this patch the reference to the old table is dropped
prior to retry, thereby avoiding the deadlock.
Signed-off-by: Hannes Reinecke <hare@suse.de>
Cc: Mike Snitzer <snitzer@redhat.com>
Cc: stable@vger.kernel.org
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md/dm.c')
-rw-r--r-- | drivers/md/dm.c | 9 |
1 files changed, 8 insertions, 1 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index d5370a94b2c1..33f20103d8d5 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -386,10 +386,12 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, | |||
386 | unsigned int cmd, unsigned long arg) | 386 | unsigned int cmd, unsigned long arg) |
387 | { | 387 | { |
388 | struct mapped_device *md = bdev->bd_disk->private_data; | 388 | struct mapped_device *md = bdev->bd_disk->private_data; |
389 | struct dm_table *map = dm_get_live_table(md); | 389 | struct dm_table *map; |
390 | struct dm_target *tgt; | 390 | struct dm_target *tgt; |
391 | int r = -ENOTTY; | 391 | int r = -ENOTTY; |
392 | 392 | ||
393 | retry: | ||
394 | map = dm_get_live_table(md); | ||
393 | if (!map || !dm_table_get_size(map)) | 395 | if (!map || !dm_table_get_size(map)) |
394 | goto out; | 396 | goto out; |
395 | 397 | ||
@@ -410,6 +412,11 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, | |||
410 | out: | 412 | out: |
411 | dm_table_put(map); | 413 | dm_table_put(map); |
412 | 414 | ||
415 | if (r == -ENOTCONN) { | ||
416 | msleep(10); | ||
417 | goto retry; | ||
418 | } | ||
419 | |||
413 | return r; | 420 | return r; |
414 | } | 421 | } |
415 | 422 | ||