mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 11:19:37 +00:00
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>
This commit is contained in:
parent
8bb495e3f0
commit
6c182cd88d
2 changed files with 10 additions and 7 deletions
|
@ -1561,7 +1561,6 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
|
|||
unsigned long flags;
|
||||
int r;
|
||||
|
||||
again:
|
||||
bdev = NULL;
|
||||
mode = 0;
|
||||
r = 0;
|
||||
|
@ -1579,7 +1578,7 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
|
|||
}
|
||||
|
||||
if ((pgpath && m->queue_io) || (!pgpath && m->queue_if_no_path))
|
||||
r = -EAGAIN;
|
||||
r = -ENOTCONN;
|
||||
else if (!bdev)
|
||||
r = -EIO;
|
||||
|
||||
|
@ -1591,11 +1590,8 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
|
|||
if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
|
||||
r = scsi_verify_blk_ioctl(NULL, cmd);
|
||||
|
||||
if (r == -EAGAIN && !fatal_signal_pending(current)) {
|
||||
if (r == -ENOTCONN && !fatal_signal_pending(current))
|
||||
queue_work(kmultipathd, &m->process_queued_ios);
|
||||
msleep(10);
|
||||
goto again;
|
||||
}
|
||||
|
||||
return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
||||
}
|
||||
|
|
|
@ -386,10 +386,12 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
|
|||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct mapped_device *md = bdev->bd_disk->private_data;
|
||||
struct dm_table *map = dm_get_live_table(md);
|
||||
struct dm_table *map;
|
||||
struct dm_target *tgt;
|
||||
int r = -ENOTTY;
|
||||
|
||||
retry:
|
||||
map = dm_get_live_table(md);
|
||||
if (!map || !dm_table_get_size(map))
|
||||
goto out;
|
||||
|
||||
|
@ -410,6 +412,11 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
|
|||
out:
|
||||
dm_table_put(map);
|
||||
|
||||
if (r == -ENOTCONN) {
|
||||
msleep(10);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue