diff options
author | Daniel Stodden <daniel.stodden@citrix.com> | 2010-05-01 00:01:22 +0200 |
---|---|---|
committer | Jens Axboe <jaxboe@fusionio.com> | 2010-08-07 18:45:27 +0200 |
commit | fa1bd3591a669b92b635dbdb11d1a32a5630821b (patch) | |
tree | 41309de6425e854420b26bdcfd94accaf52c3cee /drivers/block/xen-blkfront.c | |
parent | blkfront: Fix blkfront backend switch race (bdev release) (diff) | |
download | linux-fa1bd3591a669b92b635dbdb11d1a32a5630821b.tar.xz linux-fa1bd3591a669b92b635dbdb11d1a32a5630821b.zip |
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, } } -static int blkfront_remove(struct xenbus_device *dev) +static int blkfront_remove(struct xenbus_device *xbdev) { - struct blkfront_info *info = dev_get_drvdata(&dev->dev); + struct blkfront_info *info = dev_get_drvdata(&xbdev->dev); + struct block_device *bdev = NULL; + struct gendisk *disk; - dev_dbg(&dev->dev, "blkfront_remove: %s removed\n", dev->nodename); + dev_dbg(&xbdev->dev, "%s removed", xbdev->nodename); blkif_free(info, 0); - if(info->users == 0) + mutex_lock(&info->mutex); + + disk = info->gd; + if (disk) + bdev = bdget_disk(disk, 0); + + info->xbdev = NULL; + mutex_unlock(&info->mutex); + + if (!bdev) { + kfree(info); + return 0; + } + + /* + * The xbdev was removed before we reached the Closed + * state. See if it's safe to remove the disk. If the bdev + * isn't closed yet, we let release take care of it. + */ + + mutex_lock(&bdev->bd_mutex); + info = disk->private_data; + + if (info && !info->users) { + xlvbd_release_gendisk(info); + disk->private_data = NULL; kfree(info); - else - info->xbdev = NULL; + } + + mutex_unlock(&bdev->bd_mutex); + bdput(bdev); return 0; } |