From e9ce7cb6b107407e4798e8905b18ad8b642766f6 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Wed, 4 Jun 2014 10:30:42 +0100 Subject: xen-netback: Factor queue-specific data into queue struct In preparation for multi-queue support in xen-netback, move the queue-specific data from struct xenvif into struct xenvif_queue, and update the rest of the code to use this. Also adds loops over queues where appropriate, even though only one is configured at this point, and uses alloc_netdev_mq() and the corresponding multi-queue netif wake/start/stop functions in preparation for multiple active queues. Finally, implements a trivial queue selection function suitable for ndo_select_queue, which simply returns 0 for a single queue and uses skb_get_hash() to compute the queue index otherwise. Signed-off-by: Andrew J. Bennieston Signed-off-by: Wei Liu Signed-off-by: David S. Miller --- drivers/net/xen-netback/xenbus.c | 95 ++++++++++++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 24 deletions(-) (limited to 'drivers/net/xen-netback/xenbus.c') diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 7a206cffb06..358602f55af 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -19,6 +19,8 @@ */ #include "common.h" +#include +#include struct backend_info { struct xenbus_device *dev; @@ -34,8 +36,9 @@ struct backend_info { u8 have_hotplug_status_watch:1; }; -static int connect_rings(struct backend_info *); -static void connect(struct backend_info *); +static int connect_rings(struct backend_info *be, struct xenvif_queue *queue); +static void connect(struct backend_info *be); +static int read_xenbus_vif_flags(struct backend_info *be); static void backend_create_xenvif(struct backend_info *be); static void unregister_hotplug_status_watch(struct backend_info *be); static void set_backend_state(struct backend_info *be, @@ -485,10 +488,10 @@ static void connect(struct backend_info *be) { int err; struct xenbus_device *dev = be->dev; - - err = connect_rings(be); - if (err) - return; + unsigned long credit_bytes, credit_usec; + unsigned int queue_index; + unsigned int requested_num_queues = 1; + struct xenvif_queue *queue; err = xen_net_read_mac(dev, be->vif->fe_dev_addr); if (err) { @@ -496,9 +499,34 @@ static void connect(struct backend_info *be) return; } - xen_net_read_rate(dev, &be->vif->credit_bytes, - &be->vif->credit_usec); - be->vif->remaining_credit = be->vif->credit_bytes; + xen_net_read_rate(dev, &credit_bytes, &credit_usec); + read_xenbus_vif_flags(be); + + be->vif->queues = vzalloc(requested_num_queues * + sizeof(struct xenvif_queue)); + rtnl_lock(); + netif_set_real_num_tx_queues(be->vif->dev, requested_num_queues); + rtnl_unlock(); + + for (queue_index = 0; queue_index < requested_num_queues; ++queue_index) { + queue = &be->vif->queues[queue_index]; + queue->vif = be->vif; + queue->id = queue_index; + snprintf(queue->name, sizeof(queue->name), "%s-q%u", + be->vif->dev->name, queue->id); + + err = xenvif_init_queue(queue); + if (err) + goto err; + + queue->remaining_credit = credit_bytes; + + err = connect_rings(be, queue); + if (err) + goto err; + } + + xenvif_carrier_on(be->vif); unregister_hotplug_status_watch(be); err = xenbus_watch_pathfmt(dev, &be->hotplug_status_watch, @@ -507,18 +535,26 @@ static void connect(struct backend_info *be) if (!err) be->have_hotplug_status_watch = 1; - netif_wake_queue(be->vif->dev); + netif_tx_wake_all_queues(be->vif->dev); + + return; + +err: + vfree(be->vif->queues); + be->vif->queues = NULL; + rtnl_lock(); + netif_set_real_num_tx_queues(be->vif->dev, 0); + rtnl_unlock(); + return; } -static int connect_rings(struct backend_info *be) +static int connect_rings(struct backend_info *be, struct xenvif_queue *queue) { - struct xenvif *vif = be->vif; struct xenbus_device *dev = be->dev; unsigned long tx_ring_ref, rx_ring_ref; - unsigned int tx_evtchn, rx_evtchn, rx_copy; + unsigned int tx_evtchn, rx_evtchn; int err; - int val; err = xenbus_gather(XBT_NIL, dev->otherend, "tx-ring-ref", "%lu", &tx_ring_ref, @@ -546,6 +582,27 @@ static int connect_rings(struct backend_info *be) rx_evtchn = tx_evtchn; } + /* Map the shared frame, irq etc. */ + err = xenvif_connect(queue, tx_ring_ref, rx_ring_ref, + tx_evtchn, rx_evtchn); + if (err) { + xenbus_dev_fatal(dev, err, + "mapping shared-frames %lu/%lu port tx %u rx %u", + tx_ring_ref, rx_ring_ref, + tx_evtchn, rx_evtchn); + return err; + } + + return 0; +} + +static int read_xenbus_vif_flags(struct backend_info *be) +{ + struct xenvif *vif = be->vif; + struct xenbus_device *dev = be->dev; + unsigned int rx_copy; + int err, val; + err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy", "%u", &rx_copy); if (err == -ENOENT) { @@ -621,16 +678,6 @@ static int connect_rings(struct backend_info *be) val = 0; vif->ipv6_csum = !!val; - /* Map the shared frame, irq etc. */ - err = xenvif_connect(vif, tx_ring_ref, rx_ring_ref, - tx_evtchn, rx_evtchn); - if (err) { - xenbus_dev_fatal(dev, err, - "mapping shared-frames %lu/%lu port tx %u rx %u", - tx_ring_ref, rx_ring_ref, - tx_evtchn, rx_evtchn); - return err; - } return 0; } -- cgit v1.2.3-70-g09d2 From 8d3d53b3e43363e79ab9a9ecc149b06c1314b25d Mon Sep 17 00:00:00 2001 From: "Andrew J. Bennieston" Date: Wed, 4 Jun 2014 10:30:43 +0100 Subject: xen-netback: Add support for multiple queues Builds on the refactoring of the previous patch to implement multiple queues between xen-netfront and xen-netback. Writes the maximum supported number of queues into XenStore, and reads the values written by the frontend to determine how many queues to use. Ring references and event channels are read from XenStore on a per-queue basis and rings are connected accordingly. Also adds code to handle the cleanup of any already initialised queues if the initialisation of a subsequent queue fails. Signed-off-by: Andrew J. Bennieston Acked-by: Wei Liu Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 2 + drivers/net/xen-netback/interface.c | 23 +++++--- drivers/net/xen-netback/netback.c | 8 +++ drivers/net/xen-netback/xenbus.c | 101 +++++++++++++++++++++++++++++++----- 4 files changed, 116 insertions(+), 18 deletions(-) (limited to 'drivers/net/xen-netback/xenbus.c') diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index b6885cfcc7d..4dd7c4a1923 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -237,6 +237,7 @@ struct xenvif *xenvif_alloc(struct device *parent, unsigned int handle); int xenvif_init_queue(struct xenvif_queue *queue); +void xenvif_deinit_queue(struct xenvif_queue *queue); int xenvif_connect(struct xenvif_queue *queue, unsigned long tx_ring_ref, unsigned long rx_ring_ref, unsigned int tx_evtchn, @@ -299,5 +300,6 @@ extern bool separate_tx_rx_irq; extern unsigned int rx_drain_timeout_msecs; extern unsigned int rx_drain_timeout_jiffies; +extern unsigned int xenvif_max_queues; #endif /* __XEN_NETBACK__COMMON_H__ */ diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 6005b5d1d40..6929bcb61cf 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -139,7 +139,6 @@ static void xenvif_wake_queue_callback(unsigned long data) static u16 xenvif_select_queue(struct net_device *dev, struct sk_buff *skb, void *accel_priv, select_queue_fallback_t fallback) { - struct xenvif *vif = netdev_priv(dev); unsigned int num_queues = dev->real_num_tx_queues; u32 hash; u16 queue_index; @@ -436,7 +435,12 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, char name[IFNAMSIZ] = {}; snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle); - dev = alloc_netdev_mq(sizeof(struct xenvif), name, ether_setup, 1); + /* Allocate a netdev with the max. supported number of queues. + * When the guest selects the desired number, it will be updated + * via netif_set_real_num_tx_queues(). + */ + dev = alloc_netdev_mq(sizeof(struct xenvif), name, ether_setup, + xenvif_max_queues); if (dev == NULL) { pr_warn("Could not allocate netdev for %s\n", name); return ERR_PTR(-ENOMEM); @@ -706,6 +710,16 @@ void xenvif_disconnect(struct xenvif *vif) } } +/* Reverse the relevant parts of xenvif_init_queue(). + * Used for queue teardown from xenvif_free(), and on the + * error handling paths in xenbus.c:connect(). + */ +void xenvif_deinit_queue(struct xenvif_queue *queue) +{ + free_xenballooned_pages(MAX_PENDING_REQS, queue->mmap_pages); + netif_napi_del(&queue->napi); +} + void xenvif_free(struct xenvif *vif) { struct xenvif_queue *queue = NULL; @@ -729,11 +743,8 @@ void xenvif_free(struct xenvif *vif) for (queue_index = 0; queue_index < num_queues; ++queue_index) { queue = &vif->queues[queue_index]; - xenvif_wait_unmap_timeout(queue, worst_case_skb_lifetime); - free_xenballooned_pages(MAX_PENDING_REQS, queue->mmap_pages); - - netif_napi_del(&queue->napi); + xenvif_deinit_queue(queue); } /* Free the array of queues. The call below does not require diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index a5484e8cb06..49efff9b99f 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -62,6 +62,11 @@ unsigned int rx_drain_timeout_msecs = 10000; module_param(rx_drain_timeout_msecs, uint, 0444); unsigned int rx_drain_timeout_jiffies; +unsigned int xenvif_max_queues; +module_param_named(max_queues, xenvif_max_queues, uint, 0644); +MODULE_PARM_DESC(max_queues, + "Maximum number of queues per virtual interface"); + /* * This is the maximum slots a skb can have. If a guest sends a skb * which exceeds this limit it is considered malicious. @@ -1953,6 +1958,9 @@ static int __init netback_init(void) if (!xen_domain()) return -ENODEV; + /* Allow as many queues as there are CPUs, by default */ + xenvif_max_queues = num_online_cpus(); + if (fatal_skb_slots < XEN_NETBK_LEGACY_SLOTS_MAX) { pr_info("fatal_skb_slots too small (%d), bump it to XEN_NETBK_LEGACY_SLOTS_MAX (%d)\n", fatal_skb_slots, XEN_NETBK_LEGACY_SLOTS_MAX); diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 358602f55af..96c63dc2509 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -160,6 +160,12 @@ static int netback_probe(struct xenbus_device *dev, if (err) pr_debug("Error writing feature-split-event-channels\n"); + /* Multi-queue support: This is an optional feature. */ + err = xenbus_printf(XBT_NIL, dev->nodename, + "multi-queue-max-queues", "%u", xenvif_max_queues); + if (err) + pr_debug("Error writing multi-queue-max-queues\n"); + err = xenbus_switch_state(dev, XenbusStateInitWait); if (err) goto fail; @@ -490,9 +496,25 @@ static void connect(struct backend_info *be) struct xenbus_device *dev = be->dev; unsigned long credit_bytes, credit_usec; unsigned int queue_index; - unsigned int requested_num_queues = 1; + unsigned int requested_num_queues; struct xenvif_queue *queue; + /* Check whether the frontend requested multiple queues + * and read the number requested. + */ + err = xenbus_scanf(XBT_NIL, dev->otherend, + "multi-queue-num-queues", + "%u", &requested_num_queues); + if (err < 0) { + requested_num_queues = 1; /* Fall back to single queue */ + } else if (requested_num_queues > xenvif_max_queues) { + /* buggy or malicious guest */ + xenbus_dev_fatal(dev, err, + "guest requested %u queues, exceeding the maximum of %u.", + requested_num_queues, xenvif_max_queues); + return; + } + err = xen_net_read_mac(dev, be->vif->fe_dev_addr); if (err) { xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename); @@ -502,6 +524,7 @@ static void connect(struct backend_info *be) xen_net_read_rate(dev, &credit_bytes, &credit_usec); read_xenbus_vif_flags(be); + /* Use the number of queues requested by the frontend */ be->vif->queues = vzalloc(requested_num_queues * sizeof(struct xenvif_queue)); rtnl_lock(); @@ -516,14 +539,33 @@ static void connect(struct backend_info *be) be->vif->dev->name, queue->id); err = xenvif_init_queue(queue); - if (err) + if (err) { + /* xenvif_init_queue() cleans up after itself on + * failure, but we need to clean up any previously + * initialised queues. Set num_queues to i so that + * earlier queues can be destroyed using the regular + * disconnect logic. + */ + rtnl_lock(); + netif_set_real_num_tx_queues(be->vif->dev, queue_index); + rtnl_unlock(); goto err; + } queue->remaining_credit = credit_bytes; err = connect_rings(be, queue); - if (err) + if (err) { + /* connect_rings() cleans up after itself on failure, + * but we need to clean up after xenvif_init_queue() here, + * and also clean up any previously initialised queues. + */ + xenvif_deinit_queue(queue); + rtnl_lock(); + netif_set_real_num_tx_queues(be->vif->dev, queue_index); + rtnl_unlock(); goto err; + } } xenvif_carrier_on(be->vif); @@ -540,6 +582,8 @@ static void connect(struct backend_info *be) return; err: + if (be->vif->dev->real_num_tx_queues > 0) + xenvif_disconnect(be->vif); /* Clean up existing queues */ vfree(be->vif->queues); be->vif->queues = NULL; rtnl_lock(); @@ -552,32 +596,62 @@ err: static int connect_rings(struct backend_info *be, struct xenvif_queue *queue) { struct xenbus_device *dev = be->dev; + unsigned int num_queues = queue->vif->dev->real_num_tx_queues; unsigned long tx_ring_ref, rx_ring_ref; unsigned int tx_evtchn, rx_evtchn; int err; + char *xspath; + size_t xspathsize; + const size_t xenstore_path_ext_size = 11; /* sufficient for "/queue-NNN" */ + + /* If the frontend requested 1 queue, or we have fallen back + * to single queue due to lack of frontend support for multi- + * queue, expect the remaining XenStore keys in the toplevel + * directory. Otherwise, expect them in a subdirectory called + * queue-N. + */ + if (num_queues == 1) { + xspath = kzalloc(strlen(dev->otherend) + 1, GFP_KERNEL); + if (!xspath) { + xenbus_dev_fatal(dev, -ENOMEM, + "reading ring references"); + return -ENOMEM; + } + strcpy(xspath, dev->otherend); + } else { + xspathsize = strlen(dev->otherend) + xenstore_path_ext_size; + xspath = kzalloc(xspathsize, GFP_KERNEL); + if (!xspath) { + xenbus_dev_fatal(dev, -ENOMEM, + "reading ring references"); + return -ENOMEM; + } + snprintf(xspath, xspathsize, "%s/queue-%u", dev->otherend, + queue->id); + } - err = xenbus_gather(XBT_NIL, dev->otherend, + err = xenbus_gather(XBT_NIL, xspath, "tx-ring-ref", "%lu", &tx_ring_ref, "rx-ring-ref", "%lu", &rx_ring_ref, NULL); if (err) { xenbus_dev_fatal(dev, err, "reading %s/ring-ref", - dev->otherend); - return err; + xspath); + goto err; } /* Try split event channels first, then single event channel. */ - err = xenbus_gather(XBT_NIL, dev->otherend, + err = xenbus_gather(XBT_NIL, xspath, "event-channel-tx", "%u", &tx_evtchn, "event-channel-rx", "%u", &rx_evtchn, NULL); if (err < 0) { - err = xenbus_scanf(XBT_NIL, dev->otherend, + err = xenbus_scanf(XBT_NIL, xspath, "event-channel", "%u", &tx_evtchn); if (err < 0) { xenbus_dev_fatal(dev, err, "reading %s/event-channel(-tx/rx)", - dev->otherend); - return err; + xspath); + goto err; } rx_evtchn = tx_evtchn; } @@ -590,10 +664,13 @@ static int connect_rings(struct backend_info *be, struct xenvif_queue *queue) "mapping shared-frames %lu/%lu port tx %u rx %u", tx_ring_ref, rx_ring_ref, tx_evtchn, rx_evtchn); - return err; + goto err; } - return 0; + err = 0; +err: /* Regular return falls through with err == 0 */ + kfree(xspath); + return err; } static int read_xenbus_vif_flags(struct backend_info *be) -- cgit v1.2.3-70-g09d2 From f7b50c4e7ced702d80d3b873d81a2cdafb580f13 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Mon, 23 Jun 2014 10:50:17 +0100 Subject: xen-netback: bookkeep number of active queues in our own module The original code uses netdev->real_num_tx_queues to bookkeep number of queues and invokes netif_set_real_num_tx_queues to set the number of queues. However, netif_set_real_num_tx_queues doesn't allow real_num_tx_queues to be smaller than 1, which means setting the number to 0 will not work and real_num_tx_queues is untouched. This is bogus when xenvif_free is invoked before any number of queues is allocated. That function needs to iterate through all queues to free resources. Using the wrong number of queues results in NULL pointer dereference. So we bookkeep the number of queues in xen-netback to solve this problem. This fixes a regression introduced by multiqueue patchset in 3.16-rc1. There's another bug in original code that the real number of RX queues is never set. In current Xen multiqueue design, the number of TX queues and RX queues are in fact the same. We need to set the numbers of TX and RX queues to the same value. Also remove xenvif_select_queue and leave queue selection to core driver, as suggested by David Miller. Reported-by: Boris Ostrovsky Signed-off-by: Wei Liu CC: Ian Campbell CC: Paul Durrant Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 1 + drivers/net/xen-netback/interface.c | 49 +++++++++---------------------------- drivers/net/xen-netback/xenbus.c | 28 ++++++++++----------- 3 files changed, 26 insertions(+), 52 deletions(-) (limited to 'drivers/net/xen-netback/xenbus.c') diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 4dd7c4a1923..2532ce85d71 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -222,6 +222,7 @@ struct xenvif { /* Queues */ struct xenvif_queue *queues; + unsigned int num_queues; /* active queues, resource allocated */ /* Miscellaneous private stuff. */ struct net_device *dev; diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 852da34b896..9e97c7ca0dd 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -137,32 +137,11 @@ static void xenvif_wake_queue_callback(unsigned long data) } } -static u16 xenvif_select_queue(struct net_device *dev, struct sk_buff *skb, - void *accel_priv, select_queue_fallback_t fallback) -{ - unsigned int num_queues = dev->real_num_tx_queues; - u32 hash; - u16 queue_index; - - /* First, check if there is only one queue to optimise the - * single-queue or old frontend scenario. - */ - if (num_queues == 1) { - queue_index = 0; - } else { - /* Use skb_get_hash to obtain an L4 hash if available */ - hash = skb_get_hash(skb); - queue_index = hash % num_queues; - } - - return queue_index; -} - static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct xenvif *vif = netdev_priv(dev); struct xenvif_queue *queue = NULL; - unsigned int num_queues = dev->real_num_tx_queues; + unsigned int num_queues = vif->num_queues; u16 index; int min_slots_needed; @@ -225,7 +204,7 @@ static struct net_device_stats *xenvif_get_stats(struct net_device *dev) { struct xenvif *vif = netdev_priv(dev); struct xenvif_queue *queue = NULL; - unsigned int num_queues = dev->real_num_tx_queues; + unsigned int num_queues = vif->num_queues; unsigned long rx_bytes = 0; unsigned long rx_packets = 0; unsigned long tx_bytes = 0; @@ -256,7 +235,7 @@ out: static void xenvif_up(struct xenvif *vif) { struct xenvif_queue *queue = NULL; - unsigned int num_queues = vif->dev->real_num_tx_queues; + unsigned int num_queues = vif->num_queues; unsigned int queue_index; for (queue_index = 0; queue_index < num_queues; ++queue_index) { @@ -272,7 +251,7 @@ static void xenvif_up(struct xenvif *vif) static void xenvif_down(struct xenvif *vif) { struct xenvif_queue *queue = NULL; - unsigned int num_queues = vif->dev->real_num_tx_queues; + unsigned int num_queues = vif->num_queues; unsigned int queue_index; for (queue_index = 0; queue_index < num_queues; ++queue_index) { @@ -379,7 +358,7 @@ static void xenvif_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 * data) { struct xenvif *vif = netdev_priv(dev); - unsigned int num_queues = dev->real_num_tx_queues; + unsigned int num_queues = vif->num_queues; int i; unsigned int queue_index; struct xenvif_stats *vif_stats; @@ -424,7 +403,6 @@ static const struct net_device_ops xenvif_netdev_ops = { .ndo_fix_features = xenvif_fix_features, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, - .ndo_select_queue = xenvif_select_queue, }; struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, @@ -438,7 +416,7 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle); /* Allocate a netdev with the max. supported number of queues. * When the guest selects the desired number, it will be updated - * via netif_set_real_num_tx_queues(). + * via netif_set_real_num_*_queues(). */ dev = alloc_netdev_mq(sizeof(struct xenvif), name, ether_setup, xenvif_max_queues); @@ -458,11 +436,9 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, vif->dev = dev; vif->disabled = false; - /* Start out with no queues. The call below does not require - * rtnl_lock() as it happens before register_netdev(). - */ + /* Start out with no queues. */ vif->queues = NULL; - netif_set_real_num_tx_queues(dev, 0); + vif->num_queues = 0; dev->netdev_ops = &xenvif_netdev_ops; dev->hw_features = NETIF_F_SG | @@ -677,7 +653,7 @@ static void xenvif_wait_unmap_timeout(struct xenvif_queue *queue, void xenvif_disconnect(struct xenvif *vif) { struct xenvif_queue *queue = NULL; - unsigned int num_queues = vif->dev->real_num_tx_queues; + unsigned int num_queues = vif->num_queues; unsigned int queue_index; if (netif_carrier_ok(vif->dev)) @@ -724,7 +700,7 @@ void xenvif_deinit_queue(struct xenvif_queue *queue) void xenvif_free(struct xenvif *vif) { struct xenvif_queue *queue = NULL; - unsigned int num_queues = vif->dev->real_num_tx_queues; + unsigned int num_queues = vif->num_queues; unsigned int queue_index; /* Here we want to avoid timeout messages if an skb can be legitimately * stuck somewhere else. Realistically this could be an another vif's @@ -748,12 +724,9 @@ void xenvif_free(struct xenvif *vif) xenvif_deinit_queue(queue); } - /* Free the array of queues. The call below does not require - * rtnl_lock() because it happens after unregister_netdev(). - */ - netif_set_real_num_tx_queues(vif->dev, 0); vfree(vif->queues); vif->queues = NULL; + vif->num_queues = 0; free_netdev(vif->dev); diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 96c63dc2509..3d85acd84ba 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -527,9 +527,7 @@ static void connect(struct backend_info *be) /* Use the number of queues requested by the frontend */ be->vif->queues = vzalloc(requested_num_queues * sizeof(struct xenvif_queue)); - rtnl_lock(); - netif_set_real_num_tx_queues(be->vif->dev, requested_num_queues); - rtnl_unlock(); + be->vif->num_queues = requested_num_queues; for (queue_index = 0; queue_index < requested_num_queues; ++queue_index) { queue = &be->vif->queues[queue_index]; @@ -546,9 +544,7 @@ static void connect(struct backend_info *be) * earlier queues can be destroyed using the regular * disconnect logic. */ - rtnl_lock(); - netif_set_real_num_tx_queues(be->vif->dev, queue_index); - rtnl_unlock(); + be->vif->num_queues = queue_index; goto err; } @@ -561,13 +557,19 @@ static void connect(struct backend_info *be) * and also clean up any previously initialised queues. */ xenvif_deinit_queue(queue); - rtnl_lock(); - netif_set_real_num_tx_queues(be->vif->dev, queue_index); - rtnl_unlock(); + be->vif->num_queues = queue_index; goto err; } } + /* Initialisation completed, tell core driver the number of + * active queues. + */ + rtnl_lock(); + netif_set_real_num_tx_queues(be->vif->dev, requested_num_queues); + netif_set_real_num_rx_queues(be->vif->dev, requested_num_queues); + rtnl_unlock(); + xenvif_carrier_on(be->vif); unregister_hotplug_status_watch(be); @@ -582,13 +584,11 @@ static void connect(struct backend_info *be) return; err: - if (be->vif->dev->real_num_tx_queues > 0) + if (be->vif->num_queues > 0) xenvif_disconnect(be->vif); /* Clean up existing queues */ vfree(be->vif->queues); be->vif->queues = NULL; - rtnl_lock(); - netif_set_real_num_tx_queues(be->vif->dev, 0); - rtnl_unlock(); + be->vif->num_queues = 0; return; } @@ -596,7 +596,7 @@ err: static int connect_rings(struct backend_info *be, struct xenvif_queue *queue) { struct xenbus_device *dev = be->dev; - unsigned int num_queues = queue->vif->dev->real_num_tx_queues; + unsigned int num_queues = queue->vif->num_queues; unsigned long tx_ring_ref, rx_ring_ref; unsigned int tx_evtchn, rx_evtchn; int err; -- cgit v1.2.3-70-g09d2