commit:     215deabf1be5d79b5db37aee287bca795cf0805d
Author:     Alice Ferrazzi <alicef <AT> gentoo <DOT> org>
AuthorDate: Tue Nov 15 07:58:39 2016 +0000
Commit:     Alice Ferrazzi <alicef <AT> gentoo <DOT> org>
CommitDate: Tue Nov 15 07:58:39 2016 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=215deabf

Linux patch 4.8.8

 0000_README            |    4 +
 1007_linux-4.8.8.patch | 1846 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1850 insertions(+)

diff --git a/0000_README b/0000_README
index 9cd8633..236529a 100644
--- a/0000_README
+++ b/0000_README
@@ -71,6 +71,10 @@ Patch:  1006_linux-4.8.7.patch
 From:   http://www.kernel.org
 Desc:   Linux 4.8.7
 
+Patch:  1007_linux-4.8.8.patch
+From:   http://www.kernel.org
+Desc:   Linux 4.8.8
+
 Patch:  1500_XATTR_USER_PREFIX.patch
 From:   https://bugs.gentoo.org/show_bug.cgi?id=470644
 Desc:   Support for namespace user.pax.* on tmpfs.

diff --git a/1007_linux-4.8.8.patch b/1007_linux-4.8.8.patch
new file mode 100644
index 0000000..7f46629
--- /dev/null
+++ b/1007_linux-4.8.8.patch
@@ -0,0 +1,1846 @@
+diff --git a/Makefile b/Makefile
+index 4d0f28cb481d..8f18daa2c76a 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,6 +1,6 @@
+ VERSION = 4
+ PATCHLEVEL = 8
+-SUBLEVEL = 7
++SUBLEVEL = 8
+ EXTRAVERSION =
+ NAME = Psychotic Stoned Sheep
+ 
+diff --git a/arch/powerpc/include/asm/checksum.h 
b/arch/powerpc/include/asm/checksum.h
+index ee655ed1ff1b..1e8fceb308a5 100644
+--- a/arch/powerpc/include/asm/checksum.h
++++ b/arch/powerpc/include/asm/checksum.h
+@@ -53,10 +53,8 @@ static inline __sum16 csum_fold(__wsum sum)
+       return (__force __sum16)(~((__force u32)sum + tmp) >> 16);
+ }
+ 
+-static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
+-                                     unsigned short len,
+-                                     unsigned short proto,
+-                                     __wsum sum)
++static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len,
++                                      __u8 proto, __wsum sum)
+ {
+ #ifdef __powerpc64__
+       unsigned long s = (__force u32)sum;
+@@ -83,10 +81,8 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr, 
__be32 daddr,
+  * computes the checksum of the TCP/UDP pseudo-header
+  * returns a 16-bit checksum, already complemented
+  */
+-static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
+-                                      unsigned short len,
+-                                      unsigned short proto,
+-                                      __wsum sum)
++static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len,
++                                      __u8 proto, __wsum sum)
+ {
+       return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
+ }
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h 
b/drivers/infiniband/ulp/ipoib/ipoib.h
+index 9dbfcc0ab577..5ff64afd69f9 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib.h
++++ b/drivers/infiniband/ulp/ipoib/ipoib.h
+@@ -63,6 +63,8 @@ enum ipoib_flush_level {
+ 
+ enum {
+       IPOIB_ENCAP_LEN           = 4,
++      IPOIB_PSEUDO_LEN          = 20,
++      IPOIB_HARD_LEN            = IPOIB_ENCAP_LEN + IPOIB_PSEUDO_LEN,
+ 
+       IPOIB_UD_HEAD_SIZE        = IB_GRH_BYTES + IPOIB_ENCAP_LEN,
+       IPOIB_UD_RX_SG            = 2, /* max buffer needed for 4K mtu */
+@@ -134,15 +136,21 @@ struct ipoib_header {
+       u16     reserved;
+ };
+ 
+-struct ipoib_cb {
+-      struct qdisc_skb_cb     qdisc_cb;
+-      u8                      hwaddr[INFINIBAND_ALEN];
++struct ipoib_pseudo_header {
++      u8      hwaddr[INFINIBAND_ALEN];
+ };
+ 
+-static inline struct ipoib_cb *ipoib_skb_cb(const struct sk_buff *skb)
++static inline void skb_add_pseudo_hdr(struct sk_buff *skb)
+ {
+-      BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct ipoib_cb));
+-      return (struct ipoib_cb *)skb->cb;
++      char *data = skb_push(skb, IPOIB_PSEUDO_LEN);
++
++      /*
++       * only the ipoib header is present now, make room for a dummy
++       * pseudo header and set skb field accordingly
++       */
++      memset(data, 0, IPOIB_PSEUDO_LEN);
++      skb_reset_mac_header(skb);
++      skb_pull(skb, IPOIB_HARD_LEN);
+ }
+ 
+ /* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c 
b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+index 4ad297d3de89..339a1eecdfe3 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+@@ -63,6 +63,8 @@ MODULE_PARM_DESC(cm_data_debug_level,
+ #define IPOIB_CM_RX_DELAY       (3 * 256 * HZ)
+ #define IPOIB_CM_RX_UPDATE_MASK (0x3)
+ 
++#define IPOIB_CM_RX_RESERVE     (ALIGN(IPOIB_HARD_LEN, 16) - IPOIB_ENCAP_LEN)
++
+ static struct ib_qp_attr ipoib_cm_err_attr = {
+       .qp_state = IB_QPS_ERR
+ };
+@@ -146,15 +148,15 @@ static struct sk_buff *ipoib_cm_alloc_rx_skb(struct 
net_device *dev,
+       struct sk_buff *skb;
+       int i;
+ 
+-      skb = dev_alloc_skb(IPOIB_CM_HEAD_SIZE + 12);
++      skb = dev_alloc_skb(ALIGN(IPOIB_CM_HEAD_SIZE + IPOIB_PSEUDO_LEN, 16));
+       if (unlikely(!skb))
+               return NULL;
+ 
+       /*
+-       * IPoIB adds a 4 byte header. So we need 12 more bytes to align the
++       * IPoIB adds a IPOIB_ENCAP_LEN byte header, this will align the
+        * IP header to a multiple of 16.
+        */
+-      skb_reserve(skb, 12);
++      skb_reserve(skb, IPOIB_CM_RX_RESERVE);
+ 
+       mapping[0] = ib_dma_map_single(priv->ca, skb->data, IPOIB_CM_HEAD_SIZE,
+                                      DMA_FROM_DEVICE);
+@@ -624,9 +626,9 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct 
ib_wc *wc)
+       if (wc->byte_len < IPOIB_CM_COPYBREAK) {
+               int dlen = wc->byte_len;
+ 
+-              small_skb = dev_alloc_skb(dlen + 12);
++              small_skb = dev_alloc_skb(dlen + IPOIB_CM_RX_RESERVE);
+               if (small_skb) {
+-                      skb_reserve(small_skb, 12);
++                      skb_reserve(small_skb, IPOIB_CM_RX_RESERVE);
+                       ib_dma_sync_single_for_cpu(priv->ca, 
rx_ring[wr_id].mapping[0],
+                                                  dlen, DMA_FROM_DEVICE);
+                       skb_copy_from_linear_data(skb, small_skb->data, dlen);
+@@ -663,8 +665,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct 
ib_wc *wc)
+ 
+ copied:
+       skb->protocol = ((struct ipoib_header *) skb->data)->proto;
+-      skb_reset_mac_header(skb);
+-      skb_pull(skb, IPOIB_ENCAP_LEN);
++      skb_add_pseudo_hdr(skb);
+ 
+       ++dev->stats.rx_packets;
+       dev->stats.rx_bytes += skb->len;
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c 
b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+index be11d5d5b8c1..830fecb6934c 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+@@ -128,16 +128,15 @@ static struct sk_buff *ipoib_alloc_rx_skb(struct 
net_device *dev, int id)
+ 
+       buf_size = IPOIB_UD_BUF_SIZE(priv->max_ib_mtu);
+ 
+-      skb = dev_alloc_skb(buf_size + IPOIB_ENCAP_LEN);
++      skb = dev_alloc_skb(buf_size + IPOIB_HARD_LEN);
+       if (unlikely(!skb))
+               return NULL;
+ 
+       /*
+-       * IB will leave a 40 byte gap for a GRH and IPoIB adds a 4 byte
+-       * header.  So we need 4 more bytes to get to 48 and align the
+-       * IP header to a multiple of 16.
++       * the IP header will be at IPOIP_HARD_LEN + IB_GRH_BYTES, that is
++       * 64 bytes aligned
+        */
+-      skb_reserve(skb, 4);
++      skb_reserve(skb, sizeof(struct ipoib_pseudo_header));
+ 
+       mapping = priv->rx_ring[id].mapping;
+       mapping[0] = ib_dma_map_single(priv->ca, skb->data, buf_size,
+@@ -253,8 +252,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, 
struct ib_wc *wc)
+       skb_pull(skb, IB_GRH_BYTES);
+ 
+       skb->protocol = ((struct ipoib_header *) skb->data)->proto;
+-      skb_reset_mac_header(skb);
+-      skb_pull(skb, IPOIB_ENCAP_LEN);
++      skb_add_pseudo_hdr(skb);
+ 
+       ++dev->stats.rx_packets;
+       dev->stats.rx_bytes += skb->len;
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c 
b/drivers/infiniband/ulp/ipoib/ipoib_main.c
+index cc1c1b062ea5..823a528ef4eb 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
+@@ -925,9 +925,12 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,
+                               ipoib_neigh_free(neigh);
+                               goto err_drop;
+                       }
+-                      if (skb_queue_len(&neigh->queue) < 
IPOIB_MAX_PATH_REC_QUEUE)
++                      if (skb_queue_len(&neigh->queue) <
++                          IPOIB_MAX_PATH_REC_QUEUE) {
++                              /* put pseudoheader back on for next time */
++                              skb_push(skb, IPOIB_PSEUDO_LEN);
+                               __skb_queue_tail(&neigh->queue, skb);
+-                      else {
++                      } else {
+                               ipoib_warn(priv, "queue length limit %d. Packet 
drop.\n",
+                                          skb_queue_len(&neigh->queue));
+                               goto err_drop;
+@@ -964,7 +967,7 @@ err_drop:
+ }
+ 
+ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
+-                           struct ipoib_cb *cb)
++                           struct ipoib_pseudo_header *phdr)
+ {
+       struct ipoib_dev_priv *priv = netdev_priv(dev);
+       struct ipoib_path *path;
+@@ -972,16 +975,18 @@ static void unicast_arp_send(struct sk_buff *skb, struct 
net_device *dev,
+ 
+       spin_lock_irqsave(&priv->lock, flags);
+ 
+-      path = __path_find(dev, cb->hwaddr + 4);
++      path = __path_find(dev, phdr->hwaddr + 4);
+       if (!path || !path->valid) {
+               int new_path = 0;
+ 
+               if (!path) {
+-                      path = path_rec_create(dev, cb->hwaddr + 4);
++                      path = path_rec_create(dev, phdr->hwaddr + 4);
+                       new_path = 1;
+               }
+               if (path) {
+                       if (skb_queue_len(&path->queue) < 
IPOIB_MAX_PATH_REC_QUEUE) {
++                              /* put pseudoheader back on for next time */
++                              skb_push(skb, IPOIB_PSEUDO_LEN);
+                               __skb_queue_tail(&path->queue, skb);
+                       } else {
+                               ++dev->stats.tx_dropped;
+@@ -1009,10 +1014,12 @@ static void unicast_arp_send(struct sk_buff *skb, 
struct net_device *dev,
+                         be16_to_cpu(path->pathrec.dlid));
+ 
+               spin_unlock_irqrestore(&priv->lock, flags);
+-              ipoib_send(dev, skb, path->ah, IPOIB_QPN(cb->hwaddr));
++              ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr));
+               return;
+       } else if ((path->query || !path_rec_start(dev, path)) &&
+                  skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
++              /* put pseudoheader back on for next time */
++              skb_push(skb, IPOIB_PSEUDO_LEN);
+               __skb_queue_tail(&path->queue, skb);
+       } else {
+               ++dev->stats.tx_dropped;
+@@ -1026,13 +1033,15 @@ static int ipoib_start_xmit(struct sk_buff *skb, 
struct net_device *dev)
+ {
+       struct ipoib_dev_priv *priv = netdev_priv(dev);
+       struct ipoib_neigh *neigh;
+-      struct ipoib_cb *cb = ipoib_skb_cb(skb);
++      struct ipoib_pseudo_header *phdr;
+       struct ipoib_header *header;
+       unsigned long flags;
+ 
++      phdr = (struct ipoib_pseudo_header *) skb->data;
++      skb_pull(skb, sizeof(*phdr));
+       header = (struct ipoib_header *) skb->data;
+ 
+-      if (unlikely(cb->hwaddr[4] == 0xff)) {
++      if (unlikely(phdr->hwaddr[4] == 0xff)) {
+               /* multicast, arrange "if" according to probability */
+               if ((header->proto != htons(ETH_P_IP)) &&
+                   (header->proto != htons(ETH_P_IPV6)) &&
+@@ -1045,13 +1054,13 @@ static int ipoib_start_xmit(struct sk_buff *skb, 
struct net_device *dev)
+                       return NETDEV_TX_OK;
+               }
+               /* Add in the P_Key for multicast*/
+-              cb->hwaddr[8] = (priv->pkey >> 8) & 0xff;
+-              cb->hwaddr[9] = priv->pkey & 0xff;
++              phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff;
++              phdr->hwaddr[9] = priv->pkey & 0xff;
+ 
+-              neigh = ipoib_neigh_get(dev, cb->hwaddr);
++              neigh = ipoib_neigh_get(dev, phdr->hwaddr);
+               if (likely(neigh))
+                       goto send_using_neigh;
+-              ipoib_mcast_send(dev, cb->hwaddr, skb);
++              ipoib_mcast_send(dev, phdr->hwaddr, skb);
+               return NETDEV_TX_OK;
+       }
+ 
+@@ -1060,16 +1069,16 @@ static int ipoib_start_xmit(struct sk_buff *skb, 
struct net_device *dev)
+       case htons(ETH_P_IP):
+       case htons(ETH_P_IPV6):
+       case htons(ETH_P_TIPC):
+-              neigh = ipoib_neigh_get(dev, cb->hwaddr);
++              neigh = ipoib_neigh_get(dev, phdr->hwaddr);
+               if (unlikely(!neigh)) {
+-                      neigh_add_path(skb, cb->hwaddr, dev);
++                      neigh_add_path(skb, phdr->hwaddr, dev);
+                       return NETDEV_TX_OK;
+               }
+               break;
+       case htons(ETH_P_ARP):
+       case htons(ETH_P_RARP):
+               /* for unicast ARP and RARP should always perform path find */
+-              unicast_arp_send(skb, dev, cb);
++              unicast_arp_send(skb, dev, phdr);
+               return NETDEV_TX_OK;
+       default:
+               /* ethertype not supported by IPoIB */
+@@ -1086,11 +1095,13 @@ send_using_neigh:
+                       goto unref;
+               }
+       } else if (neigh->ah) {
+-              ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(cb->hwaddr));
++              ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(phdr->hwaddr));
+               goto unref;
+       }
+ 
+       if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
++              /* put pseudoheader back on for next time */
++              skb_push(skb, sizeof(*phdr));
+               spin_lock_irqsave(&priv->lock, flags);
+               __skb_queue_tail(&neigh->queue, skb);
+               spin_unlock_irqrestore(&priv->lock, flags);
+@@ -1122,8 +1133,8 @@ static int ipoib_hard_header(struct sk_buff *skb,
+                            unsigned short type,
+                            const void *daddr, const void *saddr, unsigned len)
+ {
++      struct ipoib_pseudo_header *phdr;
+       struct ipoib_header *header;
+-      struct ipoib_cb *cb = ipoib_skb_cb(skb);
+ 
+       header = (struct ipoib_header *) skb_push(skb, sizeof *header);
+ 
+@@ -1132,12 +1143,13 @@ static int ipoib_hard_header(struct sk_buff *skb,
+ 
+       /*
+        * we don't rely on dst_entry structure,  always stuff the
+-       * destination address into skb->cb so we can figure out where
++       * destination address into skb hard header so we can figure out where
+        * to send the packet later.
+        */
+-      memcpy(cb->hwaddr, daddr, INFINIBAND_ALEN);
++      phdr = (struct ipoib_pseudo_header *) skb_push(skb, sizeof(*phdr));
++      memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
+ 
+-      return sizeof *header;
++      return IPOIB_HARD_LEN;
+ }
+ 
+ static void ipoib_set_mcast_list(struct net_device *dev)
+@@ -1759,7 +1771,7 @@ void ipoib_setup(struct net_device *dev)
+ 
+       dev->flags              |= IFF_BROADCAST | IFF_MULTICAST;
+ 
+-      dev->hard_header_len     = IPOIB_ENCAP_LEN;
++      dev->hard_header_len     = IPOIB_HARD_LEN;
+       dev->addr_len            = INFINIBAND_ALEN;
+       dev->type                = ARPHRD_INFINIBAND;
+       dev->tx_queue_len        = ipoib_sendq_size * 2;
+diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c 
b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+index d3394b6add24..1909dd252c94 100644
+--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
++++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+@@ -796,9 +796,11 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, 
struct sk_buff *skb)
+                       __ipoib_mcast_add(dev, mcast);
+                       list_add_tail(&mcast->list, &priv->multicast_list);
+               }
+-              if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE)
++              if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE) {
++                      /* put pseudoheader back on for next time */
++                      skb_push(skb, sizeof(struct ipoib_pseudo_header));
+                       skb_queue_tail(&mcast->pkt_queue, skb);
+-              else {
++              } else {
+                       ++dev->stats.tx_dropped;
+                       dev_kfree_skb_any(skb);
+               }
+diff --git a/drivers/net/ethernet/freescale/fec_main.c 
b/drivers/net/ethernet/freescale/fec_main.c
+index 692ee248e486..3474de576dde 100644
+--- a/drivers/net/ethernet/freescale/fec_main.c
++++ b/drivers/net/ethernet/freescale/fec_main.c
+@@ -913,13 +913,11 @@ fec_restart(struct net_device *ndev)
+        * enet-mac reset will reset mac address registers too,
+        * so need to reconfigure it.
+        */
+-      if (fep->quirks & FEC_QUIRK_ENET_MAC) {
+-              memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN);
+-              writel((__force u32)cpu_to_be32(temp_mac[0]),
+-                     fep->hwp + FEC_ADDR_LOW);
+-              writel((__force u32)cpu_to_be32(temp_mac[1]),
+-                     fep->hwp + FEC_ADDR_HIGH);
+-      }
++      memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN);
++      writel((__force u32)cpu_to_be32(temp_mac[0]),
++             fep->hwp + FEC_ADDR_LOW);
++      writel((__force u32)cpu_to_be32(temp_mac[1]),
++             fep->hwp + FEC_ADDR_HIGH);
+ 
+       /* Clear any outstanding interrupt. */
+       writel(0xffffffff, fep->hwp + FEC_IEVENT);
+@@ -1432,14 +1430,14 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, 
u16 queue_id)
+               skb_put(skb, pkt_len - 4);
+               data = skb->data;
+ 
++              if (!is_copybreak && need_swap)
++                      swap_buffer(data, pkt_len);
++
+ #if !defined(CONFIG_M5272)
+               if (fep->quirks & FEC_QUIRK_HAS_RACC)
+                       data = skb_pull_inline(skb, 2);
+ #endif
+ 
+-              if (!is_copybreak && need_swap)
+-                      swap_buffer(data, pkt_len);
+-
+               /* Extract the enhanced buffer descriptor */
+               ebdp = NULL;
+               if (fep->bufdesc_ex)
+diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c 
b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
+index 132cea655920..e3be7e44ff51 100644
+--- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c
++++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
+@@ -127,7 +127,15 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct 
mlx4_en_cq *cq,
+               /* For TX we use the same irq per
+               ring we assigned for the RX    */
+               struct mlx4_en_cq *rx_cq;
+-
++              int xdp_index;
++
++              /* The xdp tx irq must align with the rx ring that forwards to
++               * it, so reindex these from 0. This should only happen when
++               * tx_ring_num is not a multiple of rx_ring_num.
++               */
++              xdp_index = (priv->xdp_ring_num - priv->tx_ring_num) + cq_idx;
++              if (xdp_index >= 0)
++                      cq_idx = xdp_index;
+               cq_idx = cq_idx % priv->rx_ring_num;
+               rx_cq = priv->rx_cq[cq_idx];
+               cq->vector = rx_cq->vector;
+diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
+index 3c20e87bb761..16af1ce99233 100644
+--- a/drivers/net/geneve.c
++++ b/drivers/net/geneve.c
+@@ -453,7 +453,7 @@ static struct sk_buff **geneve_gro_receive(struct sock *sk,
+ 
+       skb_gro_pull(skb, gh_len);
+       skb_gro_postpull_rcsum(skb, gh, gh_len);
+-      pp = ptype->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+       flush = 0;
+ 
+ out_unlock:
+diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
+index 3ba29fc80d05..c4d9653cae66 100644
+--- a/drivers/net/hyperv/netvsc_drv.c
++++ b/drivers/net/hyperv/netvsc_drv.c
+@@ -624,15 +624,18 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct 
net_device *net,
+              packet->total_data_buflen);
+ 
+       skb->protocol = eth_type_trans(skb, net);
+-      if (csum_info) {
+-              /* We only look at the IP checksum here.
+-               * Should we be dropping the packet if checksum
+-               * failed? How do we deal with other checksums - TCP/UDP?
+-               */
+-              if (csum_info->receive.ip_checksum_succeeded)
++
++      /* skb is already created with CHECKSUM_NONE */
++      skb_checksum_none_assert(skb);
++
++      /*
++       * In Linux, the IP checksum is always checked.
++       * Do L4 checksum offload if enabled and present.
++       */
++      if (csum_info && (net->features & NETIF_F_RXCSUM)) {
++              if (csum_info->receive.tcp_checksum_succeeded ||
++                  csum_info->receive.udp_checksum_succeeded)
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+-              else
+-                      skb->ip_summed = CHECKSUM_NONE;
+       }
+ 
+       if (vlan_tci & VLAN_TAG_PRESENT)
+diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
+index 351e701eb043..b72ddc61eff8 100644
+--- a/drivers/net/macsec.c
++++ b/drivers/net/macsec.c
+@@ -397,6 +397,14 @@ static struct macsec_cb *macsec_skb_cb(struct sk_buff 
*skb)
+ #define DEFAULT_ENCRYPT false
+ #define DEFAULT_ENCODING_SA 0
+ 
++static bool send_sci(const struct macsec_secy *secy)
++{
++      const struct macsec_tx_sc *tx_sc = &secy->tx_sc;
++
++      return tx_sc->send_sci ||
++              (secy->n_rx_sc > 1 && !tx_sc->end_station && !tx_sc->scb);
++}
++
+ static sci_t make_sci(u8 *addr, __be16 port)
+ {
+       sci_t sci;
+@@ -437,15 +445,15 @@ static unsigned int macsec_extra_len(bool sci_present)
+ 
+ /* Fill SecTAG according to IEEE 802.1AE-2006 10.5.3 */
+ static void macsec_fill_sectag(struct macsec_eth_header *h,
+-                             const struct macsec_secy *secy, u32 pn)
++                             const struct macsec_secy *secy, u32 pn,
++                             bool sci_present)
+ {
+       const struct macsec_tx_sc *tx_sc = &secy->tx_sc;
+ 
+-      memset(&h->tci_an, 0, macsec_sectag_len(tx_sc->send_sci));
++      memset(&h->tci_an, 0, macsec_sectag_len(sci_present));
+       h->eth.h_proto = htons(ETH_P_MACSEC);
+ 
+-      if (tx_sc->send_sci ||
+-          (secy->n_rx_sc > 1 && !tx_sc->end_station && !tx_sc->scb)) {
++      if (sci_present) {
+               h->tci_an |= MACSEC_TCI_SC;
+               memcpy(&h->secure_channel_id, &secy->sci,
+                      sizeof(h->secure_channel_id));
+@@ -650,6 +658,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
+       struct macsec_tx_sc *tx_sc;
+       struct macsec_tx_sa *tx_sa;
+       struct macsec_dev *macsec = macsec_priv(dev);
++      bool sci_present;
+       u32 pn;
+ 
+       secy = &macsec->secy;
+@@ -687,7 +696,8 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
+ 
+       unprotected_len = skb->len;
+       eth = eth_hdr(skb);
+-      hh = (struct macsec_eth_header *)skb_push(skb, 
macsec_extra_len(tx_sc->send_sci));
++      sci_present = send_sci(secy);
++      hh = (struct macsec_eth_header *)skb_push(skb, 
macsec_extra_len(sci_present));
+       memmove(hh, eth, 2 * ETH_ALEN);
+ 
+       pn = tx_sa_update_pn(tx_sa, secy);
+@@ -696,7 +706,7 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb,
+               kfree_skb(skb);
+               return ERR_PTR(-ENOLINK);
+       }
+-      macsec_fill_sectag(hh, secy, pn);
++      macsec_fill_sectag(hh, secy, pn, sci_present);
+       macsec_set_shortlen(hh, unprotected_len - 2 * ETH_ALEN);
+ 
+       skb_put(skb, secy->icv_len);
+@@ -726,10 +736,10 @@ static struct sk_buff *macsec_encrypt(struct sk_buff 
*skb,
+       skb_to_sgvec(skb, sg, 0, skb->len);
+ 
+       if (tx_sc->encrypt) {
+-              int len = skb->len - macsec_hdr_len(tx_sc->send_sci) -
++              int len = skb->len - macsec_hdr_len(sci_present) -
+                         secy->icv_len;
+               aead_request_set_crypt(req, sg, sg, len, iv);
+-              aead_request_set_ad(req, macsec_hdr_len(tx_sc->send_sci));
++              aead_request_set_ad(req, macsec_hdr_len(sci_present));
+       } else {
+               aead_request_set_crypt(req, sg, sg, 0, iv);
+               aead_request_set_ad(req, skb->len - secy->icv_len);
+diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
+index c6f66832a1a6..f424b867f73e 100644
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -608,6 +608,21 @@ void phy_start_machine(struct phy_device *phydev)
+ }
+ 
+ /**
++ * phy_trigger_machine - trigger the state machine to run
++ *
++ * @phydev: the phy_device struct
++ *
++ * Description: There has been a change in state which requires that the
++ *   state machine runs.
++ */
++
++static void phy_trigger_machine(struct phy_device *phydev)
++{
++      cancel_delayed_work_sync(&phydev->state_queue);
++      queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 0);
++}
++
++/**
+  * phy_stop_machine - stop the PHY state machine tracking
+  * @phydev: target phy_device struct
+  *
+@@ -639,6 +654,8 @@ static void phy_error(struct phy_device *phydev)
+       mutex_lock(&phydev->lock);
+       phydev->state = PHY_HALTED;
+       mutex_unlock(&phydev->lock);
++
++      phy_trigger_machine(phydev);
+ }
+ 
+ /**
+@@ -800,8 +817,7 @@ void phy_change(struct work_struct *work)
+       }
+ 
+       /* reschedule state queue work to run as soon as possible */
+-      cancel_delayed_work_sync(&phydev->state_queue);
+-      queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 0);
++      phy_trigger_machine(phydev);
+       return;
+ 
+ ignore:
+@@ -890,6 +906,8 @@ void phy_start(struct phy_device *phydev)
+       /* if phy was suspended, bring the physical link up again */
+       if (do_resume)
+               phy_resume(phydev);
++
++      phy_trigger_machine(phydev);
+ }
+ EXPORT_SYMBOL(phy_start);
+ 
+diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
+index 6e65832051d6..5ae664c02528 100644
+--- a/drivers/net/vxlan.c
++++ b/drivers/net/vxlan.c
+@@ -584,7 +584,7 @@ static struct sk_buff **vxlan_gro_receive(struct sock *sk,
+               }
+       }
+ 
+-      pp = eth_gro_receive(head, skb);
++      pp = call_gro_receive(eth_gro_receive, head, skb);
+       flush = 0;
+ 
+ out:
+diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
+index d637c933c8a9..58a97d420572 100644
+--- a/drivers/ptp/ptp_chardev.c
++++ b/drivers/ptp/ptp_chardev.c
+@@ -193,6 +193,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, 
unsigned long arg)
+               if (err)
+                       break;
+ 
++              memset(&precise_offset, 0, sizeof(precise_offset));
+               ts = ktime_to_timespec64(xtstamp.device);
+               precise_offset.device.sec = ts.tv_sec;
+               precise_offset.device.nsec = ts.tv_nsec;
+diff --git a/drivers/scsi/megaraid/megaraid_sas.h 
b/drivers/scsi/megaraid/megaraid_sas.h
+index ca86c885dfaa..3aaea713bf37 100644
+--- a/drivers/scsi/megaraid/megaraid_sas.h
++++ b/drivers/scsi/megaraid/megaraid_sas.h
+@@ -2233,7 +2233,7 @@ struct megasas_instance_template {
+ };
+ 
+ #define MEGASAS_IS_LOGICAL(scp)                                               
\
+-      (scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1
++      ((scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1)
+ 
+ #define MEGASAS_DEV_INDEX(scp)                                                
\
+       (((scp->device->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) +   \
+diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c 
b/drivers/scsi/megaraid/megaraid_sas_base.c
+index c1ed25adb17e..71e489937c6f 100644
+--- a/drivers/scsi/megaraid/megaraid_sas_base.c
++++ b/drivers/scsi/megaraid/megaraid_sas_base.c
+@@ -1713,16 +1713,13 @@ megasas_queue_command(struct Scsi_Host *shost, struct 
scsi_cmnd *scmd)
+               goto out_done;
+       }
+ 
+-      switch (scmd->cmnd[0]) {
+-      case SYNCHRONIZE_CACHE:
+-              /*
+-               * FW takes care of flush cache on its own
+-               * No need to send it down
+-               */
++      /*
++       * FW takes care of flush cache on its own for Virtual Disk.
++       * No need to send it down for VD. For JBOD send SYNCHRONIZE_CACHE to 
FW.
++       */
++      if ((scmd->cmnd[0] == SYNCHRONIZE_CACHE) && MEGASAS_IS_LOGICAL(scmd)) {
+               scmd->result = DID_OK << 16;
+               goto out_done;
+-      default:
+-              break;
+       }
+ 
+       return instance->instancet->build_and_issue_cmd(instance, scmd);
+diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
+index 6443cfba7b55..dc3b5962d087 100644
+--- a/drivers/usb/dwc3/gadget.c
++++ b/drivers/usb/dwc3/gadget.c
+@@ -789,6 +789,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
+               req->trb = trb;
+               req->trb_dma = dwc3_trb_dma_offset(dep, trb);
+               req->first_trb_index = dep->trb_enqueue;
++              dep->queued_requests++;
+       }
+ 
+       dwc3_ep_inc_enq(dep);
+@@ -841,8 +842,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
+ 
+       trb->ctrl |= DWC3_TRB_CTRL_HWO;
+ 
+-      dep->queued_requests++;
+-
+       trace_dwc3_prepare_trb(dep, trb);
+ }
+ 
+@@ -1963,7 +1962,9 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, 
struct dwc3_ep *dep,
+       unsigned int            s_pkt = 0;
+       unsigned int            trb_status;
+ 
+-      dep->queued_requests--;
++      if (req->trb == trb)
++              dep->queued_requests--;
++
+       trace_dwc3_complete_trb(dep, trb);
+ 
+       /*
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index e8d79d4ebcfe..e942c67ea230 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -2154,7 +2154,10 @@ struct napi_gro_cb {
+       /* Used to determine if flush_id can be ignored */
+       u8      is_atomic:1;
+ 
+-      /* 5 bit hole */
++      /* Number of gro_receive callbacks this packet already went through */
++      u8 recursion_counter:4;
++
++      /* 1 bit hole */
+ 
+       /* used to support CHECKSUM_COMPLETE for tunneling protocols */
+       __wsum  csum;
+@@ -2165,6 +2168,40 @@ struct napi_gro_cb {
+ 
+ #define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb)
+ 
++#define GRO_RECURSION_LIMIT 15
++static inline int gro_recursion_inc_test(struct sk_buff *skb)
++{
++      return ++NAPI_GRO_CB(skb)->recursion_counter == GRO_RECURSION_LIMIT;
++}
++
++typedef struct sk_buff **(*gro_receive_t)(struct sk_buff **, struct sk_buff 
*);
++static inline struct sk_buff **call_gro_receive(gro_receive_t cb,
++                                              struct sk_buff **head,
++                                              struct sk_buff *skb)
++{
++      if (unlikely(gro_recursion_inc_test(skb))) {
++              NAPI_GRO_CB(skb)->flush |= 1;
++              return NULL;
++      }
++
++      return cb(head, skb);
++}
++
++typedef struct sk_buff **(*gro_receive_sk_t)(struct sock *, struct sk_buff **,
++                                           struct sk_buff *);
++static inline struct sk_buff **call_gro_receive_sk(gro_receive_sk_t cb,
++                                                 struct sock *sk,
++                                                 struct sk_buff **head,
++                                                 struct sk_buff *skb)
++{
++      if (unlikely(gro_recursion_inc_test(skb))) {
++              NAPI_GRO_CB(skb)->flush |= 1;
++              return NULL;
++      }
++
++      return cb(sk, head, skb);
++}
++
+ struct packet_type {
+       __be16                  type;   /* This is really htons(ether_type). */
+       struct net_device       *dev;   /* NULL is wildcarded here           */
+@@ -3862,7 +3899,7 @@ struct net_device *netdev_all_lower_get_next_rcu(struct 
net_device *dev,
+            ldev = netdev_all_lower_get_next(dev, &(iter)))
+ 
+ #define netdev_for_each_all_lower_dev_rcu(dev, ldev, iter) \
+-      for (iter = (dev)->all_adj_list.lower.next, \
++      for (iter = &(dev)->all_adj_list.lower, \
+            ldev = netdev_all_lower_get_next_rcu(dev, &(iter)); \
+            ldev; \
+            ldev = netdev_all_lower_get_next_rcu(dev, &(iter)))
+diff --git a/include/net/ip.h b/include/net/ip.h
+index 9742b92dc933..156b0c11b524 100644
+--- a/include/net/ip.h
++++ b/include/net/ip.h
+@@ -549,7 +549,7 @@ int ip_options_rcv_srr(struct sk_buff *skb);
+  */
+ 
+ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb);
+-void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, int offset);
++void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, int tlen, 
int offset);
+ int ip_cmsg_send(struct sock *sk, struct msghdr *msg,
+                struct ipcm_cookie *ipc, bool allow_ipv6);
+ int ip_setsockopt(struct sock *sk, int level, int optname, char __user 
*optval,
+@@ -571,7 +571,7 @@ void ip_local_error(struct sock *sk, int err, __be32 
daddr, __be16 dport,
+ 
+ static inline void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
+ {
+-      ip_cmsg_recv_offset(msg, skb, 0);
++      ip_cmsg_recv_offset(msg, skb, 0, 0);
+ }
+ 
+ bool icmp_global_allow(void);
+diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
+index d97305d0e71f..0a2d2701285d 100644
+--- a/include/net/ip6_route.h
++++ b/include/net/ip6_route.h
+@@ -32,6 +32,7 @@ struct route_info {
+ #define RT6_LOOKUP_F_SRCPREF_TMP      0x00000008
+ #define RT6_LOOKUP_F_SRCPREF_PUBLIC   0x00000010
+ #define RT6_LOOKUP_F_SRCPREF_COA      0x00000020
++#define RT6_LOOKUP_F_IGNORE_LINKSTATE 0x00000040
+ 
+ /* We do not (yet ?) support IPv6 jumbograms (RFC 2675)
+  * Unlike IPv4, hdr->seg_len doesn't include the IPv6 header
+diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
+index 262f0379d83a..5a78be518101 100644
+--- a/include/uapi/linux/rtnetlink.h
++++ b/include/uapi/linux/rtnetlink.h
+@@ -350,7 +350,7 @@ struct rtnexthop {
+ #define RTNH_F_OFFLOAD                8       /* offloaded route */
+ #define RTNH_F_LINKDOWN               16      /* carrier-down on nexthop */
+ 
+-#define RTNH_COMPARE_MASK     (RTNH_F_DEAD | RTNH_F_LINKDOWN)
++#define RTNH_COMPARE_MASK     (RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD)
+ 
+ /* Macros to handle hexthops */
+ 
+diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
+index 8de138d3306b..f2531ad66b68 100644
+--- a/net/8021q/vlan.c
++++ b/net/8021q/vlan.c
+@@ -664,7 +664,7 @@ static struct sk_buff **vlan_gro_receive(struct sk_buff 
**head,
+ 
+       skb_gro_pull(skb, sizeof(*vhdr));
+       skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr));
+-      pp = ptype->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+       rcu_read_unlock();
+diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
+index c5fea9393946..2136e45f5277 100644
+--- a/net/bridge/br_multicast.c
++++ b/net/bridge/br_multicast.c
+@@ -972,13 +972,12 @@ static void br_multicast_enable(struct 
bridge_mcast_own_query *query)
+               mod_timer(&query->timer, jiffies);
+ }
+ 
+-void br_multicast_enable_port(struct net_bridge_port *port)
++static void __br_multicast_enable_port(struct net_bridge_port *port)
+ {
+       struct net_bridge *br = port->br;
+ 
+-      spin_lock(&br->multicast_lock);
+       if (br->multicast_disabled || !netif_running(br->dev))
+-              goto out;
++              return;
+ 
+       br_multicast_enable(&port->ip4_own_query);
+ #if IS_ENABLED(CONFIG_IPV6)
+@@ -987,8 +986,14 @@ void br_multicast_enable_port(struct net_bridge_port 
*port)
+       if (port->multicast_router == MDB_RTR_TYPE_PERM &&
+           hlist_unhashed(&port->rlist))
+               br_multicast_add_router(br, port);
++}
+ 
+-out:
++void br_multicast_enable_port(struct net_bridge_port *port)
++{
++      struct net_bridge *br = port->br;
++
++      spin_lock(&br->multicast_lock);
++      __br_multicast_enable_port(port);
+       spin_unlock(&br->multicast_lock);
+ }
+ 
+@@ -1994,8 +1999,9 @@ static void br_multicast_start_querier(struct net_bridge 
*br,
+ 
+ int br_multicast_toggle(struct net_bridge *br, unsigned long val)
+ {
+-      int err = 0;
+       struct net_bridge_mdb_htable *mdb;
++      struct net_bridge_port *port;
++      int err = 0;
+ 
+       spin_lock_bh(&br->multicast_lock);
+       if (br->multicast_disabled == !val)
+@@ -2023,10 +2029,9 @@ rollback:
+                       goto rollback;
+       }
+ 
+-      br_multicast_start_querier(br, &br->ip4_own_query);
+-#if IS_ENABLED(CONFIG_IPV6)
+-      br_multicast_start_querier(br, &br->ip6_own_query);
+-#endif
++      br_multicast_open(br);
++      list_for_each_entry(port, &br->port_list, list)
++              __br_multicast_enable_port(port);
+ 
+ unlock:
+       spin_unlock_bh(&br->multicast_lock);
+diff --git a/net/core/dev.c b/net/core/dev.c
+index ea6312057a71..44b3ba462ba1 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -3035,6 +3035,7 @@ struct sk_buff *validate_xmit_skb_list(struct sk_buff 
*skb, struct net_device *d
+       }
+       return head;
+ }
++EXPORT_SYMBOL_GPL(validate_xmit_skb_list);
+ 
+ static void qdisc_pkt_len_init(struct sk_buff *skb)
+ {
+@@ -4496,6 +4497,7 @@ static enum gro_result dev_gro_receive(struct 
napi_struct *napi, struct sk_buff
+               NAPI_GRO_CB(skb)->flush = 0;
+               NAPI_GRO_CB(skb)->free = 0;
+               NAPI_GRO_CB(skb)->encap_mark = 0;
++              NAPI_GRO_CB(skb)->recursion_counter = 0;
+               NAPI_GRO_CB(skb)->is_fou = 0;
+               NAPI_GRO_CB(skb)->is_atomic = 1;
+               NAPI_GRO_CB(skb)->gro_remcsum_start = 0;
+@@ -5500,10 +5502,14 @@ struct net_device 
*netdev_all_lower_get_next_rcu(struct net_device *dev,
+ {
+       struct netdev_adjacent *lower;
+ 
+-      lower = list_first_or_null_rcu(&dev->all_adj_list.lower,
+-                                     struct netdev_adjacent, list);
++      lower = list_entry_rcu((*iter)->next, struct netdev_adjacent, list);
++
++      if (&lower->list == &dev->all_adj_list.lower)
++              return NULL;
++
++      *iter = &lower->list;
+ 
+-      return lower ? lower->dev : NULL;
++      return lower->dev;
+ }
+ EXPORT_SYMBOL(netdev_all_lower_get_next_rcu);
+ 
+@@ -5578,6 +5584,7 @@ static inline bool netdev_adjacent_is_neigh_list(struct 
net_device *dev,
+ 
+ static int __netdev_adjacent_dev_insert(struct net_device *dev,
+                                       struct net_device *adj_dev,
++                                      u16 ref_nr,
+                                       struct list_head *dev_list,
+                                       void *private, bool master)
+ {
+@@ -5587,7 +5594,7 @@ static int __netdev_adjacent_dev_insert(struct 
net_device *dev,
+       adj = __netdev_find_adj(adj_dev, dev_list);
+ 
+       if (adj) {
+-              adj->ref_nr++;
++              adj->ref_nr += ref_nr;
+               return 0;
+       }
+ 
+@@ -5597,7 +5604,7 @@ static int __netdev_adjacent_dev_insert(struct 
net_device *dev,
+ 
+       adj->dev = adj_dev;
+       adj->master = master;
+-      adj->ref_nr = 1;
++      adj->ref_nr = ref_nr;
+       adj->private = private;
+       dev_hold(adj_dev);
+ 
+@@ -5636,6 +5643,7 @@ free_adj:
+ 
+ static void __netdev_adjacent_dev_remove(struct net_device *dev,
+                                        struct net_device *adj_dev,
++                                       u16 ref_nr,
+                                        struct list_head *dev_list)
+ {
+       struct netdev_adjacent *adj;
+@@ -5648,10 +5656,10 @@ static void __netdev_adjacent_dev_remove(struct 
net_device *dev,
+               BUG();
+       }
+ 
+-      if (adj->ref_nr > 1) {
+-              pr_debug("%s to %s ref_nr-- = %d\n", dev->name, adj_dev->name,
+-                       adj->ref_nr-1);
+-              adj->ref_nr--;
++      if (adj->ref_nr > ref_nr) {
++              pr_debug("%s to %s ref_nr-%d = %d\n", dev->name, adj_dev->name,
++                       ref_nr, adj->ref_nr-ref_nr);
++              adj->ref_nr -= ref_nr;
+               return;
+       }
+ 
+@@ -5670,21 +5678,22 @@ static void __netdev_adjacent_dev_remove(struct 
net_device *dev,
+ 
+ static int __netdev_adjacent_dev_link_lists(struct net_device *dev,
+                                           struct net_device *upper_dev,
++                                          u16 ref_nr,
+                                           struct list_head *up_list,
+                                           struct list_head *down_list,
+                                           void *private, bool master)
+ {
+       int ret;
+ 
+-      ret = __netdev_adjacent_dev_insert(dev, upper_dev, up_list, private,
+-                                         master);
++      ret = __netdev_adjacent_dev_insert(dev, upper_dev, ref_nr, up_list,
++                                         private, master);
+       if (ret)
+               return ret;
+ 
+-      ret = __netdev_adjacent_dev_insert(upper_dev, dev, down_list, private,
+-                                         false);
++      ret = __netdev_adjacent_dev_insert(upper_dev, dev, ref_nr, down_list,
++                                         private, false);
+       if (ret) {
+-              __netdev_adjacent_dev_remove(dev, upper_dev, up_list);
++              __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list);
+               return ret;
+       }
+ 
+@@ -5692,9 +5701,10 @@ static int __netdev_adjacent_dev_link_lists(struct 
net_device *dev,
+ }
+ 
+ static int __netdev_adjacent_dev_link(struct net_device *dev,
+-                                    struct net_device *upper_dev)
++                                    struct net_device *upper_dev,
++                                    u16 ref_nr)
+ {
+-      return __netdev_adjacent_dev_link_lists(dev, upper_dev,
++      return __netdev_adjacent_dev_link_lists(dev, upper_dev, ref_nr,
+                                               &dev->all_adj_list.upper,
+                                               &upper_dev->all_adj_list.lower,
+                                               NULL, false);
+@@ -5702,17 +5712,19 @@ static int __netdev_adjacent_dev_link(struct 
net_device *dev,
+ 
+ static void __netdev_adjacent_dev_unlink_lists(struct net_device *dev,
+                                              struct net_device *upper_dev,
++                                             u16 ref_nr,
+                                              struct list_head *up_list,
+                                              struct list_head *down_list)
+ {
+-      __netdev_adjacent_dev_remove(dev, upper_dev, up_list);
+-      __netdev_adjacent_dev_remove(upper_dev, dev, down_list);
++      __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list);
++      __netdev_adjacent_dev_remove(upper_dev, dev, ref_nr, down_list);
+ }
+ 
+ static void __netdev_adjacent_dev_unlink(struct net_device *dev,
+-                                       struct net_device *upper_dev)
++                                       struct net_device *upper_dev,
++                                       u16 ref_nr)
+ {
+-      __netdev_adjacent_dev_unlink_lists(dev, upper_dev,
++      __netdev_adjacent_dev_unlink_lists(dev, upper_dev, ref_nr,
+                                          &dev->all_adj_list.upper,
+                                          &upper_dev->all_adj_list.lower);
+ }
+@@ -5721,17 +5733,17 @@ static int __netdev_adjacent_dev_link_neighbour(struct 
net_device *dev,
+                                               struct net_device *upper_dev,
+                                               void *private, bool master)
+ {
+-      int ret = __netdev_adjacent_dev_link(dev, upper_dev);
++      int ret = __netdev_adjacent_dev_link(dev, upper_dev, 1);
+ 
+       if (ret)
+               return ret;
+ 
+-      ret = __netdev_adjacent_dev_link_lists(dev, upper_dev,
++      ret = __netdev_adjacent_dev_link_lists(dev, upper_dev, 1,
+                                              &dev->adj_list.upper,
+                                              &upper_dev->adj_list.lower,
+                                              private, master);
+       if (ret) {
+-              __netdev_adjacent_dev_unlink(dev, upper_dev);
++              __netdev_adjacent_dev_unlink(dev, upper_dev, 1);
+               return ret;
+       }
+ 
+@@ -5741,8 +5753,8 @@ static int __netdev_adjacent_dev_link_neighbour(struct 
net_device *dev,
+ static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev,
+                                                  struct net_device *upper_dev)
+ {
+-      __netdev_adjacent_dev_unlink(dev, upper_dev);
+-      __netdev_adjacent_dev_unlink_lists(dev, upper_dev,
++      __netdev_adjacent_dev_unlink(dev, upper_dev, 1);
++      __netdev_adjacent_dev_unlink_lists(dev, upper_dev, 1,
+                                          &dev->adj_list.upper,
+                                          &upper_dev->adj_list.lower);
+ }
+@@ -5795,7 +5807,7 @@ static int __netdev_upper_dev_link(struct net_device 
*dev,
+               list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) {
+                       pr_debug("Interlinking %s with %s, non-neighbour\n",
+                                i->dev->name, j->dev->name);
+-                      ret = __netdev_adjacent_dev_link(i->dev, j->dev);
++                      ret = __netdev_adjacent_dev_link(i->dev, j->dev, 
i->ref_nr);
+                       if (ret)
+                               goto rollback_mesh;
+               }
+@@ -5805,7 +5817,7 @@ static int __netdev_upper_dev_link(struct net_device 
*dev,
+       list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) {
+               pr_debug("linking %s's upper device %s with %s\n",
+                        upper_dev->name, i->dev->name, dev->name);
+-              ret = __netdev_adjacent_dev_link(dev, i->dev);
++              ret = __netdev_adjacent_dev_link(dev, i->dev, i->ref_nr);
+               if (ret)
+                       goto rollback_upper_mesh;
+       }
+@@ -5814,7 +5826,7 @@ static int __netdev_upper_dev_link(struct net_device 
*dev,
+       list_for_each_entry(i, &dev->all_adj_list.lower, list) {
+               pr_debug("linking %s's lower device %s with %s\n", dev->name,
+                        i->dev->name, upper_dev->name);
+-              ret = __netdev_adjacent_dev_link(i->dev, upper_dev);
++              ret = __netdev_adjacent_dev_link(i->dev, upper_dev, i->ref_nr);
+               if (ret)
+                       goto rollback_lower_mesh;
+       }
+@@ -5832,7 +5844,7 @@ rollback_lower_mesh:
+       list_for_each_entry(i, &dev->all_adj_list.lower, list) {
+               if (i == to_i)
+                       break;
+-              __netdev_adjacent_dev_unlink(i->dev, upper_dev);
++              __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr);
+       }
+ 
+       i = NULL;
+@@ -5842,7 +5854,7 @@ rollback_upper_mesh:
+       list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) {
+               if (i == to_i)
+                       break;
+-              __netdev_adjacent_dev_unlink(dev, i->dev);
++              __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);
+       }
+ 
+       i = j = NULL;
+@@ -5854,7 +5866,7 @@ rollback_mesh:
+               list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) {
+                       if (i == to_i && j == to_j)
+                               break;
+-                      __netdev_adjacent_dev_unlink(i->dev, j->dev);
++                      __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr);
+               }
+               if (i == to_i)
+                       break;
+@@ -5934,16 +5946,16 @@ void netdev_upper_dev_unlink(struct net_device *dev,
+        */
+       list_for_each_entry(i, &dev->all_adj_list.lower, list)
+               list_for_each_entry(j, &upper_dev->all_adj_list.upper, list)
+-                      __netdev_adjacent_dev_unlink(i->dev, j->dev);
++                      __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr);
+ 
+       /* remove also the devices itself from lower/upper device
+        * list
+        */
+       list_for_each_entry(i, &dev->all_adj_list.lower, list)
+-              __netdev_adjacent_dev_unlink(i->dev, upper_dev);
++              __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr);
+ 
+       list_for_each_entry(i, &upper_dev->all_adj_list.upper, list)
+-              __netdev_adjacent_dev_unlink(dev, i->dev);
++              __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);
+ 
+       call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev,
+                                     &changeupper_info.info);
+diff --git a/net/core/pktgen.c b/net/core/pktgen.c
+index bbd118b19aef..306b8f0e03c1 100644
+--- a/net/core/pktgen.c
++++ b/net/core/pktgen.c
+@@ -216,8 +216,8 @@
+ #define M_QUEUE_XMIT          2       /* Inject packet into qdisc */
+ 
+ /* If lock -- protects updating of if_list */
+-#define   if_lock(t)           spin_lock(&(t->if_lock));
+-#define   if_unlock(t)           spin_unlock(&(t->if_lock));
++#define   if_lock(t)           mutex_lock(&(t->if_lock));
++#define   if_unlock(t)           mutex_unlock(&(t->if_lock));
+ 
+ /* Used to help with determining the pkts on receive */
+ #define PKTGEN_MAGIC 0xbe9be955
+@@ -423,7 +423,7 @@ struct pktgen_net {
+ };
+ 
+ struct pktgen_thread {
+-      spinlock_t if_lock;             /* for list of devices */
++      struct mutex if_lock;           /* for list of devices */
+       struct list_head if_list;       /* All device here */
+       struct list_head th_list;
+       struct task_struct *tsk;
+@@ -2010,11 +2010,13 @@ static void pktgen_change_name(const struct pktgen_net 
*pn, struct net_device *d
+ {
+       struct pktgen_thread *t;
+ 
++      mutex_lock(&pktgen_thread_lock);
++
+       list_for_each_entry(t, &pn->pktgen_threads, th_list) {
+               struct pktgen_dev *pkt_dev;
+ 
+-              rcu_read_lock();
+-              list_for_each_entry_rcu(pkt_dev, &t->if_list, list) {
++              if_lock(t);
++              list_for_each_entry(pkt_dev, &t->if_list, list) {
+                       if (pkt_dev->odev != dev)
+                               continue;
+ 
+@@ -2029,8 +2031,9 @@ static void pktgen_change_name(const struct pktgen_net 
*pn, struct net_device *d
+                                      dev->name);
+                       break;
+               }
+-              rcu_read_unlock();
++              if_unlock(t);
+       }
++      mutex_unlock(&pktgen_thread_lock);
+ }
+ 
+ static int pktgen_device_event(struct notifier_block *unused,
+@@ -2286,7 +2289,7 @@ out:
+ 
+ static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
+ {
+-      pkt_dev->pkt_overhead = LL_RESERVED_SPACE(pkt_dev->odev);
++      pkt_dev->pkt_overhead = 0;
+       pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32);
+       pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev);
+       pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev);
+@@ -2777,13 +2780,13 @@ static void pktgen_finalize_skb(struct pktgen_dev 
*pkt_dev, struct sk_buff *skb,
+ }
+ 
+ static struct sk_buff *pktgen_alloc_skb(struct net_device *dev,
+-                                      struct pktgen_dev *pkt_dev,
+-                                      unsigned int extralen)
++                                      struct pktgen_dev *pkt_dev)
+ {
++      unsigned int extralen = LL_RESERVED_SPACE(dev);
+       struct sk_buff *skb = NULL;
+-      unsigned int size = pkt_dev->cur_pkt_size + 64 + extralen +
+-                          pkt_dev->pkt_overhead;
++      unsigned int size;
+ 
++      size = pkt_dev->cur_pkt_size + 64 + extralen + pkt_dev->pkt_overhead;
+       if (pkt_dev->flags & F_NODE) {
+               int node = pkt_dev->node >= 0 ? pkt_dev->node : numa_node_id();
+ 
+@@ -2796,8 +2799,9 @@ static struct sk_buff *pktgen_alloc_skb(struct 
net_device *dev,
+                skb = __netdev_alloc_skb(dev, size, GFP_NOWAIT);
+       }
+ 
++      /* the caller pre-fetches from skb->data and reserves for the mac hdr */
+       if (likely(skb))
+-              skb_reserve(skb, LL_RESERVED_SPACE(dev));
++              skb_reserve(skb, extralen - 16);
+ 
+       return skb;
+ }
+@@ -2830,16 +2834,14 @@ static struct sk_buff *fill_packet_ipv4(struct 
net_device *odev,
+       mod_cur_headers(pkt_dev);
+       queue_map = pkt_dev->cur_queue_map;
+ 
+-      datalen = (odev->hard_header_len + 16) & ~0xf;
+-
+-      skb = pktgen_alloc_skb(odev, pkt_dev, datalen);
++      skb = pktgen_alloc_skb(odev, pkt_dev);
+       if (!skb) {
+               sprintf(pkt_dev->result, "No memory");
+               return NULL;
+       }
+ 
+       prefetchw(skb->data);
+-      skb_reserve(skb, datalen);
++      skb_reserve(skb, 16);
+ 
+       /*  Reserve for ethernet and IP header  */
+       eth = (__u8 *) skb_push(skb, 14);
+@@ -2959,7 +2961,7 @@ static struct sk_buff *fill_packet_ipv6(struct 
net_device *odev,
+       mod_cur_headers(pkt_dev);
+       queue_map = pkt_dev->cur_queue_map;
+ 
+-      skb = pktgen_alloc_skb(odev, pkt_dev, 16);
++      skb = pktgen_alloc_skb(odev, pkt_dev);
+       if (!skb) {
+               sprintf(pkt_dev->result, "No memory");
+               return NULL;
+@@ -3763,7 +3765,7 @@ static int __net_init pktgen_create_thread(int cpu, 
struct pktgen_net *pn)
+               return -ENOMEM;
+       }
+ 
+-      spin_lock_init(&t->if_lock);
++      mutex_init(&t->if_lock);
+       t->cpu = cpu;
+ 
+       INIT_LIST_HEAD(&t->if_list);
+diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
+index 66dff5e3d772..02acfff36028 100644
+--- a/net/ethernet/eth.c
++++ b/net/ethernet/eth.c
+@@ -439,7 +439,7 @@ struct sk_buff **eth_gro_receive(struct sk_buff **head,
+ 
+       skb_gro_pull(skb, sizeof(*eh));
+       skb_gro_postpull_rcsum(skb, eh, sizeof(*eh));
+-      pp = ptype->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+       rcu_read_unlock();
+diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
+index 55513e654d79..eebbc0f2baa8 100644
+--- a/net/ipv4/af_inet.c
++++ b/net/ipv4/af_inet.c
+@@ -1388,7 +1388,7 @@ struct sk_buff **inet_gro_receive(struct sk_buff **head, 
struct sk_buff *skb)
+       skb_gro_pull(skb, sizeof(*iph));
+       skb_set_transport_header(skb, skb_gro_offset(skb));
+ 
+-      pp = ops->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+       rcu_read_unlock();
+diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
+index 321d57f825ce..5351b61ab8d3 100644
+--- a/net/ipv4/fou.c
++++ b/net/ipv4/fou.c
+@@ -249,7 +249,7 @@ static struct sk_buff **fou_gro_receive(struct sock *sk,
+       if (!ops || !ops->callbacks.gro_receive)
+               goto out_unlock;
+ 
+-      pp = ops->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+       rcu_read_unlock();
+@@ -441,7 +441,7 @@ next_proto:
+       if (WARN_ON_ONCE(!ops || !ops->callbacks.gro_receive))
+               goto out_unlock;
+ 
+-      pp = ops->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+       flush = 0;
+ 
+ out_unlock:
+diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c
+index ecd1e09dbbf1..6871f59cd0c0 100644
+--- a/net/ipv4/gre_offload.c
++++ b/net/ipv4/gre_offload.c
+@@ -227,7 +227,7 @@ static struct sk_buff **gre_gro_receive(struct sk_buff 
**head,
+       /* Adjusted NAPI_GRO_CB(skb)->csum after skb_gro_pull()*/
+       skb_gro_postpull_rcsum(skb, greh, grehlen);
+ 
+-      pp = ptype->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb);
+       flush = 0;
+ 
+ out_unlock:
+diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
+index 71a52f4d4cff..11ef96e2147a 100644
+--- a/net/ipv4/ip_sockglue.c
++++ b/net/ipv4/ip_sockglue.c
+@@ -98,7 +98,7 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct 
sk_buff *skb)
+ }
+ 
+ static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
+-                                int offset)
++                                int tlen, int offset)
+ {
+       __wsum csum = skb->csum;
+ 
+@@ -106,8 +106,9 @@ static void ip_cmsg_recv_checksum(struct msghdr *msg, 
struct sk_buff *skb,
+               return;
+ 
+       if (offset != 0)
+-              csum = csum_sub(csum, csum_partial(skb_transport_header(skb),
+-                                                 offset, 0));
++              csum = csum_sub(csum,
++                              csum_partial(skb_transport_header(skb) + tlen,
++                                           offset, 0));
+ 
+       put_cmsg(msg, SOL_IP, IP_CHECKSUM, sizeof(__wsum), &csum);
+ }
+@@ -153,7 +154,7 @@ static void ip_cmsg_recv_dstaddr(struct msghdr *msg, 
struct sk_buff *skb)
+ }
+ 
+ void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb,
+-                       int offset)
++                       int tlen, int offset)
+ {
+       struct inet_sock *inet = inet_sk(skb->sk);
+       unsigned int flags = inet->cmsg_flags;
+@@ -216,7 +217,7 @@ void ip_cmsg_recv_offset(struct msghdr *msg, struct 
sk_buff *skb,
+       }
+ 
+       if (flags & IP_CMSG_CHECKSUM)
+-              ip_cmsg_recv_checksum(msg, skb, offset);
++              ip_cmsg_recv_checksum(msg, skb, tlen, offset);
+ }
+ EXPORT_SYMBOL(ip_cmsg_recv_offset);
+ 
+diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
+index 1cb67de106fe..80bc36b25de2 100644
+--- a/net/ipv4/sysctl_net_ipv4.c
++++ b/net/ipv4/sysctl_net_ipv4.c
+@@ -96,11 +96,11 @@ static void inet_get_ping_group_range_table(struct 
ctl_table *table, kgid_t *low
+               container_of(table->data, struct net, 
ipv4.ping_group_range.range);
+       unsigned int seq;
+       do {
+-              seq = read_seqbegin(&net->ipv4.ip_local_ports.lock);
++              seq = read_seqbegin(&net->ipv4.ping_group_range.lock);
+ 
+               *low = data[0];
+               *high = data[1];
+-      } while (read_seqretry(&net->ipv4.ip_local_ports.lock, seq));
++      } while (read_seqretry(&net->ipv4.ping_group_range.lock, seq));
+ }
+ 
+ /* Update system visible IP port range */
+@@ -109,10 +109,10 @@ static void set_ping_group_range(struct ctl_table 
*table, kgid_t low, kgid_t hig
+       kgid_t *data = table->data;
+       struct net *net =
+               container_of(table->data, struct net, 
ipv4.ping_group_range.range);
+-      write_seqlock(&net->ipv4.ip_local_ports.lock);
++      write_seqlock(&net->ipv4.ping_group_range.lock);
+       data[0] = low;
+       data[1] = high;
+-      write_sequnlock(&net->ipv4.ip_local_ports.lock);
++      write_sequnlock(&net->ipv4.ping_group_range.lock);
+ }
+ 
+ /* Validate changes from /proc interface. */
+diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
+index 5fdcb8d108d4..c0d71e7d663e 100644
+--- a/net/ipv4/udp.c
++++ b/net/ipv4/udp.c
+@@ -1327,7 +1327,7 @@ try_again:
+               *addr_len = sizeof(*sin);
+       }
+       if (inet->cmsg_flags)
+-              ip_cmsg_recv_offset(msg, skb, sizeof(struct udphdr) + off);
++              ip_cmsg_recv_offset(msg, skb, sizeof(struct udphdr), off);
+ 
+       err = copied;
+       if (flags & MSG_TRUNC)
+diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
+index 81f253b6ff36..6de9f977356e 100644
+--- a/net/ipv4/udp_offload.c
++++ b/net/ipv4/udp_offload.c
+@@ -293,7 +293,7 @@ unflush:
+ 
+       skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp 
header */
+       skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr));
+-      pp = udp_sk(sk)->gro_receive(sk, head, skb);
++      pp = call_gro_receive_sk(udp_sk(sk)->gro_receive, sk, head, skb);
+ 
+ out_unlock:
+       rcu_read_unlock();
+diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
+index 2f1f5d439788..f5432d65e6bf 100644
+--- a/net/ipv6/addrconf.c
++++ b/net/ipv6/addrconf.c
+@@ -2995,7 +2995,7 @@ static void init_loopback(struct net_device *dev)
+                                * lo device down, release this obsolete dst and
+                                * reallocate a new router for ifa.
+                                */
+-                              if (sp_ifa->rt->dst.obsolete > 0) {
++                              if (!atomic_read(&sp_ifa->rt->rt6i_ref)) {
+                                       ip6_rt_put(sp_ifa->rt);
+                                       sp_ifa->rt = NULL;
+                               } else {
+diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
+index 22e90e56b5a9..a09418bda1f8 100644
+--- a/net/ipv6/ip6_offload.c
++++ b/net/ipv6/ip6_offload.c
+@@ -243,7 +243,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff 
**head,
+ 
+       skb_gro_postpull_rcsum(skb, iph, nlen);
+ 
+-      pp = ops->callbacks.gro_receive(head, skb);
++      pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
+ 
+ out_unlock:
+       rcu_read_unlock();
+diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
+index 888543debe4e..41489f39c456 100644
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -155,6 +155,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr 
*remote, const struct in6_
+       hash = HASH(&any, local);
+       for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+               if (ipv6_addr_equal(local, &t->parms.laddr) &&
++                  ipv6_addr_any(&t->parms.raddr) &&
+                   (t->dev->flags & IFF_UP))
+                       return t;
+       }
+@@ -162,6 +163,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr 
*remote, const struct in6_
+       hash = HASH(remote, &any);
+       for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
+               if (ipv6_addr_equal(remote, &t->parms.raddr) &&
++                  ipv6_addr_any(&t->parms.laddr) &&
+                   (t->dev->flags & IFF_UP))
+                       return t;
+       }
+@@ -1132,6 +1134,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device 
*dev, __u8 dsfield,
+       if (err)
+               return err;
+ 
++      skb->protocol = htons(ETH_P_IPV6);
+       skb_push(skb, sizeof(struct ipv6hdr));
+       skb_reset_network_header(skb);
+       ipv6h = ipv6_hdr(skb);
+diff --git a/net/ipv6/route.c b/net/ipv6/route.c
+index 269218aacbea..23153ac6c9b9 100644
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -656,7 +656,8 @@ static struct rt6_info *find_match(struct rt6_info *rt, 
int oif, int strict,
+       struct net_device *dev = rt->dst.dev;
+ 
+       if (dev && !netif_carrier_ok(dev) &&
+-          idev->cnf.ignore_routes_with_linkdown)
++          idev->cnf.ignore_routes_with_linkdown &&
++          !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE))
+               goto out;
+ 
+       if (rt6_check_expired(rt))
+@@ -1050,6 +1051,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct 
fib6_table *table,
+       int strict = 0;
+ 
+       strict |= flags & RT6_LOOKUP_F_IFACE;
++      strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE;
+       if (net->ipv6.devconf_all->forwarding == 0)
+               strict |= RT6_LOOKUP_F_REACHABLE;
+ 
+@@ -1783,7 +1785,7 @@ static struct rt6_info *ip6_nh_lookup_table(struct net 
*net,
+       };
+       struct fib6_table *table;
+       struct rt6_info *rt;
+-      int flags = RT6_LOOKUP_F_IFACE;
++      int flags = RT6_LOOKUP_F_IFACE | RT6_LOOKUP_F_IGNORE_LINKSTATE;
+ 
+       table = fib6_get_table(net, cfg->fc_table);
+       if (!table)
+diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
+index 94f4f89d73e7..fc67822c42e0 100644
+--- a/net/ipv6/tcp_ipv6.c
++++ b/net/ipv6/tcp_ipv6.c
+@@ -1193,6 +1193,16 @@ out:
+       return NULL;
+ }
+ 
++static void tcp_v6_restore_cb(struct sk_buff *skb)
++{
++      /* We need to move header back to the beginning if xfrm6_policy_check()
++       * and tcp_v6_fill_cb() are going to be called again.
++       * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there.
++       */
++      memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
++              sizeof(struct inet6_skb_parm));
++}
++
+ /* The socket must have it's spinlock held when we get
+  * here, unless it is a TCP_LISTEN socket.
+  *
+@@ -1322,6 +1332,7 @@ ipv6_pktoptions:
+                       np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb));
+               if (ipv6_opt_accepted(sk, opt_skb, 
&TCP_SKB_CB(opt_skb)->header.h6)) {
+                       skb_set_owner_r(opt_skb, sk);
++                      tcp_v6_restore_cb(opt_skb);
+                       opt_skb = xchg(&np->pktoptions, opt_skb);
+               } else {
+                       __kfree_skb(opt_skb);
+@@ -1355,15 +1366,6 @@ static void tcp_v6_fill_cb(struct sk_buff *skb, const 
struct ipv6hdr *hdr,
+       TCP_SKB_CB(skb)->sacked = 0;
+ }
+ 
+-static void tcp_v6_restore_cb(struct sk_buff *skb)
+-{
+-      /* We need to move header back to the beginning if xfrm6_policy_check()
+-       * and tcp_v6_fill_cb() are going to be called again.
+-       */
+-      memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
+-              sizeof(struct inet6_skb_parm));
+-}
+-
+ static int tcp_v6_rcv(struct sk_buff *skb)
+ {
+       const struct tcphdr *th;
+diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
+index 19ac3a1c308d..c2a8656c22eb 100644
+--- a/net/ipv6/udp.c
++++ b/net/ipv6/udp.c
+@@ -427,7 +427,8 @@ try_again:
+ 
+       if (is_udp4) {
+               if (inet->cmsg_flags)
+-                      ip_cmsg_recv(msg, skb);
++                      ip_cmsg_recv_offset(msg, skb,
++                                          sizeof(struct udphdr), off);
+       } else {
+               if (np->rxopt.all)
+                       ip6_datagram_recv_specific_ctl(sk, msg, skb);
+diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
+index 627f898c05b9..62bea4591054 100644
+--- a/net/netlink/af_netlink.c
++++ b/net/netlink/af_netlink.c
+@@ -1832,7 +1832,7 @@ static int netlink_recvmsg(struct socket *sock, struct 
msghdr *msg, size_t len,
+       /* Record the max length of recvmsg() calls for future allocations */
+       nlk->max_recvmsg_len = max(nlk->max_recvmsg_len, len);
+       nlk->max_recvmsg_len = min_t(size_t, nlk->max_recvmsg_len,
+-                                   16384);
++                                   SKB_WITH_OVERHEAD(32768));
+ 
+       copied = data_skb->len;
+       if (len < copied) {
+@@ -2083,8 +2083,9 @@ static int netlink_dump(struct sock *sk)
+ 
+       if (alloc_min_size < nlk->max_recvmsg_len) {
+               alloc_size = nlk->max_recvmsg_len;
+-              skb = alloc_skb(alloc_size, GFP_KERNEL |
+-                                          __GFP_NOWARN | __GFP_NORETRY);
++              skb = alloc_skb(alloc_size,
++                              (GFP_KERNEL & ~__GFP_DIRECT_RECLAIM) |
++                              __GFP_NOWARN | __GFP_NORETRY);
+       }
+       if (!skb) {
+               alloc_size = alloc_min_size;
+diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
+index 33a4697d5539..d2238b204691 100644
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -250,7 +250,7 @@ static void __fanout_link(struct sock *sk, struct 
packet_sock *po);
+ static int packet_direct_xmit(struct sk_buff *skb)
+ {
+       struct net_device *dev = skb->dev;
+-      netdev_features_t features;
++      struct sk_buff *orig_skb = skb;
+       struct netdev_queue *txq;
+       int ret = NETDEV_TX_BUSY;
+ 
+@@ -258,9 +258,8 @@ static int packet_direct_xmit(struct sk_buff *skb)
+                    !netif_carrier_ok(dev)))
+               goto drop;
+ 
+-      features = netif_skb_features(skb);
+-      if (skb_needs_linearize(skb, features) &&
+-          __skb_linearize(skb))
++      skb = validate_xmit_skb_list(skb, dev);
++      if (skb != orig_skb)
+               goto drop;
+ 
+       txq = skb_get_tx_queue(dev, skb);
+@@ -280,7 +279,7 @@ static int packet_direct_xmit(struct sk_buff *skb)
+       return ret;
+ drop:
+       atomic_long_inc(&dev->tx_dropped);
+-      kfree_skb(skb);
++      kfree_skb_list(skb);
+       return NET_XMIT_DROP;
+ }
+ 
+@@ -3952,6 +3951,7 @@ static int packet_notifier(struct notifier_block *this,
+                               }
+                               if (msg == NETDEV_UNREGISTER) {
+                                       packet_cached_dev_reset(po);
++                                      fanout_release(sk);
+                                       po->ifindex = -1;
+                                       if (po->prot_hook.dev)
+                                               dev_put(po->prot_hook.dev);
+diff --git a/net/sched/act_api.c b/net/sched/act_api.c
+index d09d0687594b..027ddf412c40 100644
+--- a/net/sched/act_api.c
++++ b/net/sched/act_api.c
+@@ -341,22 +341,25 @@ int tcf_register_action(struct tc_action_ops *act,
+       if (!act->act || !act->dump || !act->init || !act->walk || !act->lookup)
+               return -EINVAL;
+ 
++      /* We have to register pernet ops before making the action ops visible,
++       * otherwise tcf_action_init_1() could get a partially initialized
++       * netns.
++       */
++      ret = register_pernet_subsys(ops);
++      if (ret)
++              return ret;
++
+       write_lock(&act_mod_lock);
+       list_for_each_entry(a, &act_base, head) {
+               if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) {
+                       write_unlock(&act_mod_lock);
++                      unregister_pernet_subsys(ops);
+                       return -EEXIST;
+               }
+       }
+       list_add_tail(&act->head, &act_base);
+       write_unlock(&act_mod_lock);
+ 
+-      ret = register_pernet_subsys(ops);
+-      if (ret) {
+-              tcf_unregister_action(act, ops);
+-              return ret;
+-      }
+-
+       return 0;
+ }
+ EXPORT_SYMBOL(tcf_register_action);
+@@ -367,8 +370,6 @@ int tcf_unregister_action(struct tc_action_ops *act,
+       struct tc_action_ops *a;
+       int err = -ENOENT;
+ 
+-      unregister_pernet_subsys(ops);
+-
+       write_lock(&act_mod_lock);
+       list_for_each_entry(a, &act_base, head) {
+               if (a == act) {
+@@ -378,6 +379,8 @@ int tcf_unregister_action(struct tc_action_ops *act,
+               }
+       }
+       write_unlock(&act_mod_lock);
++      if (!err)
++              unregister_pernet_subsys(ops);
+       return err;
+ }
+ EXPORT_SYMBOL(tcf_unregister_action);
+diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c
+index 691409de3e1a..4ffc6c13a566 100644
+--- a/net/sched/act_vlan.c
++++ b/net/sched/act_vlan.c
+@@ -36,6 +36,12 @@ static int tcf_vlan(struct sk_buff *skb, const struct 
tc_action *a,
+       bstats_update(&v->tcf_bstats, skb);
+       action = v->tcf_action;
+ 
++      /* Ensure 'data' points at mac_header prior calling vlan manipulating
++       * functions.
++       */
++      if (skb_at_tc_ingress(skb))
++              skb_push_rcsum(skb, skb->mac_len);
++
+       switch (v->tcfv_action) {
+       case TCA_VLAN_ACT_POP:
+               err = skb_vlan_pop(skb);
+@@ -57,6 +63,9 @@ drop:
+       action = TC_ACT_SHOT;
+       v->tcf_qstats.drops++;
+ unlock:
++      if (skb_at_tc_ingress(skb))
++              skb_pull_rcsum(skb, skb->mac_len);
++
+       spin_unlock(&v->tcf_lock);
+       return action;
+ }
+diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
+index a7c5645373af..74bed5e9bb89 100644
+--- a/net/sched/cls_api.c
++++ b/net/sched/cls_api.c
+@@ -344,7 +344,8 @@ replay:
+                       if (err == 0) {
+                               struct tcf_proto *next = 
rtnl_dereference(tp->next);
+ 
+-                              tfilter_notify(net, skb, n, tp, fh, 
RTM_DELTFILTER);
++                              tfilter_notify(net, skb, n, tp,
++                                             t->tcm_handle, RTM_DELTFILTER);
+                               if (tcf_destroy(tp, false))
+                                       RCU_INIT_POINTER(*back, next);
+                       }
+diff --git a/net/sctp/output.c b/net/sctp/output.c
+index 31b7bc35895d..81929907a365 100644
+--- a/net/sctp/output.c
++++ b/net/sctp/output.c
+@@ -417,6 +417,7 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t 
gfp)
+       __u8 has_data = 0;
+       int gso = 0;
+       int pktcount = 0;
++      int auth_len = 0;
+       struct dst_entry *dst;
+       unsigned char *auth = NULL;     /* pointer to auth in skb data */
+ 
+@@ -505,7 +506,12 @@ int sctp_packet_transmit(struct sctp_packet *packet, 
gfp_t gfp)
+                       list_for_each_entry(chunk, &packet->chunk_list, list) {
+                               int padded = WORD_ROUND(chunk->skb->len);
+ 
+-                              if (pkt_size + padded > tp->pathmtu)
++                              if (chunk == packet->auth)
++                                      auth_len = padded;
++                              else if (auth_len + padded + packet->overhead >
++                                       tp->pathmtu)
++                                      goto nomem;
++                              else if (pkt_size + padded > tp->pathmtu)
+                                       break;
+                               pkt_size += padded;
+                       }
+diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
+index d88bb2b0b699..920469e7b0ef 100644
+--- a/net/sctp/sm_statefuns.c
++++ b/net/sctp/sm_statefuns.c
+@@ -3422,6 +3422,12 @@ sctp_disposition_t sctp_sf_ootb(struct net *net,
+                       return sctp_sf_violation_chunklen(net, ep, asoc, type, 
arg,
+                                                 commands);
+ 
++              /* Report violation if chunk len overflows */
++              ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
++              if (ch_end > skb_tail_pointer(skb))
++                      return sctp_sf_violation_chunklen(net, ep, asoc, type, 
arg,
++                                                commands);
++
+               /* Now that we know we at least have a chunk header,
+                * do things that are type appropriate.
+                */
+@@ -3453,12 +3459,6 @@ sctp_disposition_t sctp_sf_ootb(struct net *net,
+                       }
+               }
+ 
+-              /* Report violation if chunk len overflows */
+-              ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
+-              if (ch_end > skb_tail_pointer(skb))
+-                      return sctp_sf_violation_chunklen(net, ep, asoc, type, 
arg,
+-                                                commands);
+-
+               ch = (sctp_chunkhdr_t *) ch_end;
+       } while (ch_end < skb_tail_pointer(skb));
+ 
+diff --git a/net/sctp/socket.c b/net/sctp/socket.c
+index 8ed2d99bde6d..baccbf3c1c60 100644
+--- a/net/sctp/socket.c
++++ b/net/sctp/socket.c
+@@ -4683,7 +4683,7 @@ static int sctp_getsockopt_disable_fragments(struct sock 
*sk, int len,
+ static int sctp_getsockopt_events(struct sock *sk, int len, char __user 
*optval,
+                                 int __user *optlen)
+ {
+-      if (len <= 0)
++      if (len == 0)
+               return -EINVAL;
+       if (len > sizeof(struct sctp_event_subscribe))
+               len = sizeof(struct sctp_event_subscribe);
+@@ -6426,6 +6426,9 @@ static int sctp_getsockopt(struct sock *sk, int level, 
int optname,
+       if (get_user(len, optlen))
+               return -EFAULT;
+ 
++      if (len < 0)
++              return -EINVAL;
++
+       lock_sock(sk);
+ 
+       switch (optname) {
+diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c
+index a5fc9dd24aa9..a56c5e6f4498 100644
+--- a/net/switchdev/switchdev.c
++++ b/net/switchdev/switchdev.c
+@@ -774,6 +774,9 @@ int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 
pid, u32 seq,
+       u32 mask = BR_LEARNING | BR_LEARNING_SYNC | BR_FLOOD;
+       int err;
+ 
++      if (!netif_is_bridge_port(dev))
++              return -EOPNOTSUPP;
++
+       err = switchdev_port_attr_get(dev, &attr);
+       if (err && err != -EOPNOTSUPP)
+               return err;
+@@ -929,6 +932,9 @@ int switchdev_port_bridge_setlink(struct net_device *dev,
+       struct nlattr *afspec;
+       int err = 0;
+ 
++      if (!netif_is_bridge_port(dev))
++              return -EOPNOTSUPP;
++
+       protinfo = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg),
+                                  IFLA_PROTINFO);
+       if (protinfo) {
+@@ -962,6 +968,9 @@ int switchdev_port_bridge_dellink(struct net_device *dev,
+ {
+       struct nlattr *afspec;
+ 
++      if (!netif_is_bridge_port(dev))
++              return -EOPNOTSUPP;
++
+       afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg),
+                                IFLA_AF_SPEC);
+       if (afspec)

Reply via email to