| From: Ross Lagerwall <ross.lagerwall@citrix.com> |
| Date: Wed, 8 Feb 2017 10:57:37 +0000 |
| Subject: xen-netfront: Improve error handling during initialization |
| |
| commit e2e004acc7cbe3c531e752a270a74e95cde3ea48 upstream. |
| |
| This fixes a crash when running out of grant refs when creating many |
| queues across many netdevs. |
| |
| * If creating queues fails (i.e. there are no grant refs available), |
| call xenbus_dev_fatal() to ensure that the xenbus device is set to the |
| closed state. |
| * If no queues are created, don't call xennet_disconnect_backend as |
| netdev->real_num_tx_queues will not have been set correctly. |
| * If setup_netfront() fails, ensure that all the queues created are |
| cleaned up, not just those that have been set up. |
| * If any queues were set up and an error occurs, call |
| xennet_destroy_queues() to clean up the napi context. |
| * If any fatal error occurs, unregister and destroy the netdev to avoid |
| leaving around a half setup network device. |
| |
| Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com> |
| Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| drivers/net/xen-netfront.c | 29 +++++++++++------------------ |
| 1 file changed, 11 insertions(+), 18 deletions(-) |
| |
| --- a/drivers/net/xen-netfront.c |
| +++ b/drivers/net/xen-netfront.c |
| @@ -1879,27 +1879,19 @@ static int talk_to_netback(struct xenbus |
| xennet_destroy_queues(info); |
| |
| err = xennet_create_queues(info, &num_queues); |
| - if (err < 0) |
| - goto destroy_ring; |
| + if (err < 0) { |
| + xenbus_dev_fatal(dev, err, "creating queues"); |
| + kfree(info->queues); |
| + info->queues = NULL; |
| + goto out; |
| + } |
| |
| /* Create shared ring, alloc event channel -- for each queue */ |
| for (i = 0; i < num_queues; ++i) { |
| queue = &info->queues[i]; |
| err = setup_netfront(dev, queue, feature_split_evtchn); |
| - if (err) { |
| - /* setup_netfront() will tidy up the current |
| - * queue on error, but we need to clean up |
| - * those already allocated. |
| - */ |
| - if (i > 0) { |
| - rtnl_lock(); |
| - netif_set_real_num_tx_queues(info->netdev, i); |
| - rtnl_unlock(); |
| - goto destroy_ring; |
| - } else { |
| - goto out; |
| - } |
| - } |
| + if (err) |
| + goto destroy_ring; |
| } |
| |
| again: |
| @@ -1986,9 +1978,10 @@ abort_transaction_no_dev_fatal: |
| xenbus_transaction_end(xbt, 1); |
| destroy_ring: |
| xennet_disconnect_backend(info); |
| - kfree(info->queues); |
| - info->queues = NULL; |
| + xennet_destroy_queues(info); |
| out: |
| + unregister_netdev(info->netdev); |
| + xennet_free_netdev(info->netdev); |
| return err; |
| } |
| |