Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

block: Don't check events while open is in progress

Not all block drivers clear events immediately after reporting. Some
do so in ->revalidate_disk() or other steps during ->open(). There is
a slim chance event poll may happen between the clearing event check
from check_disk_change() and the actual clearing of the events which
would result in spurious events.

Block event checks while block device open is in progress. There is
no need to kick explicit event check afterwards as events are always
checked during open.

-v2: The original patch could have called disk_unblock_events() with
an already released or %NULL @disk causing oops. Fixed by making
sure references are put after disk_unblock_events() is called.
It also makes the error path of __blkdev_get() a bit simpler.
This problem was reported by Jens.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Kay Sievers <kay.sievers@vrfy.org>

Tejun Heo 69e02c59 6936217c

+10 -7
+10 -7
fs/block_dev.c
··· 1087 1087 if (!disk) 1088 1088 goto out; 1089 1089 1090 + disk_block_events(disk); 1090 1091 mutex_lock_nested(&bdev->bd_mutex, for_part); 1091 1092 if (!bdev->bd_openers) { 1092 1093 bdev->bd_disk = disk; ··· 1109 1108 */ 1110 1109 disk_put_part(bdev->bd_part); 1111 1110 bdev->bd_part = NULL; 1112 - module_put(disk->fops->owner); 1113 - put_disk(disk); 1114 1111 bdev->bd_disk = NULL; 1115 1112 mutex_unlock(&bdev->bd_mutex); 1113 + disk_unblock_events(disk); 1114 + module_put(disk->fops->owner); 1115 + put_disk(disk); 1116 1116 goto restart; 1117 1117 } 1118 1118 if (ret) ··· 1150 1148 bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9); 1151 1149 } 1152 1150 } else { 1153 - module_put(disk->fops->owner); 1154 - put_disk(disk); 1155 - disk = NULL; 1156 1151 if (bdev->bd_contains == bdev) { 1157 1152 if (bdev->bd_disk->fops->open) { 1158 1153 ret = bdev->bd_disk->fops->open(bdev, mode); ··· 1159 1160 if (bdev->bd_invalidated) 1160 1161 rescan_partitions(bdev->bd_disk, bdev); 1161 1162 } 1163 + /* only one opener holds refs to the module and disk */ 1164 + module_put(disk->fops->owner); 1165 + put_disk(disk); 1162 1166 } 1163 1167 bdev->bd_openers++; 1164 1168 if (for_part) 1165 1169 bdev->bd_part_count++; 1166 1170 mutex_unlock(&bdev->bd_mutex); 1171 + disk_unblock_events(disk); 1167 1172 return 0; 1168 1173 1169 1174 out_clear: ··· 1180 1177 bdev->bd_contains = NULL; 1181 1178 out_unlock_bdev: 1182 1179 mutex_unlock(&bdev->bd_mutex); 1180 + disk_unblock_events(disk); 1183 1181 out: 1184 - if (disk) 1185 - module_put(disk->fops->owner); 1182 + module_put(disk->fops->owner); 1186 1183 put_disk(disk); 1187 1184 bdput(bdev); 1188 1185