aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/xen-blkfront.c
diff options
context:
space:
mode:
authorDaniel Stodden <daniel.stodden@citrix.com>2010-08-07 12:45:12 -0400
committerJens Axboe <jaxboe@fusionio.com>2010-08-07 12:45:12 -0400
commit7fd152f4b6ae4f3cf89e4b7a0383cc3c470772fc (patch)
tree105d00acbdd635aa30f0a0f8257714d5cbb6699e /drivers/block/xen-blkfront.c
parent139617437aff1f0d3b57c2d7cc60e60efc8fe6c3 (diff)
blkfront: Fix blkfront backend switch race (bdev release)
We cannot read backend state within bdev operations, because it risks grabbing the state change before xenbus gets to do it. Fixed by tracking deferral with a frontend switch to Closing. State exposure isn't strictly necessary, but the backends won't mind. For a 'clean' deferral this seems actually a more decent protocol than raising errors. Signed-off-by: Daniel Stodden <daniel.stodden@citrix.com> Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Diffstat (limited to 'drivers/block/xen-blkfront.c')
-rw-r--r--drivers/block/xen-blkfront.c49
1 files changed, 33 insertions, 16 deletions
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 763a315712cc..49862993f31e 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -1142,31 +1142,48 @@ static int blkif_open(struct block_device *bdev, fmode_t mode)
1142 if (!err) 1142 if (!err)
1143 ++info->users; 1143 ++info->users;
1144 1144
1145 unlock_kernel();
1146out: 1145out:
1146 unlock_kernel();
1147 return err; 1147 return err;
1148} 1148}
1149 1149
1150static int blkif_release(struct gendisk *disk, fmode_t mode) 1150static int blkif_release(struct gendisk *disk, fmode_t mode)
1151{ 1151{
1152 struct blkfront_info *info = disk->private_data; 1152 struct blkfront_info *info = disk->private_data;
1153 struct block_device *bdev;
1154 struct xenbus_device *xbdev;
1155
1153 lock_kernel(); 1156 lock_kernel();
1154 info->users--; 1157 if (--info->users)
1155 if (info->users == 0) { 1158 goto out;
1156 /* Check whether we have been instructed to close. We will 1159
1157 have ignored this request initially, as the device was 1160 bdev = bdget_disk(disk, 0);
1158 still mounted. */ 1161 bdput(bdev);
1159 struct xenbus_device *dev = info->xbdev; 1162
1160 1163 /*
1161 if (!dev) { 1164 * Check if we have been instructed to close. We will have
1162 xlvbd_release_gendisk(info); 1165 * deferred this request, because the bdev was still open.
1163 kfree(info); 1166 */
1164 } else if (xenbus_read_driver_state(dev->otherend) 1167
1165 == XenbusStateClosing && info->is_ready) { 1168 mutex_lock(&info->mutex);
1166 xlvbd_release_gendisk(info); 1169 xbdev = info->xbdev;
1167 xenbus_frontend_closed(dev); 1170
1168 } 1171 if (xbdev && xbdev->state == XenbusStateClosing) {
1172 /* pending switch to state closed */
1173 xlvbd_release_gendisk(info);
1174 xenbus_frontend_closed(info->xbdev);
1175 }
1176
1177 mutex_unlock(&info->mutex);
1178
1179 if (!xbdev) {
1180 /* sudden device removal */
1181 xlvbd_release_gendisk(info);
1182 disk->private_data = NULL;
1183 kfree(info);
1169 } 1184 }
1185
1186out:
1170 unlock_kernel(); 1187 unlock_kernel();
1171 return 0; 1188 return 0;
1172} 1189}