diff options
Diffstat (limited to 'drivers/net/xen-netback')
| -rw-r--r-- | drivers/net/xen-netback/common.h | 8 | ||||
| -rw-r--r-- | drivers/net/xen-netback/hash.c | 2 | ||||
| -rw-r--r-- | drivers/net/xen-netback/interface.c | 40 | ||||
| -rw-r--r-- | drivers/net/xen-netback/netback.c | 8 | ||||
| -rw-r--r-- | drivers/net/xen-netback/xenbus.c | 102 | 
5 files changed, 87 insertions, 73 deletions
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 3ce1f7da8647..530586be05b4 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -113,10 +113,10 @@ struct xenvif_stats {  	 * A subset of struct net_device_stats that contains only the  	 * fields that are updated in netback.c for each queue.  	 */ -	unsigned int rx_bytes; -	unsigned int rx_packets; -	unsigned int tx_bytes; -	unsigned int tx_packets; +	u64 rx_bytes; +	u64 rx_packets; +	u64 tx_bytes; +	u64 tx_packets;  	/* Additional stats used by xenvif */  	unsigned long rx_gso_checksum_fixup; diff --git a/drivers/net/xen-netback/hash.c b/drivers/net/xen-netback/hash.c index e8c5dddc54ba..3c4c58b9fe76 100644 --- a/drivers/net/xen-netback/hash.c +++ b/drivers/net/xen-netback/hash.c @@ -39,7 +39,7 @@ static void xenvif_add_hash(struct xenvif *vif, const u8 *tag,  	unsigned long flags;  	bool found; -	new = kmalloc(sizeof(*entry), GFP_KERNEL); +	new = kmalloc(sizeof(*entry), GFP_ATOMIC);  	if (!new)  		return; diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 74dc2bf71428..8397f6c92451 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -31,6 +31,7 @@  #include "common.h"  #include <linux/kthread.h> +#include <linux/sched/task.h>  #include <linux/ethtool.h>  #include <linux/rtnetlink.h>  #include <linux/if_vlan.h> @@ -104,7 +105,7 @@ static int xenvif_poll(struct napi_struct *napi, int budget)  	work_done = xenvif_tx_action(queue, budget);  	if (work_done < budget) { -		napi_complete(napi); +		napi_complete_done(napi, work_done);  		xenvif_napi_schedule_or_enable_events(queue);  	} @@ -164,13 +165,17 @@ 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 = vif->num_queues; +	unsigned int num_queues;  	u16 index;  	struct xenvif_rx_cb *cb;  	BUG_ON(skb->dev != dev); -	/* Drop the packet if queues are not set up */ +	/* Drop the packet if queues are not set up. +	 * This handler should be called inside an RCU read section +	 * so we don't need to enter it here explicitly. +	 */ +	num_queues = READ_ONCE(vif->num_queues);  	if (num_queues < 1)  		goto drop; @@ -221,15 +226,15 @@ 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 = vif->num_queues; -	unsigned long rx_bytes = 0; -	unsigned long rx_packets = 0; -	unsigned long tx_bytes = 0; -	unsigned long tx_packets = 0; +	unsigned int num_queues; +	u64 rx_bytes = 0; +	u64 rx_packets = 0; +	u64 tx_bytes = 0; +	u64 tx_packets = 0;  	unsigned int index; -	if (vif->queues == NULL) -		goto out; +	rcu_read_lock(); +	num_queues = READ_ONCE(vif->num_queues);  	/* Aggregate tx and rx stats from each queue */  	for (index = 0; index < num_queues; ++index) { @@ -240,7 +245,8 @@ static struct net_device_stats *xenvif_get_stats(struct net_device *dev)  		tx_packets += queue->stats.tx_packets;  	} -out: +	rcu_read_unlock(); +  	vif->dev->stats.rx_bytes = rx_bytes;  	vif->dev->stats.rx_packets = rx_packets;  	vif->dev->stats.tx_bytes = tx_bytes; @@ -302,7 +308,7 @@ static int xenvif_close(struct net_device *dev)  static int xenvif_change_mtu(struct net_device *dev, int mtu)  {  	struct xenvif *vif = netdev_priv(dev); -	int max = vif->can_sg ? 65535 - VLAN_ETH_HLEN : ETH_DATA_LEN; +	int max = vif->can_sg ? ETH_MAX_MTU - VLAN_ETH_HLEN : ETH_DATA_LEN;  	if (mtu > max)  		return -EINVAL; @@ -375,10 +381,13 @@ 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 = vif->num_queues; +	unsigned int num_queues;  	int i;  	unsigned int queue_index; +	rcu_read_lock(); +	num_queues = READ_ONCE(vif->num_queues); +  	for (i = 0; i < ARRAY_SIZE(xenvif_stats); i++) {  		unsigned long accum = 0;  		for (queue_index = 0; queue_index < num_queues; ++queue_index) { @@ -387,6 +396,8 @@ static void xenvif_get_ethtool_stats(struct net_device *dev,  		}  		data[i] = accum;  	} + +	rcu_read_unlock();  }  static void xenvif_get_strings(struct net_device *dev, u32 stringset, u8 * data) @@ -471,6 +482,9 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,  	dev->tx_queue_len = XENVIF_QUEUE_LENGTH; +	dev->min_mtu = 0; +	dev->max_mtu = ETH_MAX_MTU - VLAN_ETH_HLEN; +  	/*  	 * Initialise a dummy MAC address. We choose the numerically  	 * largest non-broadcast address to prevent the address getting diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 47b481095d77..602d408fa25e 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -67,6 +67,7 @@ module_param(rx_drain_timeout_msecs, uint, 0444);  unsigned int rx_stall_timeout_msecs = 60000;  module_param(rx_stall_timeout_msecs, uint, 0444); +#define MAX_QUEUES_DEFAULT 8  unsigned int xenvif_max_queues;  module_param_named(max_queues, xenvif_max_queues, uint, 0644);  MODULE_PARM_DESC(max_queues, @@ -213,7 +214,7 @@ static void xenvif_fatal_tx_err(struct xenvif *vif)  	netdev_err(vif->dev, "fatal error; disabling device\n");  	vif->disabled = true;  	/* Disable the vif from queue 0's kthread */ -	if (vif->queues) +	if (vif->num_queues)  		xenvif_kick_thread(&vif->queues[0]);  } @@ -1622,11 +1623,12 @@ static int __init netback_init(void)  	if (!xen_domain())  		return -ENODEV; -	/* Allow as many queues as there are CPUs if user has not +	/* Allow as many queues as there are CPUs but max. 8 if user has not  	 * specified a value.  	 */  	if (xenvif_max_queues == 0) -		xenvif_max_queues = num_online_cpus(); +		xenvif_max_queues = min_t(unsigned int, MAX_QUEUES_DEFAULT, +					  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", diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 8674e188b697..a56d3eab35dd 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -492,13 +492,31 @@ static int backend_create_xenvif(struct backend_info *be)  static void backend_disconnect(struct backend_info *be)  { -	if (be->vif) { -		xen_unregister_watchers(be->vif); +	struct xenvif *vif = be->vif; + +	if (vif) { +		unsigned int num_queues = vif->num_queues; +		unsigned int queue_index; + +		xen_unregister_watchers(vif);  #ifdef CONFIG_DEBUG_FS -		xenvif_debugfs_delif(be->vif); +		xenvif_debugfs_delif(vif);  #endif /* CONFIG_DEBUG_FS */ -		xenvif_disconnect_data(be->vif); -		xenvif_disconnect_ctrl(be->vif); +		xenvif_disconnect_data(vif); + +		/* At this point some of the handlers may still be active +		 * so we need to have additional synchronization here. +		 */ +		vif->num_queues = 0; +		synchronize_net(); + +		for (queue_index = 0; queue_index < num_queues; ++queue_index) +			xenvif_deinit_queue(&vif->queues[queue_index]); + +		vfree(vif->queues); +		vif->queues = NULL; + +		xenvif_disconnect_ctrl(vif);  	}  } @@ -723,7 +741,7 @@ static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])  }  static void xen_net_rate_changed(struct xenbus_watch *watch, -				const char **vec, unsigned int len) +				 const char *path, const char *token)  {  	struct xenvif *vif = container_of(watch, struct xenvif, credit_watch);  	struct xenbus_device *dev = xenvif_to_xenbus_device(vif); @@ -780,17 +798,14 @@ static void xen_unregister_credit_watch(struct xenvif *vif)  }  static void xen_mcast_ctrl_changed(struct xenbus_watch *watch, -				   const char **vec, unsigned int len) +				   const char *path, const char *token)  {  	struct xenvif *vif = container_of(watch, struct xenvif,  					  mcast_ctrl_watch);  	struct xenbus_device *dev = xenvif_to_xenbus_device(vif); -	int val; -	if (xenbus_scanf(XBT_NIL, dev->otherend, -			 "request-multicast-control", "%d", &val) < 0) -		val = 0; -	vif->multicast_control = !!val; +	vif->multicast_control = !!xenbus_read_unsigned(dev->otherend, +					"request-multicast-control", 0);  }  static int xen_register_mcast_ctrl_watch(struct xenbus_device *dev, @@ -858,8 +873,8 @@ static void unregister_hotplug_status_watch(struct backend_info *be)  }  static void hotplug_status_changed(struct xenbus_watch *watch, -				   const char **vec, -				   unsigned int vec_size) +				   const char *path, +				   const char *token)  {  	struct backend_info *be = container_of(watch,  					       struct backend_info, @@ -889,16 +904,16 @@ static int connect_ctrl_ring(struct backend_info *be)  	unsigned int evtchn;  	int err; -	err = xenbus_gather(XBT_NIL, dev->otherend, -			    "ctrl-ring-ref", "%u", &val, NULL); -	if (err) +	err = xenbus_scanf(XBT_NIL, dev->otherend, +			   "ctrl-ring-ref", "%u", &val); +	if (err < 0)  		goto done; /* The frontend does not have a control ring */  	ring_ref = val; -	err = xenbus_gather(XBT_NIL, dev->otherend, -			    "event-channel-ctrl", "%u", &val, NULL); -	if (err) { +	err = xenbus_scanf(XBT_NIL, dev->otherend, +			   "event-channel-ctrl", "%u", &val); +	if (err < 0) {  		xenbus_dev_fatal(dev, err,  				 "reading %s/event-channel-ctrl",  				 dev->otherend); @@ -934,14 +949,11 @@ static void connect(struct backend_info *be)  	/* 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) { +	requested_num_queues = xenbus_read_unsigned(dev->otherend, +					"multi-queue-num-queues", 1); +	if (requested_num_queues > xenvif_max_queues) {  		/* buggy or malicious guest */ -		xenbus_dev_fatal(dev, err, +		xenbus_dev_fatal(dev, -EINVAL,  				 "guest requested %u queues, exceeding the maximum of %u.",  				 requested_num_queues, xenvif_max_queues);  		return; @@ -1040,6 +1052,8 @@ static void connect(struct backend_info *be)  err:  	if (be->vif->num_queues > 0)  		xenvif_disconnect_data(be->vif); /* Clean up existing queues */ +	for (queue_index = 0; queue_index < be->vif->num_queues; ++queue_index) +		xenvif_deinit_queue(&be->vif->queues[queue_index]);  	vfree(be->vif->queues);  	be->vif->queues = NULL;  	be->vif->num_queues = 0; @@ -1134,7 +1148,7 @@ 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; +	int err;  	err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy", "%u",  			   &rx_copy); @@ -1150,10 +1164,7 @@ static int read_xenbus_vif_flags(struct backend_info *be)  	if (!rx_copy)  		return -EOPNOTSUPP; -	if (xenbus_scanf(XBT_NIL, dev->otherend, -			 "feature-rx-notify", "%d", &val) < 0) -		val = 0; -	if (!val) { +	if (!xenbus_read_unsigned(dev->otherend, "feature-rx-notify", 0)) {  		/* - Reduce drain timeout to poll more frequently for  		 *   Rx requests.  		 * - Disable Rx stall detection. @@ -1162,34 +1173,21 @@ static int read_xenbus_vif_flags(struct backend_info *be)  		be->vif->stall_timeout = 0;  	} -	if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg", -			 "%d", &val) < 0) -		val = 0; -	vif->can_sg = !!val; +	vif->can_sg = !!xenbus_read_unsigned(dev->otherend, "feature-sg", 0);  	vif->gso_mask = 0; -	if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4", -			 "%d", &val) < 0) -		val = 0; -	if (val) +	if (xenbus_read_unsigned(dev->otherend, "feature-gso-tcpv4", 0))  		vif->gso_mask |= GSO_BIT(TCPV4); -	if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv6", -			 "%d", &val) < 0) -		val = 0; -	if (val) +	if (xenbus_read_unsigned(dev->otherend, "feature-gso-tcpv6", 0))  		vif->gso_mask |= GSO_BIT(TCPV6); -	if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload", -			 "%d", &val) < 0) -		val = 0; -	vif->ip_csum = !val; +	vif->ip_csum = !xenbus_read_unsigned(dev->otherend, +					     "feature-no-csum-offload", 0); -	if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-ipv6-csum-offload", -			 "%d", &val) < 0) -		val = 0; -	vif->ipv6_csum = !!val; +	vif->ipv6_csum = !!xenbus_read_unsigned(dev->otherend, +						"feature-ipv6-csum-offload", 0);  	return 0;  }  | 

