summaryrefslogtreecommitdiff
path: root/drivers/block
diff options
context:
space:
mode:
authorAlex Elder <elder@inktank.com>2013-04-26 04:15:08 (GMT)
committerSage Weil <sage@inktank.com>2013-05-02 04:19:32 (GMT)
commita0cab924324fac8d6414009bc25ce31eeece038e (patch)
treed8b180f239a010df65a11d80047be25b33626052 /drivers/block
parentf40eb349e032bee2b6f06e9b6f1dbfae561bd30a (diff)
downloadlinux-fsl-qoriq-a0cab924324fac8d6414009bc25ce31eeece038e.tar.xz
rbd: avoid dropping extra reference in rbd_free_disk()
I found during some failure injection testing that the call to rbd_free_disk() in the error path of rbd_dev_probe_finish() was dropping an extra reference to the disk queue. The problem occurred when put_disk tried to drop a reference to the disk's queue. A call to blk_cleanup_queue() just prior to that will have also dropped a reference to the queue. The problem is that the reference dropped by put_disk() is assumed to have been taken by add_disk(). Our code has error paths that can occur after the disk and its queue are initialized, but before the call to add_disk(), and in those paths we won't have that extra reference. The fix is easy though. In rbd_free_disk() we're already checking the disk's GENHD_FL_UP flag. That flag is an indication that add_disk() has been called, so just call blk_cleanup_queue() conditional on that flag being set. This resolves: http://tracker.ceph.com/issues/4800 Signed-off-by: Alex Elder <elder@inktank.com> Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/rbd.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 21e84a1..1704a3b 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -2844,10 +2844,12 @@ static void rbd_free_disk(struct rbd_device *rbd_dev)
if (!disk)
return;
- if (disk->flags & GENHD_FL_UP)
+ rbd_dev->disk = NULL;
+ if (disk->flags & GENHD_FL_UP) {
del_gendisk(disk);
- if (disk->queue)
- blk_cleanup_queue(disk->queue);
+ if (disk->queue)
+ blk_cleanup_queue(disk->queue);
+ }
put_disk(disk);
}