aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorPaul Durrant <Paul.Durrant@citrix.com>2013-09-17 12:46:08 -0400
committerDavid S. Miller <davem@davemloft.net>2013-09-19 14:03:51 -0400
commit279f438e36c0a70b23b86d2090aeec50155034a9 (patch)
tree2321278098da43c72508e97edbf8a76f2ee63683 /drivers/net
parentbd784a140712fd06674f2240eecfc4ccae421129 (diff)
xen-netback: Don't destroy the netdev until the vif is shut down
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: Paul 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> Acked-by: Wei Liu <wei.liu2@citrix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/xen-netback/common.h1
-rw-r--r--drivers/net/xen-netback/interface.c26
-rw-r--r--drivers/net/xen-netback/xenbus.c17
3 files changed, 23 insertions, 21 deletions
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index a1977430ddfb..5715318d6bab 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -184,6 +184,7 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
184 unsigned long rx_ring_ref, unsigned int tx_evtchn, 184 unsigned long rx_ring_ref, unsigned int tx_evtchn,
185 unsigned int rx_evtchn); 185 unsigned int rx_evtchn);
186void xenvif_disconnect(struct xenvif *vif); 186void xenvif_disconnect(struct xenvif *vif);
187void xenvif_free(struct xenvif *vif);
187 188
188int xenvif_xenbus_init(void); 189int xenvif_xenbus_init(void);
189void xenvif_xenbus_fini(void); 190void xenvif_xenbus_fini(void);
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index 77fee1d51fb2..01bb854c7f62 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -353,6 +353,9 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
353 } 353 }
354 354
355 netdev_dbg(dev, "Successfully created xenvif\n"); 355 netdev_dbg(dev, "Successfully created xenvif\n");
356
357 __module_get(THIS_MODULE);
358
356 return vif; 359 return vif;
357} 360}
358 361
@@ -366,8 +369,6 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
366 if (vif->tx_irq) 369 if (vif->tx_irq)
367 return 0; 370 return 0;
368 371
369 __module_get(THIS_MODULE);
370
371 err = xenvif_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref); 372 err = xenvif_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref);
372 if (err < 0) 373 if (err < 0)
373 goto err; 374 goto err;
@@ -452,12 +453,6 @@ void xenvif_carrier_off(struct xenvif *vif)
452 453
453void xenvif_disconnect(struct xenvif *vif) 454void xenvif_disconnect(struct xenvif *vif)
454{ 455{
455 /* Disconnect funtion might get called by generic framework
456 * even before vif connects, so we need to check if we really
457 * need to do a module_put.
458 */
459 int need_module_put = 0;
460
461 if (netif_carrier_ok(vif->dev)) 456 if (netif_carrier_ok(vif->dev))
462 xenvif_carrier_off(vif); 457 xenvif_carrier_off(vif);
463 458
@@ -468,23 +463,22 @@ void xenvif_disconnect(struct xenvif *vif)
468 unbind_from_irqhandler(vif->tx_irq, vif); 463 unbind_from_irqhandler(vif->tx_irq, vif);
469 unbind_from_irqhandler(vif->rx_irq, vif); 464 unbind_from_irqhandler(vif->rx_irq, vif);
470 } 465 }
471 /* vif->irq is valid, we had a module_get in 466 vif->tx_irq = 0;
472 * xenvif_connect.
473 */
474 need_module_put = 1;
475 } 467 }
476 468
477 if (vif->task) 469 if (vif->task)
478 kthread_stop(vif->task); 470 kthread_stop(vif->task);
479 471
472 xenvif_unmap_frontend_rings(vif);
473}
474
475void xenvif_free(struct xenvif *vif)
476{
480 netif_napi_del(&vif->napi); 477 netif_napi_del(&vif->napi);
481 478
482 unregister_netdev(vif->dev); 479 unregister_netdev(vif->dev);
483 480
484 xenvif_unmap_frontend_rings(vif);
485
486 free_netdev(vif->dev); 481 free_netdev(vif->dev);
487 482
488 if (need_module_put) 483 module_put(THIS_MODULE);
489 module_put(THIS_MODULE);
490} 484}
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
index 1fe48fe364ed..a53782ef1540 100644
--- a/drivers/net/xen-netback/xenbus.c
+++ b/drivers/net/xen-netback/xenbus.c
@@ -42,7 +42,7 @@ static int netback_remove(struct xenbus_device *dev)
42 if (be->vif) { 42 if (be->vif) {
43 kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE); 43 kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
44 xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status"); 44 xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
45 xenvif_disconnect(be->vif); 45 xenvif_free(be->vif);
46 be->vif = NULL; 46 be->vif = NULL;
47 } 47 }
48 kfree(be); 48 kfree(be);
@@ -213,9 +213,18 @@ static void disconnect_backend(struct xenbus_device *dev)
213{ 213{
214 struct backend_info *be = dev_get_drvdata(&dev->dev); 214 struct backend_info *be = dev_get_drvdata(&dev->dev);
215 215
216 if (be->vif)
217 xenvif_disconnect(be->vif);
218}
219
220static void destroy_backend(struct xenbus_device *dev)
221{
222 struct backend_info *be = dev_get_drvdata(&dev->dev);
223
216 if (be->vif) { 224 if (be->vif) {
225 kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
217 xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status"); 226 xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
218 xenvif_disconnect(be->vif); 227 xenvif_free(be->vif);
219 be->vif = NULL; 228 be->vif = NULL;
220 } 229 }
221} 230}
@@ -246,14 +255,11 @@ static void frontend_changed(struct xenbus_device *dev,
246 case XenbusStateConnected: 255 case XenbusStateConnected:
247 if (dev->state == XenbusStateConnected) 256 if (dev->state == XenbusStateConnected)
248 break; 257 break;
249 backend_create_xenvif(be);
250 if (be->vif) 258 if (be->vif)
251 connect(be); 259 connect(be);
252 break; 260 break;
253 261
254 case XenbusStateClosing: 262 case XenbusStateClosing:
255 if (be->vif)
256 kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
257 disconnect_backend(dev); 263 disconnect_backend(dev);
258 xenbus_switch_state(dev, XenbusStateClosing); 264 xenbus_switch_state(dev, XenbusStateClosing);
259 break; 265 break;
@@ -262,6 +268,7 @@ static void frontend_changed(struct xenbus_device *dev,
262 xenbus_switch_state(dev, XenbusStateClosed); 268 xenbus_switch_state(dev, XenbusStateClosed);
263 if (xenbus_dev_is_online(dev)) 269 if (xenbus_dev_is_online(dev))
264 break; 270 break;
271 destroy_backend(dev);
265 /* fall through if not online */ 272 /* fall through if not online */
266 case XenbusStateUnknown: 273 case XenbusStateUnknown:
267 device_unregister(&dev->dev); 274 device_unregister(&dev->dev);