summaryrefslogtreecommitdiffstats
path: root/drivers/md/dm-table.c
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2021-01-21 18:50:56 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-01-27 11:05:35 +0100
commit97c5846e04532a0651da7016b4d35862993ea56d (patch)
tree1311be0a725bb5ddb0d6e7bb669b064d54ef14ee /drivers/md/dm-table.c
parentbcf374506f46795d85cd9183f00b43af9d44c7db (diff)
downloadlinux-stable-97c5846e04532a0651da7016b4d35862993ea56d.tar.gz
linux-stable-97c5846e04532a0651da7016b4d35862993ea56d.tar.bz2
linux-stable-97c5846e04532a0651da7016b4d35862993ea56d.zip
dm: avoid filesystem lookup in dm_get_dev_t()
commit 809b1e4945774c9ec5619a8f4e2189b7b3833c0c upstream. This reverts commit 644bda6f3460 ("dm table: fall back to getting device using name_to_dev_t()") dm_get_dev_t() is just used to convert an arbitrary 'path' string into a dev_t. It doesn't presume that the device is present; that check will be done later, as the only caller is dm_get_device(), which does a dm_get_table_device() later on, which will properly open the device. So if the path string already _is_ in major:minor representation we can convert it directly, avoiding a recursion into the filesystem to lookup the block device. This avoids a hang in multipath_message() when the filesystem is inaccessible. Fixes: 644bda6f3460 ("dm table: fall back to getting device using name_to_dev_t()") Cc: stable@vger.kernel.org Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Martin Wilck <mwilck@suse.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Mike Snitzer <snitzer@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/md/dm-table.c')
-rw-r--r--drivers/md/dm-table.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index f849db3035a0..916433742485 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -431,14 +431,23 @@ int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
{
int r;
dev_t dev;
+ unsigned int major, minor;
+ char dummy;
struct dm_dev_internal *dd;
struct dm_table *t = ti->table;
BUG_ON(!t);
- dev = dm_get_dev_t(path);
- if (!dev)
- return -ENODEV;
+ if (sscanf(path, "%u:%u%c", &major, &minor, &dummy) == 2) {
+ /* Extract the major/minor numbers */
+ dev = MKDEV(major, minor);
+ if (MAJOR(dev) != major || MINOR(dev) != minor)
+ return -EOVERFLOW;
+ } else {
+ dev = dm_get_dev_t(path);
+ if (!dev)
+ return -ENODEV;
+ }
dd = find_device(&t->devices, dev);
if (!dd) {