diff options
Diffstat (limited to 'fs/block_dev.c')
| -rw-r--r-- | fs/block_dev.c | 28 | 
1 files changed, 19 insertions, 9 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 5147bdd3b8e..bf9c7a72037 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1102,6 +1102,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)  			if (!bdev->bd_part)  				goto out_clear; +			ret = 0;  			if (disk->fops->open) {  				ret = disk->fops->open(bdev, mode);  				if (ret == -ERESTARTSYS) { @@ -1118,18 +1119,26 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)  					put_disk(disk);  					goto restart;  				} -				if (ret) -					goto out_clear;  			} -			if (!bdev->bd_openers) { + +			if (!ret && !bdev->bd_openers) {  				bd_set_size(bdev,(loff_t)get_capacity(disk)<<9);  				bdi = blk_get_backing_dev_info(bdev);  				if (bdi == NULL)  					bdi = &default_backing_dev_info;  				bdev_inode_switch_bdi(bdev->bd_inode, bdi);  			} -			if (bdev->bd_invalidated) + +			/* +			 * If the device is invalidated, rescan partition +			 * if open succeeded or failed with -ENOMEDIUM. +			 * The latter is necessary to prevent ghost +			 * partitions on a removed medium. +			 */ +			if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))  				rescan_partitions(disk, bdev); +			if (ret) +				goto out_clear;  		} else {  			struct block_device *whole;  			whole = bdget_disk(disk, 0); @@ -1153,13 +1162,14 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)  		}  	} else {  		if (bdev->bd_contains == bdev) { -			if (bdev->bd_disk->fops->open) { +			ret = 0; +			if (bdev->bd_disk->fops->open)  				ret = bdev->bd_disk->fops->open(bdev, mode); -				if (ret) -					goto out_unlock_bdev; -			} -			if (bdev->bd_invalidated) +			/* the same as first opener case, read comment there */ +			if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM))  				rescan_partitions(bdev->bd_disk, bdev); +			if (ret) +				goto out_unlock_bdev;  		}  		/* only one opener holds refs to the module and disk */  		module_put(disk->fops->owner);  |