Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=74b2553f1d13e60fb27063204bd5b6908a6f8494
Commit:     74b2553f1d13e60fb27063204bd5b6908a6f8494
Parent:     d1c856e0f1a4c946c6329cff126548ef4288735f
Author:     Rusty Russell <[EMAIL PROTECTED]>
AuthorDate: Mon Nov 19 11:20:42 2007 -0500
Committer:  Rusty Russell <[EMAIL PROTECTED]>
CommitDate: Mon Nov 19 11:20:42 2007 +1100

    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 <[EMAIL PROTECTED]>
---
 drivers/block/virtio_blk.c     |   10 +++++++---
 drivers/lguest/lguest_device.c |    2 ++
 drivers/net/virtio_net.c       |    8 ++++++--
 drivers/virtio/virtio.c        |   13 +++++++++++++
 4 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 3cf7129..924ddd8 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -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);
 }
 
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
index 66f3872..e2eec38 100644
--- a/drivers/lguest/lguest_device.c
+++ b/drivers/lguest/lguest_device.c
@@ -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. */
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index a75be57..d74e6f4 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -404,8 +404,12 @@ free:
 
 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[] = {
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index 15d7787..69d7ea0 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -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);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to