xen-netback: enable user to unload netback module
authorWei Liu <wei.liu2@citrix.com>
Thu, 16 May 2013 23:26:11 +0000 (23:26 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 18 May 2013 01:23:07 +0000 (18:23 -0700)
This patch enables user to unload netback module, which is useful when user
wants to upgrade to a newer netback module without rebooting the host.

Netfront cannot handle netback removal event. As we cannot fix all possible
frontends we add module get / put along with vif get / put to avoid
mis-unloading of netback. To unload netback module, user needs to shutdown all
VMs or migrate them to another host or unplug all vifs before hand.

Signed-off-by: Wei Liu <wei.liu2@citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>¬
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/xen-netback/common.h
drivers/net/xen-netback/interface.c
drivers/net/xen-netback/netback.c
drivers/net/xen-netback/xenbus.c

index 9d7f1723dd8f750126337d7792a0614fea8ca601..6102a6c59f4ef50a1867b5fd64dace788c209203 100644 (file)
@@ -120,6 +120,7 @@ void xenvif_get(struct xenvif *vif);
 void xenvif_put(struct xenvif *vif);
 
 int xenvif_xenbus_init(void);
+void xenvif_xenbus_fini(void);
 
 int xenvif_schedulable(struct xenvif *vif);
 
index d984141684857c1708085af50ad8fed208a06f85..82202c2b1bd11a59c6175f3af393dff4060faa3f 100644 (file)
@@ -316,6 +316,8 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
        if (vif->irq)
                return 0;
 
+       __module_get(THIS_MODULE);
+
        err = xen_netbk_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref);
        if (err < 0)
                goto err;
@@ -343,6 +345,7 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
 err_unmap:
        xen_netbk_unmap_frontend_rings(vif);
 err:
+       module_put(THIS_MODULE);
        return err;
 }
 
@@ -360,18 +363,32 @@ void xenvif_carrier_off(struct xenvif *vif)
 
 void xenvif_disconnect(struct xenvif *vif)
 {
+       /* Disconnect funtion might get called by generic framework
+        * even before vif connects, so we need to check if we really
+        * need to do a module_put.
+        */
+       int need_module_put = 0;
+
        if (netif_carrier_ok(vif->dev))
                xenvif_carrier_off(vif);
 
        atomic_dec(&vif->refcnt);
        wait_event(vif->waiting_to_free, atomic_read(&vif->refcnt) == 0);
 
-       if (vif->irq)
+       if (vif->irq) {
                unbind_from_irqhandler(vif->irq, vif);
+               /* vif->irq is valid, we had a module_get in
+                * xenvif_connect.
+                */
+               need_module_put = 1;
+       }
 
        unregister_netdev(vif->dev);
 
        xen_netbk_unmap_frontend_rings(vif);
 
        free_netdev(vif->dev);
+
+       if (need_module_put)
+               module_put(THIS_MODULE);
 }
index 295a9c267df4d3d71b9ef3fac5bdb591ed1a2a7e..2d9477fd900f1aff4ead55582e21225b14da1046 100644 (file)
@@ -1949,5 +1949,25 @@ failed_init:
 
 module_init(netback_init);
 
+static void __exit netback_fini(void)
+{
+       int i, j;
+
+       xenvif_xenbus_fini();
+
+       for (i = 0; i < xen_netbk_group_nr; i++) {
+               struct xen_netbk *netbk = &xen_netbk[i];
+               del_timer_sync(&netbk->net_timer);
+               kthread_stop(netbk->task);
+               for (j = 0; j < MAX_PENDING_REQS; j++) {
+                       if (netbk->mmap_pages[i])
+                               __free_page(netbk->mmap_pages[i]);
+               }
+       }
+
+       vfree(xen_netbk);
+}
+module_exit(netback_fini);
+
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_ALIAS("xen-backend:vif");
index 410018c4c52818f0b3a697d64e4300a505825f91..d230c145660c8fdf71a71b7ed72f14f1e9581f16 100644 (file)
@@ -485,3 +485,8 @@ int xenvif_xenbus_init(void)
 {
        return xenbus_register_backend(&netback_driver);
 }
+
+void xenvif_xenbus_fini(void)
+{
+       return xenbus_unregister_driver(&netback_driver);
+}