Commit f495ddc4 authored by Paul Durrant's avatar Paul Durrant Committed by Greg Kroah-Hartman

xen-netback: Don't destroy the netdev until the vif is shut down

[ upstream commit id: 279f438e ]

Without this patch, if a frontend cycles through states Closing
and Closed (which Windows frontends need to do) then the netdev
will be destroyed and requires re-invocation of hotplug scripts
to restore state before the frontend can move to Connected. Thus
when udev is not in use the backend gets stuck in InitWait.

With this patch, the netdev is left alone whilst the backend is
still online and is only de-registered and freed just prior to
destroying the vif (which is also nicely symmetrical with the
netdev allocation and registration being done during probe) so
no re-invocation of hotplug scripts is required.
Signed-off-by: default avatarPaul Durrant <paul.durrant@citrix.com>
Cc: David Vrabel <david.vrabel@citrix.com>
Cc: Wei Liu <wei.liu2@citrix.com>
Cc: Ian Campbell <ian.campbell@citrix.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent b9396c4c
...@@ -115,6 +115,7 @@ struct xenvif *xenvif_alloc(struct device *parent, ...@@ -115,6 +115,7 @@ struct xenvif *xenvif_alloc(struct device *parent,
int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
unsigned long rx_ring_ref, unsigned int evtchn); unsigned long rx_ring_ref, unsigned int evtchn);
void xenvif_disconnect(struct xenvif *vif); void xenvif_disconnect(struct xenvif *vif);
void xenvif_free(struct xenvif *vif);
void xenvif_get(struct xenvif *vif); void xenvif_get(struct xenvif *vif);
void xenvif_put(struct xenvif *vif); void xenvif_put(struct xenvif *vif);
......
...@@ -304,6 +304,9 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, ...@@ -304,6 +304,9 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
} }
netdev_dbg(dev, "Successfully created xenvif\n"); netdev_dbg(dev, "Successfully created xenvif\n");
__module_get(THIS_MODULE);
return vif; return vif;
} }
...@@ -369,9 +372,14 @@ void xenvif_disconnect(struct xenvif *vif) ...@@ -369,9 +372,14 @@ void xenvif_disconnect(struct xenvif *vif)
if (vif->irq) if (vif->irq)
unbind_from_irqhandler(vif->irq, vif); unbind_from_irqhandler(vif->irq, vif);
unregister_netdev(vif->dev);
xen_netbk_unmap_frontend_rings(vif); xen_netbk_unmap_frontend_rings(vif);
}
void xenvif_free(struct xenvif *vif)
{
unregister_netdev(vif->dev);
free_netdev(vif->dev); free_netdev(vif->dev);
module_put(THIS_MODULE);
} }
...@@ -42,7 +42,7 @@ static int netback_remove(struct xenbus_device *dev) ...@@ -42,7 +42,7 @@ static int netback_remove(struct xenbus_device *dev)
if (be->vif) { if (be->vif) {
kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE); kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status"); xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
xenvif_disconnect(be->vif); xenvif_free(be->vif);
be->vif = NULL; be->vif = NULL;
} }
kfree(be); kfree(be);
...@@ -203,9 +203,18 @@ static void disconnect_backend(struct xenbus_device *dev) ...@@ -203,9 +203,18 @@ static void disconnect_backend(struct xenbus_device *dev)
{ {
struct backend_info *be = dev_get_drvdata(&dev->dev); struct backend_info *be = dev_get_drvdata(&dev->dev);
if (be->vif)
xenvif_disconnect(be->vif);
}
static void destroy_backend(struct xenbus_device *dev)
{
struct backend_info *be = dev_get_drvdata(&dev->dev);
if (be->vif) { if (be->vif) {
kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status"); xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
xenvif_disconnect(be->vif); xenvif_free(be->vif);
be->vif = NULL; be->vif = NULL;
} }
} }
...@@ -237,14 +246,11 @@ static void frontend_changed(struct xenbus_device *dev, ...@@ -237,14 +246,11 @@ static void frontend_changed(struct xenbus_device *dev,
case XenbusStateConnected: case XenbusStateConnected:
if (dev->state == XenbusStateConnected) if (dev->state == XenbusStateConnected)
break; break;
backend_create_xenvif(be);
if (be->vif) if (be->vif)
connect(be); connect(be);
break; break;
case XenbusStateClosing: case XenbusStateClosing:
if (be->vif)
kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
disconnect_backend(dev); disconnect_backend(dev);
xenbus_switch_state(dev, XenbusStateClosing); xenbus_switch_state(dev, XenbusStateClosing);
break; break;
...@@ -253,6 +259,7 @@ static void frontend_changed(struct xenbus_device *dev, ...@@ -253,6 +259,7 @@ static void frontend_changed(struct xenbus_device *dev,
xenbus_switch_state(dev, XenbusStateClosed); xenbus_switch_state(dev, XenbusStateClosed);
if (xenbus_dev_is_online(dev)) if (xenbus_dev_is_online(dev))
break; break;
destroy_backend(dev);
/* fall through if not online */ /* fall through if not online */
case XenbusStateUnknown: case XenbusStateUnknown:
device_unregister(&dev->dev); device_unregister(&dev->dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment