xen-netback: don’t populate the hash cache on XenBus disconnect [Linux 5.0]

This Linux kernel change "xen-netback: don’t populate the hash cache on XenBus disconnect" is included in the Linux 5.0 release. This change is authored by Igor Druzhinin <igor.druzhinin [at] citrix.com> on Thu Feb 28 14:11:26 2019 +0000. The commit for this change in Linux stable tree is a2288d4 (patch).

xen-netback: don't populate the hash cache on XenBus disconnect

Occasionally, during the disconnection procedure on XenBus which
includes hash cache deinitialization there might be some packets
still in-flight on other processors. Handling of these packets includes
hashing and hash cache population that finally results in hash cache
data structure corruption.

In order to avoid this we prevent hashing of those packets if there
are no queues initialized. In that case RCU protection of queues guards
the hash cache as well.

Signed-off-by: Igor Druzhinin <[email protected]>
Reviewed-by: Paul Durrant <[email protected]>
Signed-off-by: David S. Miller <[email protected]>

There are 9 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/net/xen-netback/hash.c      | 2 ++
 drivers/net/xen-netback/interface.c | 7 +++++++
 2 files changed, 9 insertions(+)

diff --git a/drivers/net/xen-netback/hash.c b/drivers/net/xen-netback/hash.c
index 0ccb021..10d580c 100644
--- a/drivers/net/xen-netback/hash.c
+++ b/drivers/net/xen-netback/hash.c
@@ -454,6 +454,8 @@ void xenvif_init_hash(struct xenvif *vif)
    if (xenvif_hash_cache_size == 0)
        return;

+   BUG_ON(vif->hash.cache.count);
+
    spin_lock_init(&vif->hash.cache.lock);
    INIT_LIST_HEAD(&vif->hash.cache.list);
 }
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index 182d677..6da1251 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -153,6 +153,13 @@ static u16 xenvif_select_queue(struct net_device *dev, struct sk_buff *skb,
 {
    struct xenvif *vif = netdev_priv(dev);
    unsigned int size = vif->hash.size;
+   unsigned int num_queues;
+
+   /* If queues are not set up internally - always return 0
+    * as the packet going to be dropped anyway */
+   num_queues = READ_ONCE(vif->num_queues);
+   if (num_queues < 1)
+       return 0;

    if (vif->hash.alg == XEN_NETIF_CTRL_HASH_ALGORITHM_NONE)
        return fallback(dev, skb, NULL) % dev->real_num_tx_queues;

Leave a Reply

Your email address will not be published. Required fields are marked *