Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 89f97496 authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe
Browse files

block: fix __blkdev_get() for removable devices



Commit 0762b8bd moved disk_get_part()
in front of recursive get on the whole disk, which caused removable
devices to try disk_get_part() before rescanning after a new media is
inserted, which might fail legit open attempts or give the old
partition.

This patch fixes the problem by moving disk_get_part() after
__blkdev_get() on the whole disk.

This problem was spotted by Borislav Petkov.

Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Tested-by: default avatarBorislav Petkov <petkovbb@gmail.com>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 561920a0
Loading
Loading
Loading
Loading
+11 −12
Original line number Diff line number Diff line
@@ -986,7 +986,6 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part);
static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
{
	struct gendisk *disk;
	struct hd_struct *part = NULL;
	int ret;
	int partno;
	int perm = 0;
@@ -1004,24 +1003,25 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
		return ret;
	}

	ret = -ENXIO;

	lock_kernel();

	ret = -ENXIO;
	disk = get_gendisk(bdev->bd_dev, &partno);
	if (!disk)
		goto out_unlock_kernel;
	part = disk_get_part(disk, partno);
	if (!part)
		goto out_unlock_kernel;

	mutex_lock_nested(&bdev->bd_mutex, for_part);
	if (!bdev->bd_openers) {
		bdev->bd_disk = disk;
		bdev->bd_part = part;
		bdev->bd_contains = bdev;
		if (!partno) {
			struct backing_dev_info *bdi;

			ret = -ENXIO;
			bdev->bd_part = disk_get_part(disk, partno);
			if (!bdev->bd_part)
				goto out_clear;

			if (disk->fops->open) {
				ret = disk->fops->open(bdev, mode);
				if (ret)
@@ -1049,18 +1049,17 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
			bdev->bd_contains = whole;
			bdev->bd_inode->i_data.backing_dev_info =
			   whole->bd_inode->i_data.backing_dev_info;
			bdev->bd_part = disk_get_part(disk, partno);
			if (!(disk->flags & GENHD_FL_UP) ||
			    !part || !part->nr_sects) {
			    !bdev->bd_part || !bdev->bd_part->nr_sects) {
				ret = -ENXIO;
				goto out_clear;
			}
			bd_set_size(bdev, (loff_t)part->nr_sects << 9);
			bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9);
		}
	} else {
		disk_put_part(part);
		put_disk(disk);
		module_put(disk->fops->owner);
		part = NULL;
		disk = NULL;
		if (bdev->bd_contains == bdev) {
			if (bdev->bd_disk->fops->open) {
@@ -1080,6 +1079,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
	return 0;

 out_clear:
	disk_put_part(bdev->bd_part);
	bdev->bd_disk = NULL;
	bdev->bd_part = NULL;
	bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
@@ -1091,7 +1091,6 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
 out_unlock_kernel:
	unlock_kernel();

	disk_put_part(part);
	if (disk)
		module_put(disk->fops->owner);
	put_disk(disk);