diff options
author | Daniel Stodden <daniel.stodden@citrix.com> | 2010-04-30 18:01:22 -0400 |
---|---|---|
committer | Jens Axboe <jaxboe@fusionio.com> | 2010-08-07 12:45:27 -0400 |
commit | fa1bd3591a669b92b635dbdb11d1a32a5630821b (patch) | |
tree | 41309de6425e854420b26bdcfd94accaf52c3cee /drivers/block/xen-blkfront.c | |
parent | 7fd152f4b6ae4f3cf89e4b7a0383cc3c470772fc (diff) |
blkfront: Lock blockfront_info during xbdev removal
Same approach as blkfront_closing:
* Grab the bdev safely, holding the info mutex.
* Zap xbdev safely, holding the info mutex.
* Try bdev removal safely, holding bd_mutex.
Signed-off-by: Daniel Stodden <daniel.stodden@citrix.com>
Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Diffstat (limited to 'drivers/block/xen-blkfront.c')
-rw-r--r-- | drivers/block/xen-blkfront.c | 41 |
1 files changed, 35 insertions, 6 deletions
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 49862993f31e..715de7d8ce01 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c | |||
@@ -1093,18 +1093,47 @@ static void blkback_changed(struct xenbus_device *dev, | |||
1093 | } | 1093 | } |
1094 | } | 1094 | } |
1095 | 1095 | ||
1096 | static int blkfront_remove(struct xenbus_device *dev) | 1096 | static int blkfront_remove(struct xenbus_device *xbdev) |
1097 | { | 1097 | { |
1098 | struct blkfront_info *info = dev_get_drvdata(&dev->dev); | 1098 | struct blkfront_info *info = dev_get_drvdata(&xbdev->dev); |
1099 | struct block_device *bdev = NULL; | ||
1100 | struct gendisk *disk; | ||
1099 | 1101 | ||
1100 | dev_dbg(&dev->dev, "blkfront_remove: %s removed\n", dev->nodename); | 1102 | dev_dbg(&xbdev->dev, "%s removed", xbdev->nodename); |
1101 | 1103 | ||
1102 | blkif_free(info, 0); | 1104 | blkif_free(info, 0); |
1103 | 1105 | ||
1104 | if(info->users == 0) | 1106 | mutex_lock(&info->mutex); |
1107 | |||
1108 | disk = info->gd; | ||
1109 | if (disk) | ||
1110 | bdev = bdget_disk(disk, 0); | ||
1111 | |||
1112 | info->xbdev = NULL; | ||
1113 | mutex_unlock(&info->mutex); | ||
1114 | |||
1115 | if (!bdev) { | ||
1116 | kfree(info); | ||
1117 | return 0; | ||
1118 | } | ||
1119 | |||
1120 | /* | ||
1121 | * The xbdev was removed before we reached the Closed | ||
1122 | * state. See if it's safe to remove the disk. If the bdev | ||
1123 | * isn't closed yet, we let release take care of it. | ||
1124 | */ | ||
1125 | |||
1126 | mutex_lock(&bdev->bd_mutex); | ||
1127 | info = disk->private_data; | ||
1128 | |||
1129 | if (info && !info->users) { | ||
1130 | xlvbd_release_gendisk(info); | ||
1131 | disk->private_data = NULL; | ||
1105 | kfree(info); | 1132 | kfree(info); |
1106 | else | 1133 | } |
1107 | info->xbdev = NULL; | 1134 | |
1135 | mutex_unlock(&bdev->bd_mutex); | ||
1136 | bdput(bdev); | ||
1108 | 1137 | ||
1109 | return 0; | 1138 | return 0; |
1110 | } | 1139 | } |