aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2013-07-10 18:41:15 -0400
committerAlasdair G Kergon <agk@redhat.com>2013-07-10 18:41:15 -0400
commit6c182cd88d179cbbd06f4f8a8a19b6977940753f (patch)
tree27971aeafbdd2410699e77477565157c67d8ffea /drivers/md
parent8bb495e3f02401ee6f76d1b1d77f3ac9f079e376 (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')
-rw-r--r--drivers/md/dm-mpath.c8
-rw-r--r--drivers/md/dm.c9
2 files changed, 10 insertions, 7 deletions
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index bdf26f5bd326..5adede17ddf6 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1561,7 +1561,6 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
1561 unsigned long flags; 1561 unsigned long flags;
1562 int r; 1562 int r;
1563 1563
1564again:
1565 bdev = NULL; 1564 bdev = NULL;
1566 mode = 0; 1565 mode = 0;
1567 r = 0; 1566 r = 0;
@@ -1579,7 +1578,7 @@ again:
1579 } 1578 }
1580 1579
1581 if ((pgpath && m->queue_io) || (!pgpath && m->queue_if_no_path)) 1580 if ((pgpath && m->queue_io) || (!pgpath && m->queue_if_no_path))
1582 r = -EAGAIN; 1581 r = -ENOTCONN;
1583 else if (!bdev) 1582 else if (!bdev)
1584 r = -EIO; 1583 r = -EIO;
1585 1584
@@ -1591,11 +1590,8 @@ again:
1591 if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) 1590 if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
1592 r = scsi_verify_blk_ioctl(NULL, cmd); 1591 r = scsi_verify_blk_ioctl(NULL, cmd);
1593 1592
1594 if (r == -EAGAIN && !fatal_signal_pending(current)) { 1593 if (r == -ENOTCONN && !fatal_signal_pending(current))
1595 queue_work(kmultipathd, &m->process_queued_ios); 1594 queue_work(kmultipathd, &m->process_queued_ios);
1596 msleep(10);
1597 goto again;
1598 }
1599 1595
1600 return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg); 1596 return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
1601} 1597}
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
393retry:
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,
410out: 412out:
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