Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e2e004ac authored by Ross Lagerwall's avatar Ross Lagerwall Committed by David S. Miller
Browse files

xen-netfront: Improve error handling during initialization



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: default avatarRoss Lagerwall <ross.lagerwall@citrix.com>
Reviewed-by: default avatarBoris Ostrovsky <boris.ostrovsky@oracle.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1b5805c2
Loading
Loading
Loading
Loading
+11 −18
Original line number Diff line number Diff line
@@ -1830,27 +1830,19 @@ static int talk_to_netback(struct xenbus_device *dev,
		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();
		if (err)
			goto destroy_ring;
			} else {
				goto out;
			}
		}
	}

again:
@@ -1940,9 +1932,10 @@ static int talk_to_netback(struct xenbus_device *dev,
	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;
}