forked from luck/tmp_suning_uos_patched
virtio: fix module/device unloading
The virtio code never hooked through the ->remove callback. Although noone supports device removal at the moment, this code is already needed for module unloading. This of course also revealed bugs in virtio_blk, virtio_net and lguest unloading paths. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
d1c856e0f1
commit
74b2553f1d
|
@ -223,7 +223,7 @@ static int virtblk_probe(struct virtio_device *vdev)
|
|||
err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_CAPACITY, &cap);
|
||||
if (err) {
|
||||
dev_err(&vdev->dev, "Bad/missing capacity in config\n");
|
||||
goto out_put_disk;
|
||||
goto out_cleanup_queue;
|
||||
}
|
||||
|
||||
/* If capacity is too big, truncate with warning. */
|
||||
|
@ -239,7 +239,7 @@ static int virtblk_probe(struct virtio_device *vdev)
|
|||
blk_queue_max_segment_size(vblk->disk->queue, v);
|
||||
else if (err != -ENOENT) {
|
||||
dev_err(&vdev->dev, "Bad SIZE_MAX in config\n");
|
||||
goto out_put_disk;
|
||||
goto out_cleanup_queue;
|
||||
}
|
||||
|
||||
err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_SEG_MAX, &v);
|
||||
|
@ -247,12 +247,14 @@ static int virtblk_probe(struct virtio_device *vdev)
|
|||
blk_queue_max_hw_segments(vblk->disk->queue, v);
|
||||
else if (err != -ENOENT) {
|
||||
dev_err(&vdev->dev, "Bad SEG_MAX in config\n");
|
||||
goto out_put_disk;
|
||||
goto out_cleanup_queue;
|
||||
}
|
||||
|
||||
add_disk(vblk->disk);
|
||||
return 0;
|
||||
|
||||
out_cleanup_queue:
|
||||
blk_cleanup_queue(vblk->disk->queue);
|
||||
out_put_disk:
|
||||
put_disk(vblk->disk);
|
||||
out_unregister_blkdev:
|
||||
|
@ -277,6 +279,8 @@ static void virtblk_remove(struct virtio_device *vdev)
|
|||
put_disk(vblk->disk);
|
||||
unregister_blkdev(major, "virtblk");
|
||||
mempool_destroy(vblk->pool);
|
||||
/* There should be nothing in the queue now, so no need to shutdown */
|
||||
vdev->config->del_vq(vblk->vq);
|
||||
kfree(vblk);
|
||||
}
|
||||
|
||||
|
|
|
@ -247,6 +247,8 @@ static void lg_del_vq(struct virtqueue *vq)
|
|||
{
|
||||
struct lguest_vq_info *lvq = vq->priv;
|
||||
|
||||
/* Release the interrupt */
|
||||
free_irq(lvq->config.irq, vq);
|
||||
/* Tell virtio_ring.c to free the virtqueue. */
|
||||
vring_del_virtqueue(vq);
|
||||
/* Unmap the pages containing the ring. */
|
||||
|
|
|
@ -404,8 +404,12 @@ static int virtnet_probe(struct virtio_device *vdev)
|
|||
|
||||
static void virtnet_remove(struct virtio_device *vdev)
|
||||
{
|
||||
unregister_netdev(vdev->priv);
|
||||
free_netdev(vdev->priv);
|
||||
struct virtnet_info *vi = vdev->priv;
|
||||
|
||||
vdev->config->del_vq(vi->svq);
|
||||
vdev->config->del_vq(vi->rvq);
|
||||
unregister_netdev(vi->dev);
|
||||
free_netdev(vi->dev);
|
||||
}
|
||||
|
||||
static struct virtio_device_id id_table[] = {
|
||||
|
|
|
@ -96,10 +96,23 @@ static int virtio_dev_probe(struct device *_d)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int virtio_dev_remove(struct device *_d)
|
||||
{
|
||||
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
|
||||
struct virtio_driver *drv = container_of(dev->dev.driver,
|
||||
struct virtio_driver, driver);
|
||||
|
||||
dev->config->set_status(dev, dev->config->get_status(dev)
|
||||
& ~VIRTIO_CONFIG_S_DRIVER);
|
||||
drv->remove(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int register_virtio_driver(struct virtio_driver *driver)
|
||||
{
|
||||
driver->driver.bus = &virtio_bus;
|
||||
driver->driver.probe = virtio_dev_probe;
|
||||
driver->driver.remove = virtio_dev_remove;
|
||||
return driver_register(&driver->driver);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_virtio_driver);
|
||||
|
|
Loading…
Reference in New Issue
Block a user