diff options
| author | Paul Durrant <pdurrant@amazon.com> | 2019-12-23 09:59:23 +0000 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2019-12-26 15:16:26 -0800 | 
| commit | 9476654bd5e8ad42abe8ee9f9e90069ff8e60c17 (patch) | |
| tree | d063572a1f27c26bb642e0fb30a5afe50ba5afb4 /drivers/net/xen-netback | |
| parent | 8d347992989465fc7135ef1a84ca4c710a705c1a (diff) | |
| download | linux-9476654bd5e8ad42abe8ee9f9e90069ff8e60c17.tar.bz2 | |
xen-netback: support dynamic unbind/bind
By re-attaching RX, TX, and CTL rings during connect() rather than
assuming they are freshly allocated (i.e. assuming the counters are zero),
and avoiding forcing state to Closed in netback_remove() it is possible
for vif instances to be unbound and re-bound from and to (respectively) a
running guest.
Dynamic unbind/bind is a highly useful feature for a backend module as it
allows it to be unloaded and re-loaded (i.e. updated) without requiring
domUs to be halted.
This has been tested by running iperf as a server in the test VM and
then running a client against it in a continuous loop, whilst also
running:
while true;
  do echo vif-$DOMID-$VIF >unbind;
  echo down;
  rmmod xen-netback;
  echo unloaded;
  modprobe xen-netback;
  cd $(pwd);
  brctl addif xenbr0 vif$DOMID.$VIF;
  ip link set vif$DOMID.$VIF up;
  echo up;
  sleep 5;
  done
in dom0 from /sys/bus/xen-backend/drivers/vif to continuously unbind,
unload, re-load, re-bind and re-plumb the backend.
Clearly a performance drop was seen but no TCP connection resets were
observed during this test and moreover a parallel SSH connection into the
guest remained perfectly usable throughout.
Signed-off-by: Paul Durrant <pdurrant@amazon.com>
Reviewed-by: Wei Liu <wei.liu@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/xen-netback')
| -rw-r--r-- | drivers/net/xen-netback/interface.c | 10 | ||||
| -rw-r--r-- | drivers/net/xen-netback/netback.c | 20 | ||||
| -rw-r--r-- | drivers/net/xen-netback/xenbus.c | 5 | 
3 files changed, 28 insertions, 7 deletions
| diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index f15ba3de6195..0c8a02a1ead7 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -585,6 +585,7 @@ int xenvif_connect_ctrl(struct xenvif *vif, grant_ref_t ring_ref,  	struct net_device *dev = vif->dev;  	void *addr;  	struct xen_netif_ctrl_sring *shared; +	RING_IDX rsp_prod, req_prod;  	int err;  	err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(vif), @@ -593,7 +594,14 @@ int xenvif_connect_ctrl(struct xenvif *vif, grant_ref_t ring_ref,  		goto err;  	shared = (struct xen_netif_ctrl_sring *)addr; -	BACK_RING_INIT(&vif->ctrl, shared, XEN_PAGE_SIZE); +	rsp_prod = READ_ONCE(shared->rsp_prod); +	req_prod = READ_ONCE(shared->req_prod); + +	BACK_RING_ATTACH(&vif->ctrl, shared, rsp_prod, XEN_PAGE_SIZE); + +	err = -EIO; +	if (req_prod - rsp_prod > RING_SIZE(&vif->ctrl)) +		goto err_unmap;  	err = bind_interdomain_evtchn_to_irq(vif->domid, evtchn);  	if (err < 0) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 0020b2e8c279..315dfc6ea297 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1453,7 +1453,7 @@ int xenvif_map_frontend_data_rings(struct xenvif_queue *queue,  	void *addr;  	struct xen_netif_tx_sring *txs;  	struct xen_netif_rx_sring *rxs; - +	RING_IDX rsp_prod, req_prod;  	int err = -ENOMEM;  	err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif), @@ -1462,7 +1462,14 @@ int xenvif_map_frontend_data_rings(struct xenvif_queue *queue,  		goto err;  	txs = (struct xen_netif_tx_sring *)addr; -	BACK_RING_INIT(&queue->tx, txs, XEN_PAGE_SIZE); +	rsp_prod = READ_ONCE(txs->rsp_prod); +	req_prod = READ_ONCE(txs->req_prod); + +	BACK_RING_ATTACH(&queue->tx, txs, rsp_prod, XEN_PAGE_SIZE); + +	err = -EIO; +	if (req_prod - rsp_prod > RING_SIZE(&queue->tx)) +		goto err;  	err = xenbus_map_ring_valloc(xenvif_to_xenbus_device(queue->vif),  				     &rx_ring_ref, 1, &addr); @@ -1470,7 +1477,14 @@ int xenvif_map_frontend_data_rings(struct xenvif_queue *queue,  		goto err;  	rxs = (struct xen_netif_rx_sring *)addr; -	BACK_RING_INIT(&queue->rx, rxs, XEN_PAGE_SIZE); +	rsp_prod = READ_ONCE(rxs->rsp_prod); +	req_prod = READ_ONCE(rxs->req_prod); + +	BACK_RING_ATTACH(&queue->rx, rxs, rsp_prod, XEN_PAGE_SIZE); + +	err = -EIO; +	if (req_prod - rsp_prod > RING_SIZE(&queue->rx)) +		goto err;  	return 0; diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 17b4950ec051..286054b60d47 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -954,12 +954,10 @@ static int netback_remove(struct xenbus_device *dev)  {  	struct backend_info *be = dev_get_drvdata(&dev->dev); -	set_backend_state(be, XenbusStateClosed); -  	unregister_hotplug_status_watch(be);  	if (be->vif) {  		kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE); -		xen_unregister_watchers(be->vif); +		backend_disconnect(be);  		xenvif_free(be->vif);  		be->vif = NULL;  	} @@ -1131,6 +1129,7 @@ static struct xenbus_driver netback_driver = {  	.remove = netback_remove,  	.uevent = netback_uevent,  	.otherend_changed = frontend_changed, +	.allow_rebind = true,  };  int xenvif_xenbus_init(void) |