From f9760b158f610b1792a222cc924073724c061bfb Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 7 Apr 2021 22:37:57 +0100 Subject: [PATCH 1/2] mtd: super: don't reply on mtdblock device minor To: linux-mtd@lists.infradead.org Cc: Vignesh Raghavendra , Richard Weinberger , Miquel Raynal , David Woodhouse For blktrans devices with partitions (ie. part_bits != 0) the assumption that the minor number of the mtdblock device matches the mtdnum doesn't hold true. Properly resolve mtd device from blktrans layer instead. Signed-off-by: Daniel Golle --- drivers/mtd/mtdsuper.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -121,7 +122,8 @@ int get_tree_mtd(struct fs_context *fc, { #ifdef CONFIG_BLOCK struct block_device *bdev; - int ret, major; + struct mtd_blktrans_dev *blktrans_dev; + int ret, major, part_bits; #endif int mtdnr; @@ -169,21 +171,38 @@ int get_tree_mtd(struct fs_context *fc, /* try the old way - the hack where we allowed users to mount * /dev/mtdblock$(n) but didn't actually _use_ the blockdev */ - bdev = lookup_bdev(fc->source); + bdev = blkdev_get_by_path(fc->source, FMODE_READ, NULL); if (IS_ERR(bdev)) { ret = PTR_ERR(bdev); errorf(fc, "MTD: Couldn't look up '%s': %d", fc->source, ret); return ret; } - pr_debug("MTDSB: lookup_bdev() returned 0\n"); + pr_debug("MTDSB: blkdev_get_by_path() returned 0\n"); major = MAJOR(bdev->bd_dev); - mtdnr = MINOR(bdev->bd_dev); - bdput(bdev); - if (major == MTD_BLOCK_MAJOR) - return mtd_get_sb_by_nr(fc, mtdnr, fill_super); + if (major == MTD_BLOCK_MAJOR) { + if (!bdev->bd_disk) { + blkdev_put(bdev, FMODE_READ); + BUG(); + return -EINVAL; + } + + blktrans_dev = (struct mtd_blktrans_dev *)(bdev->bd_disk->private_data); + if (!blktrans_dev || !blktrans_dev->tr) { + blkdev_put(bdev, FMODE_READ); + BUG(); + return -EINVAL; + } + mtdnr = blktrans_dev->devnum; + part_bits = blktrans_dev->tr->part_bits; + blkdev_put(bdev, FMODE_READ); + if (MINOR(bdev->bd_dev) != (mtdnr << part_bits)) + return -EINVAL; + return mtd_get_sb_by_nr(fc, mtdnr, fill_super); + } + blkdev_put(bdev, FMODE_READ); #endif /* CONFIG_BLOCK */ if (!(fc->sb_flags & SB_SILENT))