commit:     516de23c184688cd1071c1c815fbb2e9827612ad
Author:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
AuthorDate: Sat Oct  3 16:07:16 2015 +0000
Commit:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
CommitDate: Sat Oct  3 16:07:16 2015 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=516de23c

Linux patch 4.1.10

 0000_README             |    4 +
 1009_linux-4.1.10.patch | 1353 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1357 insertions(+)

diff --git a/0000_README b/0000_README
index 348e8f5..b9b941a 100644
--- a/0000_README
+++ b/0000_README
@@ -79,6 +79,10 @@ Patch:  1008_linux-4.1.9.patch
 From:   http://www.kernel.org
 Desc:   Linux 4.1.9
 
+Patch:  1009_linux-4.1.10.patch
+From:   http://www.kernel.org
+Desc:   Linux 4.1.10
+
 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/1009_linux-4.1.10.patch b/1009_linux-4.1.10.patch
new file mode 100644
index 0000000..8d80808
--- /dev/null
+++ b/1009_linux-4.1.10.patch
@@ -0,0 +1,1353 @@
+diff --git a/Documentation/devicetree/bindings/net/ethernet.txt 
b/Documentation/devicetree/bindings/net/ethernet.txt
+index 41b3f3f864e8..5d88f37480b6 100644
+--- a/Documentation/devicetree/bindings/net/ethernet.txt
++++ b/Documentation/devicetree/bindings/net/ethernet.txt
+@@ -25,7 +25,11 @@ The following properties are common to the Ethernet 
controllers:
+   flow control thresholds.
+ - tx-fifo-depth: the size of the controller's transmit fifo in bytes. This
+   is used for components that can have configurable fifo sizes.
++- managed: string, specifies the PHY management type. Supported values are:
++  "auto", "in-band-status". "auto" is the default, it usess MDIO for
++  management if fixed-link is not specified.
+ 
+ Child nodes of the Ethernet controller are typically the individual PHY 
devices
+ connected via the MDIO bus (sometimes the MDIO bus controller is separate).
+ They are described in the phy.txt file in this same directory.
++For non-MDIO PHY management see fixed-link.txt.
+diff --git a/Makefile b/Makefile
+index e071176b2ce6..d02f16b510dc 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,6 +1,6 @@
+ VERSION = 4
+ PATCHLEVEL = 1
+-SUBLEVEL = 9
++SUBLEVEL = 10
+ EXTRAVERSION =
+ NAME = Series 4800
+ 
+diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
+index f1ff39a3d1c1..54d946a9eee6 100644
+--- a/drivers/block/zram/zcomp.c
++++ b/drivers/block/zram/zcomp.c
+@@ -325,12 +325,14 @@ void zcomp_destroy(struct zcomp *comp)
+  * allocate new zcomp and initialize it. return compressing
+  * backend pointer or ERR_PTR if things went bad. ERR_PTR(-EINVAL)
+  * if requested algorithm is not supported, ERR_PTR(-ENOMEM) in
+- * case of allocation error.
++ * case of allocation error, or any other error potentially
++ * returned by functions zcomp_strm_{multi,single}_create.
+  */
+ struct zcomp *zcomp_create(const char *compress, int max_strm)
+ {
+       struct zcomp *comp;
+       struct zcomp_backend *backend;
++      int error;
+ 
+       backend = find_backend(compress);
+       if (!backend)
+@@ -342,12 +344,12 @@ struct zcomp *zcomp_create(const char *compress, int 
max_strm)
+ 
+       comp->backend = backend;
+       if (max_strm > 1)
+-              zcomp_strm_multi_create(comp, max_strm);
++              error = zcomp_strm_multi_create(comp, max_strm);
+       else
+-              zcomp_strm_single_create(comp);
+-      if (!comp->stream) {
++              error = zcomp_strm_single_create(comp);
++      if (error) {
+               kfree(comp);
+-              return ERR_PTR(-ENOMEM);
++              return ERR_PTR(error);
+       }
+       return comp;
+ }
+diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
+index cedb572bf25a..db9ebbc1a732 100644
+--- a/drivers/net/dsa/bcm_sf2.c
++++ b/drivers/net/dsa/bcm_sf2.c
+@@ -417,7 +417,7 @@ static int bcm_sf2_sw_fast_age_port(struct dsa_switch  
*ds, int port)
+       core_writel(priv, port, CORE_FAST_AGE_PORT);
+ 
+       reg = core_readl(priv, CORE_FAST_AGE_CTRL);
+-      reg |= EN_AGE_PORT | FAST_AGE_STR_DONE;
++      reg |= EN_AGE_PORT | EN_AGE_DYNAMIC | FAST_AGE_STR_DONE;
+       core_writel(priv, reg, CORE_FAST_AGE_CTRL);
+ 
+       do {
+@@ -431,6 +431,8 @@ static int bcm_sf2_sw_fast_age_port(struct dsa_switch  
*ds, int port)
+       if (!timeout)
+               return -ETIMEDOUT;
+ 
++      core_writel(priv, 0, CORE_FAST_AGE_CTRL);
++
+       return 0;
+ }
+ 
+@@ -506,7 +508,7 @@ static int bcm_sf2_sw_br_set_stp_state(struct dsa_switch 
*ds, int port,
+       u32 reg;
+ 
+       reg = core_readl(priv, CORE_G_PCTL_PORT(port));
+-      cur_hw_state = reg >> G_MISTP_STATE_SHIFT;
++      cur_hw_state = reg & (G_MISTP_STATE_MASK << G_MISTP_STATE_SHIFT);
+ 
+       switch (state) {
+       case BR_STATE_DISABLED:
+@@ -530,10 +532,12 @@ static int bcm_sf2_sw_br_set_stp_state(struct dsa_switch 
*ds, int port,
+       }
+ 
+       /* Fast-age ARL entries if we are moving a port from Learning or
+-       * Forwarding state to Disabled, Blocking or Listening state
++       * Forwarding (cur_hw_state) state to Disabled, Blocking or Listening
++       * state (hw_state)
+        */
+       if (cur_hw_state != hw_state) {
+-              if (cur_hw_state & 4 && !(hw_state & 4)) {
++              if (cur_hw_state >= G_MISTP_LEARN_STATE &&
++                  hw_state <= G_MISTP_LISTEN_STATE) {
+                       ret = bcm_sf2_sw_fast_age_port(ds, port);
+                       if (ret) {
+                               pr_err("%s: fast-ageing failed\n", __func__);
+@@ -889,15 +893,11 @@ static void bcm_sf2_sw_fixed_link_update(struct 
dsa_switch *ds, int port,
+                                        struct fixed_phy_status *status)
+ {
+       struct bcm_sf2_priv *priv = ds_to_priv(ds);
+-      u32 duplex, pause, speed;
++      u32 duplex, pause;
+       u32 reg;
+ 
+       duplex = core_readl(priv, CORE_DUPSTS);
+       pause = core_readl(priv, CORE_PAUSESTS);
+-      speed = core_readl(priv, CORE_SPDSTS);
+-
+-      speed >>= (port * SPDSTS_SHIFT);
+-      speed &= SPDSTS_MASK;
+ 
+       status->link = 0;
+ 
+@@ -925,18 +925,6 @@ static void bcm_sf2_sw_fixed_link_update(struct 
dsa_switch *ds, int port,
+               reg &= ~LINK_STS;
+       core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(port));
+ 
+-      switch (speed) {
+-      case SPDSTS_10:
+-              status->speed = SPEED_10;
+-              break;
+-      case SPDSTS_100:
+-              status->speed = SPEED_100;
+-              break;
+-      case SPDSTS_1000:
+-              status->speed = SPEED_1000;
+-              break;
+-      }
+-
+       if ((pause & (1 << port)) &&
+           (pause & (1 << (port + PAUSESTS_TX_PAUSE_SHIFT)))) {
+               status->asym_pause = 1;
+diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h
+index 22e2ebf31333..789d7b7737da 100644
+--- a/drivers/net/dsa/bcm_sf2.h
++++ b/drivers/net/dsa/bcm_sf2.h
+@@ -112,8 +112,8 @@ static inline u64 name##_readq(struct bcm_sf2_priv *priv, 
u32 off) \
+       spin_unlock(&priv->indir_lock);                                 \
+       return (u64)indir << 32 | dir;                                  \
+ }                                                                     \
+-static inline void name##_writeq(struct bcm_sf2_priv *priv, u32 off,  \
+-                                                      u64 val)        \
++static inline void name##_writeq(struct bcm_sf2_priv *priv, u64 val,  \
++                                                      u32 off)        \
+ {                                                                     \
+       spin_lock(&priv->indir_lock);                                   \
+       reg_writel(priv, upper_32_bits(val), REG_DIR_DATA_WRITE);       \
+diff --git a/drivers/net/ethernet/altera/altera_tse_main.c 
b/drivers/net/ethernet/altera/altera_tse_main.c
+index da48e66377b5..8207877d6237 100644
+--- a/drivers/net/ethernet/altera/altera_tse_main.c
++++ b/drivers/net/ethernet/altera/altera_tse_main.c
+@@ -511,8 +511,7 @@ static int tse_poll(struct napi_struct *napi, int budget)
+ 
+       if (rxcomplete < budget) {
+ 
+-              napi_gro_flush(napi, false);
+-              __napi_complete(napi);
++              napi_complete(napi);
+ 
+               netdev_dbg(priv->dev,
+                          "NAPI Complete, did %d packets with budget %d\n",
+diff --git a/drivers/net/ethernet/freescale/fec_main.c 
b/drivers/net/ethernet/freescale/fec_main.c
+index 66d47e448e4d..570390b5cd42 100644
+--- a/drivers/net/ethernet/freescale/fec_main.c
++++ b/drivers/net/ethernet/freescale/fec_main.c
+@@ -1396,6 +1396,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, 
u16 queue_id)
+               if ((status & BD_ENET_RX_LAST) == 0)
+                       netdev_err(ndev, "rcv is not +last\n");
+ 
++              writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT);
+ 
+               /* Check for errors. */
+               if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
+diff --git a/drivers/net/ethernet/marvell/mvneta.c 
b/drivers/net/ethernet/marvell/mvneta.c
+index 74d0389bf233..4d608f0117cd 100644
+--- a/drivers/net/ethernet/marvell/mvneta.c
++++ b/drivers/net/ethernet/marvell/mvneta.c
+@@ -3029,8 +3029,8 @@ static int mvneta_probe(struct platform_device *pdev)
+       const char *dt_mac_addr;
+       char hw_mac_addr[ETH_ALEN];
+       const char *mac_from;
++      const char *managed;
+       int phy_mode;
+-      int fixed_phy = 0;
+       int err;
+ 
+       /* Our multiqueue support is not complete, so for now, only
+@@ -3064,7 +3064,6 @@ static int mvneta_probe(struct platform_device *pdev)
+                       dev_err(&pdev->dev, "cannot register fixed PHY\n");
+                       goto err_free_irq;
+               }
+-              fixed_phy = 1;
+ 
+               /* In the case of a fixed PHY, the DT node associated
+                * to the PHY is the Ethernet MAC DT node.
+@@ -3088,8 +3087,10 @@ static int mvneta_probe(struct platform_device *pdev)
+       pp = netdev_priv(dev);
+       pp->phy_node = phy_node;
+       pp->phy_interface = phy_mode;
+-      pp->use_inband_status = (phy_mode == PHY_INTERFACE_MODE_SGMII) &&
+-                              fixed_phy;
++
++      err = of_property_read_string(dn, "managed", &managed);
++      pp->use_inband_status = (err == 0 &&
++                               strcmp(managed, "in-band-status") == 0);
+ 
+       pp->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(pp->clk)) {
+diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c 
b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+index eab4e080ebd2..80aac20104de 100644
+--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
++++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+@@ -1256,8 +1256,6 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
+               rss_context->hash_fn = MLX4_RSS_HASH_TOP;
+               memcpy(rss_context->rss_key, priv->rss_key,
+                      MLX4_EN_RSS_KEY_SIZE);
+-              netdev_rss_key_fill(rss_context->rss_key,
+-                                  MLX4_EN_RSS_KEY_SIZE);
+       } else {
+               en_err(priv, "Unknown RSS hash function requested\n");
+               err = -EINVAL;
+diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
+index 8c350c5d54ad..58858c5589db 100644
+--- a/drivers/net/macvtap.c
++++ b/drivers/net/macvtap.c
+@@ -1054,10 +1054,10 @@ static long macvtap_ioctl(struct file *file, unsigned 
int cmd,
+               return 0;
+ 
+       case TUNSETSNDBUF:
+-              if (get_user(u, up))
++              if (get_user(s, sp))
+                       return -EFAULT;
+ 
+-              q->sk.sk_sndbuf = u;
++              q->sk.sk_sndbuf = s;
+               return 0;
+ 
+       case TUNGETVNETHDRSZ:
+diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c
+index 1960b46add65..479b93f9581c 100644
+--- a/drivers/net/phy/fixed_phy.c
++++ b/drivers/net/phy/fixed_phy.c
+@@ -52,6 +52,10 @@ static int fixed_phy_update_regs(struct fixed_phy *fp)
+       u16 lpagb = 0;
+       u16 lpa = 0;
+ 
++      if (!fp->status.link)
++              goto done;
++      bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
++
+       if (fp->status.duplex) {
+               bmcr |= BMCR_FULLDPLX;
+ 
+@@ -96,15 +100,13 @@ static int fixed_phy_update_regs(struct fixed_phy *fp)
+               }
+       }
+ 
+-      if (fp->status.link)
+-              bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
+-
+       if (fp->status.pause)
+               lpa |= LPA_PAUSE_CAP;
+ 
+       if (fp->status.asym_pause)
+               lpa |= LPA_PAUSE_ASYM;
+ 
++done:
+       fp->regs[MII_PHYSID1] = 0;
+       fp->regs[MII_PHYSID2] = 0;
+ 
+diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
+index 3c86b107275a..e0498571ae26 100644
+--- a/drivers/net/usb/usbnet.c
++++ b/drivers/net/usb/usbnet.c
+@@ -778,7 +778,7 @@ int usbnet_stop (struct net_device *net)
+ {
+       struct usbnet           *dev = netdev_priv(net);
+       struct driver_info      *info = dev->driver_info;
+-      int                     retval, pm;
++      int                     retval, pm, mpn;
+ 
+       clear_bit(EVENT_DEV_OPEN, &dev->flags);
+       netif_stop_queue (net);
+@@ -809,6 +809,8 @@ int usbnet_stop (struct net_device *net)
+ 
+       usbnet_purge_paused_rxq(dev);
+ 
++      mpn = !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags);
++
+       /* deferred work (task, timer, softirq) must also stop.
+        * can't flush_scheduled_work() until we drop rtnl (later),
+        * else workers could deadlock; so make workers a NOP.
+@@ -819,8 +821,7 @@ int usbnet_stop (struct net_device *net)
+       if (!pm)
+               usb_autopm_put_interface(dev->intf);
+ 
+-      if (info->manage_power &&
+-          !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags))
++      if (info->manage_power && mpn)
+               info->manage_power(dev, 0);
+       else
+               usb_autopm_put_interface(dev->intf);
+diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
+index 21a0fbf1ed94..0085b8df83e2 100644
+--- a/drivers/net/vxlan.c
++++ b/drivers/net/vxlan.c
+@@ -2212,6 +2212,8 @@ static int vxlan_open(struct net_device *dev)
+ 
+       if (vxlan_addr_multicast(&vxlan->default_dst.remote_ip)) {
+               ret = vxlan_igmp_join(vxlan);
++              if (ret == -EADDRINUSE)
++                      ret = 0;
+               if (ret) {
+                       vxlan_sock_release(vs);
+                       return ret;
+diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
+index 0c064485d1c2..bec8ec2b31f6 100644
+--- a/drivers/of/of_mdio.c
++++ b/drivers/of/of_mdio.c
+@@ -263,7 +263,8 @@ EXPORT_SYMBOL(of_phy_attach);
+ bool of_phy_is_fixed_link(struct device_node *np)
+ {
+       struct device_node *dn;
+-      int len;
++      int len, err;
++      const char *managed;
+ 
+       /* New binding */
+       dn = of_get_child_by_name(np, "fixed-link");
+@@ -272,6 +273,10 @@ bool of_phy_is_fixed_link(struct device_node *np)
+               return true;
+       }
+ 
++      err = of_property_read_string(np, "managed", &managed);
++      if (err == 0 && strcmp(managed, "auto") != 0)
++              return true;
++
+       /* Old binding */
+       if (of_get_property(np, "fixed-link", &len) &&
+           len == (5 * sizeof(__be32)))
+@@ -286,8 +291,18 @@ int of_phy_register_fixed_link(struct device_node *np)
+       struct fixed_phy_status status = {};
+       struct device_node *fixed_link_node;
+       const __be32 *fixed_link_prop;
+-      int len;
++      int len, err;
+       struct phy_device *phy;
++      const char *managed;
++
++      err = of_property_read_string(np, "managed", &managed);
++      if (err == 0) {
++              if (strcmp(managed, "in-band-status") == 0) {
++                      /* status is zeroed, namely its .link member */
++                      phy = fixed_phy_register(PHY_POLL, &status, np);
++                      return IS_ERR(phy) ? PTR_ERR(phy) : 0;
++              }
++      }
+ 
+       /* New binding */
+       fixed_link_node = of_get_child_by_name(np, "fixed-link");
+diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
+index 06697315a088..fb4dd7b3ee71 100644
+--- a/drivers/platform/x86/hp-wmi.c
++++ b/drivers/platform/x86/hp-wmi.c
+@@ -54,8 +54,9 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
+ #define HPWMI_HARDWARE_QUERY 0x4
+ #define HPWMI_WIRELESS_QUERY 0x5
+ #define HPWMI_BIOS_QUERY 0x9
++#define HPWMI_FEATURE_QUERY 0xb
+ #define HPWMI_HOTKEY_QUERY 0xc
+-#define HPWMI_FEATURE_QUERY 0xd
++#define HPWMI_FEATURE2_QUERY 0xd
+ #define HPWMI_WIRELESS2_QUERY 0x1b
+ #define HPWMI_POSTCODEERROR_QUERY 0x2a
+ 
+@@ -295,25 +296,33 @@ static int hp_wmi_tablet_state(void)
+       return (state & 0x4) ? 1 : 0;
+ }
+ 
+-static int __init hp_wmi_bios_2009_later(void)
++static int __init hp_wmi_bios_2008_later(void)
+ {
+       int state = 0;
+       int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, 0, &state,
+                                      sizeof(state), sizeof(state));
+-      if (ret)
+-              return ret;
++      if (!ret)
++              return 1;
+ 
+-      return (state & 0x10) ? 1 : 0;
++      return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO;
+ }
+ 
+-static int hp_wmi_enable_hotkeys(void)
++static int __init hp_wmi_bios_2009_later(void)
+ {
+-      int ret;
+-      int query = 0x6e;
++      int state = 0;
++      int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, 0, &state,
++                                     sizeof(state), sizeof(state));
++      if (!ret)
++              return 1;
+ 
+-      ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &query, sizeof(query),
+-                                 0);
++      return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO;
++}
+ 
++static int __init hp_wmi_enable_hotkeys(void)
++{
++      int value = 0x6e;
++      int ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &value,
++                                     sizeof(value), 0);
+       if (ret)
+               return -EINVAL;
+       return 0;
+@@ -663,7 +672,7 @@ static int __init hp_wmi_input_setup(void)
+                           hp_wmi_tablet_state());
+       input_sync(hp_wmi_input_dev);
+ 
+-      if (hp_wmi_bios_2009_later() == 4)
++      if (!hp_wmi_bios_2009_later() && hp_wmi_bios_2008_later())
+               hp_wmi_enable_hotkeys();
+ 
+       status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, 
NULL);
+diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
+index ff667e18b2d6..9ba383f5b0c4 100644
+--- a/net/bridge/br_multicast.c
++++ b/net/bridge/br_multicast.c
+@@ -980,7 +980,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge 
*br,
+ 
+       ih = igmpv3_report_hdr(skb);
+       num = ntohs(ih->ngrec);
+-      len = sizeof(*ih);
++      len = skb_transport_offset(skb) + sizeof(*ih);
+ 
+       for (i = 0; i < num; i++) {
+               len += sizeof(*grec);
+@@ -1035,7 +1035,7 @@ static int br_ip6_multicast_mld2_report(struct 
net_bridge *br,
+ 
+       icmp6h = icmp6_hdr(skb);
+       num = ntohs(icmp6h->icmp6_dataun.un_data16[1]);
+-      len = sizeof(*icmp6h);
++      len = skb_transport_offset(skb) + sizeof(*icmp6h);
+ 
+       for (i = 0; i < num; i++) {
+               __be16 *nsrcs, _nsrcs;
+diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
+index 9a12668f7d62..0ad144fb0c79 100644
+--- a/net/core/fib_rules.c
++++ b/net/core/fib_rules.c
+@@ -615,15 +615,17 @@ static int dump_rules(struct sk_buff *skb, struct 
netlink_callback *cb,
+ {
+       int idx = 0;
+       struct fib_rule *rule;
++      int err = 0;
+ 
+       rcu_read_lock();
+       list_for_each_entry_rcu(rule, &ops->rules_list, list) {
+               if (idx < cb->args[1])
+                       goto skip;
+ 
+-              if (fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).portid,
+-                                   cb->nlh->nlmsg_seq, RTM_NEWRULE,
+-                                   NLM_F_MULTI, ops) < 0)
++              err = fib_nl_fill_rule(skb, rule, NETLINK_CB(cb->skb).portid,
++                                     cb->nlh->nlmsg_seq, RTM_NEWRULE,
++                                     NLM_F_MULTI, ops);
++              if (err)
+                       break;
+ skip:
+               idx++;
+@@ -632,7 +634,7 @@ skip:
+       cb->args[1] = idx;
+       rules_ops_put(ops);
+ 
+-      return skb->len;
++      return err;
+ }
+ 
+ static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb)
+@@ -648,7 +650,9 @@ static int fib_nl_dumprule(struct sk_buff *skb, struct 
netlink_callback *cb)
+               if (ops == NULL)
+                       return -EAFNOSUPPORT;
+ 
+-              return dump_rules(skb, cb, ops);
++              dump_rules(skb, cb, ops);
++
++              return skb->len;
+       }
+ 
+       rcu_read_lock();
+diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
+index 74dddf84adcd..556ecf96a385 100644
+--- a/net/core/sock_diag.c
++++ b/net/core/sock_diag.c
+@@ -86,6 +86,9 @@ int sock_diag_put_filterinfo(bool may_report_filterinfo, 
struct sock *sk,
+               goto out;
+ 
+       fprog = filter->prog->orig_prog;
++      if (!fprog)
++              goto out;
++
+       flen = bpf_classic_proglen(fprog);
+ 
+       attr = nla_reserve(skb, attrtype, flen);
+diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
+index a369e8a70b2c..986440b24978 100644
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -2893,6 +2893,7 @@ void tcp_send_active_reset(struct sock *sk, gfp_t 
priority)
+       skb_reserve(skb, MAX_TCP_HEADER);
+       tcp_init_nondata_skb(skb, tcp_acceptable_seq(sk),
+                            TCPHDR_ACK | TCPHDR_RST);
++      skb_mstamp_get(&skb->skb_mstamp);
+       /* Send it off. */
+       if (tcp_transmit_skb(sk, skb, 0, priority))
+               NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTFAILED);
+diff --git a/net/ipv6/exthdrs_offload.c b/net/ipv6/exthdrs_offload.c
+index 447a7fbd1bb6..f5e2ba1c18bf 100644
+--- a/net/ipv6/exthdrs_offload.c
++++ b/net/ipv6/exthdrs_offload.c
+@@ -36,6 +36,6 @@ out:
+       return ret;
+ 
+ out_rt:
+-      inet_del_offload(&rthdr_offload, IPPROTO_ROUTING);
++      inet6_del_offload(&rthdr_offload, IPPROTO_ROUTING);
+       goto out;
+ }
+diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
+index a38d3ac0f18f..69f4f689f06a 100644
+--- a/net/ipv6/ip6_gre.c
++++ b/net/ipv6/ip6_gre.c
+@@ -361,6 +361,7 @@ static void ip6gre_tunnel_uninit(struct net_device *dev)
+       struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id);
+ 
+       ip6gre_tunnel_unlink(ign, t);
++      ip6_tnl_dst_reset(t);
+       dev_put(dev);
+ }
+ 
+diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
+index 74ceb73c1c9a..5f36266b1f5e 100644
+--- a/net/ipv6/ip6mr.c
++++ b/net/ipv6/ip6mr.c
+@@ -550,7 +550,7 @@ static void ipmr_mfc_seq_stop(struct seq_file *seq, void 
*v)
+ 
+       if (it->cache == &mrt->mfc6_unres_queue)
+               spin_unlock_bh(&mfc_unres_lock);
+-      else if (it->cache == mrt->mfc6_cache_array)
++      else if (it->cache == &mrt->mfc6_cache_array[it->ct])
+               read_unlock(&mrt_lock);
+ }
+ 
+diff --git a/net/ipv6/route.c b/net/ipv6/route.c
+index c73ae5039e46..f371fefa7fdc 100644
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -1515,7 +1515,7 @@ static int ip6_convert_metrics(struct mx6_config *mxc,
+       return -EINVAL;
+ }
+ 
+-int ip6_route_add(struct fib6_config *cfg)
++int ip6_route_info_create(struct fib6_config *cfg, struct rt6_info **rt_ret)
+ {
+       int err;
+       struct net *net = cfg->fc_nlinfo.nl_net;
+@@ -1523,7 +1523,6 @@ int ip6_route_add(struct fib6_config *cfg)
+       struct net_device *dev = NULL;
+       struct inet6_dev *idev = NULL;
+       struct fib6_table *table;
+-      struct mx6_config mxc = { .mx = NULL, };
+       int addr_type;
+ 
+       if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128)
+@@ -1719,6 +1718,32 @@ install_route:
+ 
+       cfg->fc_nlinfo.nl_net = dev_net(dev);
+ 
++      *rt_ret = rt;
++
++      return 0;
++out:
++      if (dev)
++              dev_put(dev);
++      if (idev)
++              in6_dev_put(idev);
++      if (rt)
++              dst_free(&rt->dst);
++
++      *rt_ret = NULL;
++
++      return err;
++}
++
++int ip6_route_add(struct fib6_config *cfg)
++{
++      struct mx6_config mxc = { .mx = NULL, };
++      struct rt6_info *rt = NULL;
++      int err;
++
++      err = ip6_route_info_create(cfg, &rt);
++      if (err)
++              goto out;
++
+       err = ip6_convert_metrics(&mxc, cfg);
+       if (err)
+               goto out;
+@@ -1726,14 +1751,12 @@ install_route:
+       err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc);
+ 
+       kfree(mxc.mx);
++
+       return err;
+ out:
+-      if (dev)
+-              dev_put(dev);
+-      if (idev)
+-              in6_dev_put(idev);
+       if (rt)
+               dst_free(&rt->dst);
++
+       return err;
+ }
+ 
+@@ -2496,19 +2519,78 @@ errout:
+       return err;
+ }
+ 
+-static int ip6_route_multipath(struct fib6_config *cfg, int add)
++struct rt6_nh {
++      struct rt6_info *rt6_info;
++      struct fib6_config r_cfg;
++      struct mx6_config mxc;
++      struct list_head next;
++};
++
++static void ip6_print_replace_route_err(struct list_head *rt6_nh_list)
++{
++      struct rt6_nh *nh;
++
++      list_for_each_entry(nh, rt6_nh_list, next) {
++              pr_warn("IPV6: multipath route replace failed (check 
consistency of installed routes): %pI6 nexthop %pI6 ifi %d\n",
++                      &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway,
++                      nh->r_cfg.fc_ifindex);
++      }
++}
++
++static int ip6_route_info_append(struct list_head *rt6_nh_list,
++                               struct rt6_info *rt, struct fib6_config *r_cfg)
++{
++      struct rt6_nh *nh;
++      struct rt6_info *rtnh;
++      int err = -EEXIST;
++
++      list_for_each_entry(nh, rt6_nh_list, next) {
++              /* check if rt6_info already exists */
++              rtnh = nh->rt6_info;
++
++              if (rtnh->dst.dev == rt->dst.dev &&
++                  rtnh->rt6i_idev == rt->rt6i_idev &&
++                  ipv6_addr_equal(&rtnh->rt6i_gateway,
++                                  &rt->rt6i_gateway))
++                      return err;
++      }
++
++      nh = kzalloc(sizeof(*nh), GFP_KERNEL);
++      if (!nh)
++              return -ENOMEM;
++      nh->rt6_info = rt;
++      err = ip6_convert_metrics(&nh->mxc, r_cfg);
++      if (err) {
++              kfree(nh);
++              return err;
++      }
++      memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg));
++      list_add_tail(&nh->next, rt6_nh_list);
++
++      return 0;
++}
++
++static int ip6_route_multipath_add(struct fib6_config *cfg)
+ {
+       struct fib6_config r_cfg;
+       struct rtnexthop *rtnh;
++      struct rt6_info *rt;
++      struct rt6_nh *err_nh;
++      struct rt6_nh *nh, *nh_safe;
+       int remaining;
+       int attrlen;
+-      int err = 0, last_err = 0;
++      int err = 1;
++      int nhn = 0;
++      int replace = (cfg->fc_nlinfo.nlh &&
++                     (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE));
++      LIST_HEAD(rt6_nh_list);
+ 
+       remaining = cfg->fc_mp_len;
+-beginning:
+       rtnh = (struct rtnexthop *)cfg->fc_mp;
+ 
+-      /* Parse a Multipath Entry */
++      /* Parse a Multipath Entry and build a list (rt6_nh_list) of
++       * rt6_info structs per nexthop
++       */
+       while (rtnh_ok(rtnh, remaining)) {
+               memcpy(&r_cfg, cfg, sizeof(*cfg));
+               if (rtnh->rtnh_ifindex)
+@@ -2524,22 +2606,32 @@ beginning:
+                               r_cfg.fc_flags |= RTF_GATEWAY;
+                       }
+               }
+-              err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg);
++
++              err = ip6_route_info_create(&r_cfg, &rt);
++              if (err)
++                      goto cleanup;
++
++              err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg);
+               if (err) {
+-                      last_err = err;
+-                      /* If we are trying to remove a route, do not stop the
+-                       * loop when ip6_route_del() fails (because next hop is
+-                       * already gone), we should try to remove all next hops.
+-                       */
+-                      if (add) {
+-                              /* If add fails, we should try to delete all
+-                               * next hops that have been already added.
+-                               */
+-                              add = 0;
+-                              remaining = cfg->fc_mp_len - remaining;
+-                              goto beginning;
+-                      }
++                      dst_free(&rt->dst);
++                      goto cleanup;
++              }
++
++              rtnh = rtnh_next(rtnh, &remaining);
++      }
++
++      err_nh = NULL;
++      list_for_each_entry(nh, &rt6_nh_list, next) {
++              err = __ip6_ins_rt(nh->rt6_info, &cfg->fc_nlinfo, &nh->mxc);
++              /* nh->rt6_info is used or freed at this point, reset to NULL*/
++              nh->rt6_info = NULL;
++              if (err) {
++                      if (replace && nhn)
++                              ip6_print_replace_route_err(&rt6_nh_list);
++                      err_nh = nh;
++                      goto add_errout;
+               }
++
+               /* Because each route is added like a single route we remove
+                * these flags after the first nexthop: if there is a collision,
+                * we have already failed to add the first nexthop:
+@@ -2549,6 +2641,63 @@ beginning:
+                */
+               cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL |
+                                                    NLM_F_REPLACE);
++              nhn++;
++      }
++
++      goto cleanup;
++
++add_errout:
++      /* Delete routes that were already added */
++      list_for_each_entry(nh, &rt6_nh_list, next) {
++              if (err_nh == nh)
++                      break;
++              ip6_route_del(&nh->r_cfg);
++      }
++
++cleanup:
++      list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) {
++              if (nh->rt6_info)
++                      dst_free(&nh->rt6_info->dst);
++              if (nh->mxc.mx)
++                      kfree(nh->mxc.mx);
++              list_del(&nh->next);
++              kfree(nh);
++      }
++
++      return err;
++}
++
++static int ip6_route_multipath_del(struct fib6_config *cfg)
++{
++      struct fib6_config r_cfg;
++      struct rtnexthop *rtnh;
++      int remaining;
++      int attrlen;
++      int err = 1, last_err = 0;
++
++      remaining = cfg->fc_mp_len;
++      rtnh = (struct rtnexthop *)cfg->fc_mp;
++
++      /* Parse a Multipath Entry */
++      while (rtnh_ok(rtnh, remaining)) {
++              memcpy(&r_cfg, cfg, sizeof(*cfg));
++              if (rtnh->rtnh_ifindex)
++                      r_cfg.fc_ifindex = rtnh->rtnh_ifindex;
++
++              attrlen = rtnh_attrlen(rtnh);
++              if (attrlen > 0) {
++                      struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
++
++                      nla = nla_find(attrs, attrlen, RTA_GATEWAY);
++                      if (nla) {
++                              nla_memcpy(&r_cfg.fc_gateway, nla, 16);
++                              r_cfg.fc_flags |= RTF_GATEWAY;
++                      }
++              }
++              err = ip6_route_del(&r_cfg);
++              if (err)
++                      last_err = err;
++
+               rtnh = rtnh_next(rtnh, &remaining);
+       }
+ 
+@@ -2565,7 +2714,7 @@ static int inet6_rtm_delroute(struct sk_buff *skb, 
struct nlmsghdr *nlh)
+               return err;
+ 
+       if (cfg.fc_mp)
+-              return ip6_route_multipath(&cfg, 0);
++              return ip6_route_multipath_del(&cfg);
+       else
+               return ip6_route_del(&cfg);
+ }
+@@ -2580,7 +2729,7 @@ static int inet6_rtm_newroute(struct sk_buff *skb, 
struct nlmsghdr *nlh)
+               return err;
+ 
+       if (cfg.fc_mp)
+-              return ip6_route_multipath(&cfg, 1);
++              return ip6_route_multipath_add(&cfg);
+       else
+               return ip6_route_add(&cfg);
+ }
+diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
+index 4856d975492d..980121e75d2e 100644
+--- a/net/netlink/af_netlink.c
++++ b/net/netlink/af_netlink.c
+@@ -123,6 +123,24 @@ static inline u32 netlink_group_mask(u32 group)
+       return group ? 1 << (group - 1) : 0;
+ }
+ 
++static struct sk_buff *netlink_to_full_skb(const struct sk_buff *skb,
++                                         gfp_t gfp_mask)
++{
++      unsigned int len = skb_end_offset(skb);
++      struct sk_buff *new;
++
++      new = alloc_skb(len, gfp_mask);
++      if (new == NULL)
++              return NULL;
++
++      NETLINK_CB(new).portid = NETLINK_CB(skb).portid;
++      NETLINK_CB(new).dst_group = NETLINK_CB(skb).dst_group;
++      NETLINK_CB(new).creds = NETLINK_CB(skb).creds;
++
++      memcpy(skb_put(new, len), skb->data, len);
++      return new;
++}
++
+ int netlink_add_tap(struct netlink_tap *nt)
+ {
+       if (unlikely(nt->dev->type != ARPHRD_NETLINK))
+@@ -204,7 +222,11 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb,
+       int ret = -ENOMEM;
+ 
+       dev_hold(dev);
+-      nskb = skb_clone(skb, GFP_ATOMIC);
++
++      if (netlink_skb_is_mmaped(skb) || is_vmalloc_addr(skb->head))
++              nskb = netlink_to_full_skb(skb, GFP_ATOMIC);
++      else
++              nskb = skb_clone(skb, GFP_ATOMIC);
+       if (nskb) {
+               nskb->dev = dev;
+               nskb->protocol = htons((u16) sk->sk_protocol);
+@@ -276,11 +298,6 @@ static void netlink_rcv_wake(struct sock *sk)
+ }
+ 
+ #ifdef CONFIG_NETLINK_MMAP
+-static bool netlink_skb_is_mmaped(const struct sk_buff *skb)
+-{
+-      return NETLINK_CB(skb).flags & NETLINK_SKB_MMAPED;
+-}
+-
+ static bool netlink_rx_is_mmaped(struct sock *sk)
+ {
+       return nlk_sk(sk)->rx_ring.pg_vec != NULL;
+@@ -832,7 +849,6 @@ static void netlink_ring_set_copied(struct sock *sk, 
struct sk_buff *skb)
+ }
+ 
+ #else /* CONFIG_NETLINK_MMAP */
+-#define netlink_skb_is_mmaped(skb)    false
+ #define netlink_rx_is_mmaped(sk)      false
+ #define netlink_tx_is_mmaped(sk)      false
+ #define netlink_mmap                  sock_no_mmap
+@@ -1080,8 +1096,8 @@ static int netlink_insert(struct sock *sk, u32 portid)
+ 
+       lock_sock(sk);
+ 
+-      err = -EBUSY;
+-      if (nlk_sk(sk)->portid)
++      err = nlk_sk(sk)->portid == portid ? 0 : -EBUSY;
++      if (nlk_sk(sk)->bound)
+               goto err;
+ 
+       err = -ENOMEM;
+@@ -1101,10 +1117,13 @@ static int netlink_insert(struct sock *sk, u32 portid)
+                       err = -EOVERFLOW;
+               if (err == -EEXIST)
+                       err = -EADDRINUSE;
+-              nlk_sk(sk)->portid = 0;
+               sock_put(sk);
+       }
+ 
++      /* We need to ensure that the socket is hashed and visible. */
++      smp_wmb();
++      nlk_sk(sk)->bound = portid;
++
+ err:
+       release_sock(sk);
+       return err;
+@@ -1484,6 +1503,7 @@ static int netlink_bind(struct socket *sock, struct 
sockaddr *addr,
+       struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;
+       int err;
+       long unsigned int groups = nladdr->nl_groups;
++      bool bound;
+ 
+       if (addr_len < sizeof(struct sockaddr_nl))
+               return -EINVAL;
+@@ -1500,9 +1520,14 @@ static int netlink_bind(struct socket *sock, struct 
sockaddr *addr,
+                       return err;
+       }
+ 
+-      if (nlk->portid)
++      bound = nlk->bound;
++      if (bound) {
++              /* Ensure nlk->portid is up-to-date. */
++              smp_rmb();
++
+               if (nladdr->nl_pid != nlk->portid)
+                       return -EINVAL;
++      }
+ 
+       if (nlk->netlink_bind && groups) {
+               int group;
+@@ -1518,7 +1543,10 @@ static int netlink_bind(struct socket *sock, struct 
sockaddr *addr,
+               }
+       }
+ 
+-      if (!nlk->portid) {
++      /* No need for barriers here as we return to user-space without
++       * using any of the bound attributes.
++       */
++      if (!bound) {
+               err = nladdr->nl_pid ?
+                       netlink_insert(sk, nladdr->nl_pid) :
+                       netlink_autobind(sock);
+@@ -1566,7 +1594,10 @@ static int netlink_connect(struct socket *sock, struct 
sockaddr *addr,
+           !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
+               return -EPERM;
+ 
+-      if (!nlk->portid)
++      /* No need for barriers here as we return to user-space without
++       * using any of the bound attributes.
++       */
++      if (!nlk->bound)
+               err = netlink_autobind(sock);
+ 
+       if (err == 0) {
+@@ -2323,10 +2354,13 @@ static int netlink_sendmsg(struct socket *sock, struct 
msghdr *msg, size_t len)
+               dst_group = nlk->dst_group;
+       }
+ 
+-      if (!nlk->portid) {
++      if (!nlk->bound) {
+               err = netlink_autobind(sock);
+               if (err)
+                       goto out;
++      } else {
++              /* Ensure nlk is hashed and visible. */
++              smp_rmb();
+       }
+ 
+       /* It's a really convoluted way for userland to ask for mmaped
+diff --git a/net/netlink/af_netlink.h b/net/netlink/af_netlink.h
+index 89008405d6b4..14437d9b1965 100644
+--- a/net/netlink/af_netlink.h
++++ b/net/netlink/af_netlink.h
+@@ -35,6 +35,7 @@ struct netlink_sock {
+       unsigned long           state;
+       size_t                  max_recvmsg_len;
+       wait_queue_head_t       wait;
++      bool                    bound;
+       bool                    cb_running;
+       struct netlink_callback cb;
+       struct mutex            *cb_mutex;
+@@ -59,6 +60,15 @@ static inline struct netlink_sock *nlk_sk(struct sock *sk)
+       return container_of(sk, struct netlink_sock, sk);
+ }
+ 
++static inline bool netlink_skb_is_mmaped(const struct sk_buff *skb)
++{
++#ifdef CONFIG_NETLINK_MMAP
++      return NETLINK_CB(skb).flags & NETLINK_SKB_MMAPED;
++#else
++      return false;
++#endif /* CONFIG_NETLINK_MMAP */
++}
++
+ struct netlink_table {
+       struct rhashtable       hash;
+       struct hlist_head       mc_list;
+diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
+index 096c6276e6b9..27e14962b504 100644
+--- a/net/openvswitch/datapath.c
++++ b/net/openvswitch/datapath.c
+@@ -906,7 +906,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct 
genl_info *info)
+       if (error)
+               goto err_kfree_flow;
+ 
+-      ovs_flow_mask_key(&new_flow->key, &key, &mask);
++      ovs_flow_mask_key(&new_flow->key, &key, true, &mask);
+ 
+       /* Extract flow identifier. */
+       error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],
+@@ -1033,7 +1033,7 @@ static struct sw_flow_actions *get_flow_actions(const 
struct nlattr *a,
+       struct sw_flow_key masked_key;
+       int error;
+ 
+-      ovs_flow_mask_key(&masked_key, key, mask);
++      ovs_flow_mask_key(&masked_key, key, true, mask);
+       error = ovs_nla_copy_actions(a, &masked_key, &acts, log);
+       if (error) {
+               OVS_NLERR(log,
+diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c
+index 4613df8c8290..aa349514e4cb 100644
+--- a/net/openvswitch/flow_table.c
++++ b/net/openvswitch/flow_table.c
+@@ -56,20 +56,21 @@ static u16 range_n_bytes(const struct sw_flow_key_range 
*range)
+ }
+ 
+ void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src,
+-                     const struct sw_flow_mask *mask)
++                     bool full, const struct sw_flow_mask *mask)
+ {
+-      const long *m = (const long *)((const u8 *)&mask->key +
+-                              mask->range.start);
+-      const long *s = (const long *)((const u8 *)src +
+-                              mask->range.start);
+-      long *d = (long *)((u8 *)dst + mask->range.start);
++      int start = full ? 0 : mask->range.start;
++      int len = full ? sizeof *dst : range_n_bytes(&mask->range);
++      const long *m = (const long *)((const u8 *)&mask->key + start);
++      const long *s = (const long *)((const u8 *)src + start);
++      long *d = (long *)((u8 *)dst + start);
+       int i;
+ 
+-      /* The memory outside of the 'mask->range' are not set since
+-       * further operations on 'dst' only uses contents within
+-       * 'mask->range'.
++      /* If 'full' is true then all of 'dst' is fully initialized. Otherwise,
++       * if 'full' is false the memory outside of the 'mask->range' is left
++       * uninitialized. This can be used as an optimization when further
++       * operations on 'dst' only use contents within 'mask->range'.
+        */
+-      for (i = 0; i < range_n_bytes(&mask->range); i += sizeof(long))
++      for (i = 0; i < len; i += sizeof(long))
+               *d++ = *s++ & *m++;
+ }
+ 
+@@ -473,7 +474,7 @@ static struct sw_flow *masked_flow_lookup(struct 
table_instance *ti,
+       u32 hash;
+       struct sw_flow_key masked_key;
+ 
+-      ovs_flow_mask_key(&masked_key, unmasked, mask);
++      ovs_flow_mask_key(&masked_key, unmasked, false, mask);
+       hash = flow_hash(&masked_key, &mask->range);
+       head = find_bucket(ti, hash);
+       hlist_for_each_entry_rcu(flow, head, flow_table.node[ti->node_ver]) {
+diff --git a/net/openvswitch/flow_table.h b/net/openvswitch/flow_table.h
+index 616eda10d955..2dd9900f533d 100644
+--- a/net/openvswitch/flow_table.h
++++ b/net/openvswitch/flow_table.h
+@@ -86,5 +86,5 @@ struct sw_flow *ovs_flow_tbl_lookup_ufid(struct flow_table *,
+ bool ovs_flow_cmp(const struct sw_flow *, const struct sw_flow_match *);
+ 
+ void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src,
+-                     const struct sw_flow_mask *mask);
++                     bool full, const struct sw_flow_mask *mask);
+ #endif /* flow_table.h */
+diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
+index 715e01e5910a..f23a3b68bba6 100644
+--- a/net/sched/cls_fw.c
++++ b/net/sched/cls_fw.c
+@@ -33,7 +33,6 @@
+ 
+ struct fw_head {
+       u32                     mask;
+-      bool                    mask_set;
+       struct fw_filter __rcu  *ht[HTSIZE];
+       struct rcu_head         rcu;
+ };
+@@ -84,7 +83,7 @@ static int fw_classify(struct sk_buff *skb, const struct 
tcf_proto *tp,
+                       }
+               }
+       } else {
+-              /* old method */
++              /* Old method: classify the packet using its skb mark. */
+               if (id && (TC_H_MAJ(id) == 0 ||
+                          !(TC_H_MAJ(id ^ tp->q->handle)))) {
+                       res->classid = id;
+@@ -114,14 +113,9 @@ static unsigned long fw_get(struct tcf_proto *tp, u32 
handle)
+ 
+ static int fw_init(struct tcf_proto *tp)
+ {
+-      struct fw_head *head;
+-
+-      head = kzalloc(sizeof(struct fw_head), GFP_KERNEL);
+-      if (head == NULL)
+-              return -ENOBUFS;
+-
+-      head->mask_set = false;
+-      rcu_assign_pointer(tp->root, head);
++      /* We don't allocate fw_head here, because in the old method
++       * we don't need it at all.
++       */
+       return 0;
+ }
+ 
+@@ -252,7 +246,7 @@ static int fw_change(struct net *net, struct sk_buff 
*in_skb,
+       int err;
+ 
+       if (!opt)
+-              return handle ? -EINVAL : 0;
++              return handle ? -EINVAL : 0; /* Succeed if it is old method. */
+ 
+       err = nla_parse_nested(tb, TCA_FW_MAX, opt, fw_policy);
+       if (err < 0)
+@@ -302,11 +296,17 @@ static int fw_change(struct net *net, struct sk_buff 
*in_skb,
+       if (!handle)
+               return -EINVAL;
+ 
+-      if (!head->mask_set) {
+-              head->mask = 0xFFFFFFFF;
++      if (!head) {
++              u32 mask = 0xFFFFFFFF;
+               if (tb[TCA_FW_MASK])
+-                      head->mask = nla_get_u32(tb[TCA_FW_MASK]);
+-              head->mask_set = true;
++                      mask = nla_get_u32(tb[TCA_FW_MASK]);
++
++              head = kzalloc(sizeof(*head), GFP_KERNEL);
++              if (!head)
++                      return -ENOBUFS;
++              head->mask = mask;
++
++              rcu_assign_pointer(tp->root, head);
+       }
+ 
+       f = kzalloc(sizeof(struct fw_filter), GFP_KERNEL);
+diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
+index cab9e9b43967..4fbb67430ce4 100644
+--- a/net/sched/cls_u32.c
++++ b/net/sched/cls_u32.c
+@@ -490,6 +490,19 @@ static bool u32_destroy(struct tcf_proto *tp, bool force)
+                                       return false;
+                       }
+               }
++
++              if (tp_c->refcnt > 1)
++                      return false;
++
++              if (tp_c->refcnt == 1) {
++                      struct tc_u_hnode *ht;
++
++                      for (ht = rtnl_dereference(tp_c->hlist);
++                           ht;
++                           ht = rtnl_dereference(ht->next))
++                              if (!ht_empty(ht))
++                                      return false;
++              }
+       }
+ 
+       if (root_ht && --root_ht->refcnt == 0)
+diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
+index 53b7acde9aa3..e13c3c3ea4ac 100644
+--- a/net/sctp/protocol.c
++++ b/net/sctp/protocol.c
+@@ -1166,7 +1166,7 @@ static void sctp_v4_del_protocol(void)
+       unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
+ }
+ 
+-static int __net_init sctp_net_init(struct net *net)
++static int __net_init sctp_defaults_init(struct net *net)
+ {
+       int status;
+ 
+@@ -1259,12 +1259,6 @@ static int __net_init sctp_net_init(struct net *net)
+ 
+       sctp_dbg_objcnt_init(net);
+ 
+-      /* Initialize the control inode/socket for handling OOTB packets.  */
+-      if ((status = sctp_ctl_sock_init(net))) {
+-              pr_err("Failed to initialize the SCTP control sock\n");
+-              goto err_ctl_sock_init;
+-      }
+-
+       /* Initialize the local address list. */
+       INIT_LIST_HEAD(&net->sctp.local_addr_list);
+       spin_lock_init(&net->sctp.local_addr_lock);
+@@ -1280,9 +1274,6 @@ static int __net_init sctp_net_init(struct net *net)
+ 
+       return 0;
+ 
+-err_ctl_sock_init:
+-      sctp_dbg_objcnt_exit(net);
+-      sctp_proc_exit(net);
+ err_init_proc:
+       cleanup_sctp_mibs(net);
+ err_init_mibs:
+@@ -1291,15 +1282,12 @@ err_sysctl_register:
+       return status;
+ }
+ 
+-static void __net_exit sctp_net_exit(struct net *net)
++static void __net_exit sctp_defaults_exit(struct net *net)
+ {
+       /* Free the local address list */
+       sctp_free_addr_wq(net);
+       sctp_free_local_addr_list(net);
+ 
+-      /* Free the control endpoint.  */
+-      inet_ctl_sock_destroy(net->sctp.ctl_sock);
+-
+       sctp_dbg_objcnt_exit(net);
+ 
+       sctp_proc_exit(net);
+@@ -1307,9 +1295,32 @@ static void __net_exit sctp_net_exit(struct net *net)
+       sctp_sysctl_net_unregister(net);
+ }
+ 
+-static struct pernet_operations sctp_net_ops = {
+-      .init = sctp_net_init,
+-      .exit = sctp_net_exit,
++static struct pernet_operations sctp_defaults_ops = {
++      .init = sctp_defaults_init,
++      .exit = sctp_defaults_exit,
++};
++
++static int __net_init sctp_ctrlsock_init(struct net *net)
++{
++      int status;
++
++      /* Initialize the control inode/socket for handling OOTB packets.  */
++      status = sctp_ctl_sock_init(net);
++      if (status)
++              pr_err("Failed to initialize the SCTP control sock\n");
++
++      return status;
++}
++
++static void __net_init sctp_ctrlsock_exit(struct net *net)
++{
++      /* Free the control endpoint.  */
++      inet_ctl_sock_destroy(net->sctp.ctl_sock);
++}
++
++static struct pernet_operations sctp_ctrlsock_ops = {
++      .init = sctp_ctrlsock_init,
++      .exit = sctp_ctrlsock_exit,
+ };
+ 
+ /* Initialize the universe into something sensible.  */
+@@ -1442,8 +1453,11 @@ static __init int sctp_init(void)
+       sctp_v4_pf_init();
+       sctp_v6_pf_init();
+ 
+-      status = sctp_v4_protosw_init();
++      status = register_pernet_subsys(&sctp_defaults_ops);
++      if (status)
++              goto err_register_defaults;
+ 
++      status = sctp_v4_protosw_init();
+       if (status)
+               goto err_protosw_init;
+ 
+@@ -1451,9 +1465,9 @@ static __init int sctp_init(void)
+       if (status)
+               goto err_v6_protosw_init;
+ 
+-      status = register_pernet_subsys(&sctp_net_ops);
++      status = register_pernet_subsys(&sctp_ctrlsock_ops);
+       if (status)
+-              goto err_register_pernet_subsys;
++              goto err_register_ctrlsock;
+ 
+       status = sctp_v4_add_protocol();
+       if (status)
+@@ -1469,12 +1483,14 @@ out:
+ err_v6_add_protocol:
+       sctp_v4_del_protocol();
+ err_add_protocol:
+-      unregister_pernet_subsys(&sctp_net_ops);
+-err_register_pernet_subsys:
++      unregister_pernet_subsys(&sctp_ctrlsock_ops);
++err_register_ctrlsock:
+       sctp_v6_protosw_exit();
+ err_v6_protosw_init:
+       sctp_v4_protosw_exit();
+ err_protosw_init:
++      unregister_pernet_subsys(&sctp_defaults_ops);
++err_register_defaults:
+       sctp_v4_pf_exit();
+       sctp_v6_pf_exit();
+       sctp_sysctl_unregister();
+@@ -1507,12 +1523,14 @@ static __exit void sctp_exit(void)
+       sctp_v6_del_protocol();
+       sctp_v4_del_protocol();
+ 
+-      unregister_pernet_subsys(&sctp_net_ops);
++      unregister_pernet_subsys(&sctp_ctrlsock_ops);
+ 
+       /* Free protosw registrations */
+       sctp_v6_protosw_exit();
+       sctp_v4_protosw_exit();
+ 
++      unregister_pernet_subsys(&sctp_defaults_ops);
++
+       /* Unregister with socket layer. */
+       sctp_v6_pf_exit();
+       sctp_v4_pf_exit();

Reply via email to