Commit 02e352287a40bd456eb78df705bf888bc3161d3f
Committed by
Jens Axboe
1 parent
bf2253a6f0
Exists in
master
and in
39 other branches
block: rescan partitions on invalidated devices on -ENOMEDIA too
__blkdev_get() doesn't rescan partitions if disk->fops->open() fails, which leads to ghost partition devices lingering after medimum removal is known to both the kernel and userland. The behavior also creates a subtle inconsistency where O_NONBLOCK open, which doesn't fail even if there's no medium, clears the ghots partitions, which is exploited to work around the problem from userland. Fix it by updating __blkdev_get() to issue partition rescan after -ENOMEDIA too. This was reported in the following bz. https://bugzilla.kernel.org/show_bug.cgi?id=13029 Stable: 2.6.38 Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: David Zeuthen <zeuthen@gmail.com> Reported-by: Martin Pitt <martin.pitt@ubuntu.com> Reported-by: Kay Sievers <kay.sievers@vrfy.org> Tested-by: Kay Sievers <kay.sievers@vrfy.org> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Cc: stable@kernel.org Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Showing 1 changed file with 18 additions and 9 deletions Side-by-side Diff
fs/block_dev.c
... | ... | @@ -1102,6 +1102,7 @@ |
1102 | 1102 | if (!bdev->bd_part) |
1103 | 1103 | goto out_clear; |
1104 | 1104 | |
1105 | + ret = 0; | |
1105 | 1106 | if (disk->fops->open) { |
1106 | 1107 | ret = disk->fops->open(bdev, mode); |
1107 | 1108 | if (ret == -ERESTARTSYS) { |
1108 | 1109 | |
... | ... | @@ -1118,9 +1119,18 @@ |
1118 | 1119 | put_disk(disk); |
1119 | 1120 | goto restart; |
1120 | 1121 | } |
1121 | - if (ret) | |
1122 | - goto out_clear; | |
1123 | 1122 | } |
1123 | + /* | |
1124 | + * If the device is invalidated, rescan partition | |
1125 | + * if open succeeded or failed with -ENOMEDIUM. | |
1126 | + * The latter is necessary to prevent ghost | |
1127 | + * partitions on a removed medium. | |
1128 | + */ | |
1129 | + if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM)) | |
1130 | + rescan_partitions(disk, bdev); | |
1131 | + if (ret) | |
1132 | + goto out_clear; | |
1133 | + | |
1124 | 1134 | if (!bdev->bd_openers) { |
1125 | 1135 | bd_set_size(bdev,(loff_t)get_capacity(disk)<<9); |
1126 | 1136 | bdi = blk_get_backing_dev_info(bdev); |
... | ... | @@ -1128,8 +1138,6 @@ |
1128 | 1138 | bdi = &default_backing_dev_info; |
1129 | 1139 | bdev_inode_switch_bdi(bdev->bd_inode, bdi); |
1130 | 1140 | } |
1131 | - if (bdev->bd_invalidated) | |
1132 | - rescan_partitions(disk, bdev); | |
1133 | 1141 | } else { |
1134 | 1142 | struct block_device *whole; |
1135 | 1143 | whole = bdget_disk(disk, 0); |
1136 | 1144 | |
1137 | 1145 | |
... | ... | @@ -1153,13 +1161,14 @@ |
1153 | 1161 | } |
1154 | 1162 | } else { |
1155 | 1163 | if (bdev->bd_contains == bdev) { |
1156 | - if (bdev->bd_disk->fops->open) { | |
1164 | + ret = 0; | |
1165 | + if (bdev->bd_disk->fops->open) | |
1157 | 1166 | ret = bdev->bd_disk->fops->open(bdev, mode); |
1158 | - if (ret) | |
1159 | - goto out_unlock_bdev; | |
1160 | - } | |
1161 | - if (bdev->bd_invalidated) | |
1167 | + /* the same as first opener case, read comment there */ | |
1168 | + if (bdev->bd_invalidated && (!ret || ret == -ENOMEDIUM)) | |
1162 | 1169 | rescan_partitions(bdev->bd_disk, bdev); |
1170 | + if (ret) | |
1171 | + goto out_unlock_bdev; | |
1163 | 1172 | } |
1164 | 1173 | /* only one opener holds refs to the module and disk */ |
1165 | 1174 | module_put(disk->fops->owner); |