blktap: Fix queue restart, racing block device removal. Makes tapdisk context test dev->gd before attempting a queue restart, with the device lock held. Fixes a race lost against device destruction, which may issued anywhere on the control path. Signed-off-by: Daniel Stodden diff -r b8f6877ed00e drivers/xen/blktap/device.c --- a/drivers/xen/blktap/device.c Wed Feb 24 18:31:41 2010 -0800 +++ b/drivers/xen/blktap/device.c Wed Feb 24 18:50:18 2010 -0800 @@ -896,8 +896,6 @@ struct blktap_device *dev; dev = &tap->device; - if (!dev->gd || !dev->gd->queue) - return; if (blktap_active(tap) && RING_FULL(&tap->ring.ring)) { blktap_defer(tap); @@ -913,11 +911,15 @@ spin_lock_irq(&dev->lock); /* Re-enable calldowns. */ - if (blk_queue_stopped(dev->gd->queue)) - blk_start_queue(dev->gd->queue); + if (dev->gd) { + struct request_queue *rq = dev->gd->queue; - /* Kick things off immediately. */ - blktap_device_do_request(dev->gd->queue); + if (blk_queue_stopped(rq)) + blk_start_queue(rq); + + /* Kick things off immediately. */ + blktap_device_do_request(rq); + } spin_unlock_irq(&dev->lock); } @@ -1006,6 +1008,7 @@ blktap_device_destroy(struct blktap *tap) { struct blktap_device *dev = &tap->device; + struct gendisk *gd = dev->gd; if (!test_bit(BLKTAP_DEVICE, &tap->dev_inuse)) return 0; @@ -1017,8 +1020,9 @@ spin_lock_irq(&dev->lock); /* No more blktap_device_do_request(). */ - blk_stop_queue(dev->gd->queue); + blk_stop_queue(gd->queue); clear_bit(BLKTAP_DEVICE, &tap->dev_inuse); + dev->gd = NULL; spin_unlock_irq(&dev->lock); #ifdef ENABLE_PASSTHROUGH @@ -1026,11 +1030,9 @@ blktap_device_close_bdev(tap); #endif - del_gendisk(dev->gd); - blk_cleanup_queue(dev->gd->queue); - put_disk(dev->gd); - - dev->gd = NULL; + del_gendisk(gd); + blk_cleanup_queue(gd->queue); + put_disk(gd); wake_up(&tap->wq);