summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pagano <mpagano@gentoo.org>2015-10-03 12:12:47 -0400
committerMike Pagano <mpagano@gentoo.org>2015-10-03 12:12:47 -0400
commit2c0f6c3b92e2248ee19155496c89a7eead78472a (patch)
tree212c0021f41d275ff73c780efe3dba9f1afc23d2
parentRemove redundant patch (diff)
downloadlinux-patches-2c0f6c3b92e2248ee19155496c89a7eead78472a.tar.gz
linux-patches-2c0f6c3b92e2248ee19155496c89a7eead78472a.tar.bz2
linux-patches-2c0f6c3b92e2248ee19155496c89a7eead78472a.zip
Linux patch 4.2.34.2-6
-rw-r--r--0000_README4
-rw-r--r--1002_linux-4.2.3.patch1532
2 files changed, 1536 insertions, 0 deletions
diff --git a/0000_README b/0000_README
index 9428abcf..5a14372d 100644
--- a/0000_README
+++ b/0000_README
@@ -51,6 +51,10 @@ Patch: 1001_linux-4.2.2.patch
From: http://www.kernel.org
Desc: Linux 4.2.2
+Patch: 1002_linux-4.2.3.patch
+From: http://www.kernel.org
+Desc: Linux 4.2.3
+
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/1002_linux-4.2.3.patch b/1002_linux-4.2.3.patch
new file mode 100644
index 00000000..018e36cc
--- /dev/null
+++ b/1002_linux-4.2.3.patch
@@ -0,0 +1,1532 @@
+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 3578b4426ecf..a6edbb11a69a 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,6 +1,6 @@
+ VERSION = 4
+ PATCHLEVEL = 2
+-SUBLEVEL = 2
++SUBLEVEL = 3
+ EXTRAVERSION =
+ NAME = Hurr durr I'ma sheep
+
+diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
+index 965d1afb0eaa..5cb13ca3a3ac 100644
+--- a/drivers/block/zram/zcomp.c
++++ b/drivers/block/zram/zcomp.c
+@@ -330,12 +330,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)
+@@ -347,12 +349,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 079897b3a955..9d56515f4c4d 100644
+--- a/drivers/net/dsa/bcm_sf2.c
++++ b/drivers/net/dsa/bcm_sf2.c
+@@ -418,7 +418,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 {
+@@ -432,6 +432,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;
+ }
+
+@@ -507,7 +509,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:
+@@ -531,10 +533,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__);
+@@ -901,15 +905,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;
+
+@@ -944,18 +944,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/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
+index 561342466076..26ec2fbfaa89 100644
+--- a/drivers/net/dsa/mv88e6xxx.c
++++ b/drivers/net/dsa/mv88e6xxx.c
+@@ -1387,6 +1387,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
+ reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_PCS_CTRL);
+ if (dsa_is_cpu_port(ds, port) ||
+ ds->dsa_port_mask & (1 << port)) {
++ reg &= ~PORT_PCS_CTRL_UNFORCED;
+ reg |= PORT_PCS_CTRL_FORCE_LINK |
+ PORT_PCS_CTRL_LINK_UP |
+ PORT_PCS_CTRL_DUPLEX_FULL |
+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 b349e6f36ea7..de63266de16b 100644
+--- a/drivers/net/ethernet/freescale/fec_main.c
++++ b/drivers/net/ethernet/freescale/fec_main.c
+@@ -1402,6 +1402,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 62e48bc0cb23..09ec32e33076 100644
+--- a/drivers/net/ethernet/marvell/mvneta.c
++++ b/drivers/net/ethernet/marvell/mvneta.c
+@@ -1479,6 +1479,7 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
+ struct mvneta_rx_desc *rx_desc = mvneta_rxq_next_desc_get(rxq);
+ struct sk_buff *skb;
+ unsigned char *data;
++ dma_addr_t phys_addr;
+ u32 rx_status;
+ int rx_bytes, err;
+
+@@ -1486,6 +1487,7 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
+ rx_status = rx_desc->status;
+ rx_bytes = rx_desc->data_size - (ETH_FCS_LEN + MVNETA_MH_SIZE);
+ data = (unsigned char *)rx_desc->buf_cookie;
++ phys_addr = rx_desc->buf_phys_addr;
+
+ if (!mvneta_rxq_desc_is_first_last(rx_status) ||
+ (rx_status & MVNETA_RXD_ERR_SUMMARY)) {
+@@ -1534,7 +1536,7 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
+ if (!skb)
+ goto err_drop_frame;
+
+- dma_unmap_single(dev->dev.parent, rx_desc->buf_phys_addr,
++ dma_unmap_single(dev->dev.parent, phys_addr,
+ MVNETA_RX_BUF_SIZE(pp->pkt_size), DMA_FROM_DEVICE);
+
+ rcvd_pkts++;
+@@ -3027,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
+@@ -3062,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.
+@@ -3086,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 9c145dddd717..4f95fa7b594d 100644
+--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
++++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+@@ -1250,8 +1250,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/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
+index 29c2a017a450..a408977a531a 100644
+--- a/drivers/net/ethernet/mellanox/mlx4/main.c
++++ b/drivers/net/ethernet/mellanox/mlx4/main.c
+@@ -2654,9 +2654,14 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
+
+ if (msi_x) {
+ int nreq = dev->caps.num_ports * num_online_cpus() + 1;
++ bool shared_ports = false;
+
+ nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs,
+ nreq);
++ if (nreq > MAX_MSIX) {
++ nreq = MAX_MSIX;
++ shared_ports = true;
++ }
+
+ entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL);
+ if (!entries)
+@@ -2679,6 +2684,9 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
+ bitmap_zero(priv->eq_table.eq[MLX4_EQ_ASYNC].actv_ports.ports,
+ dev->caps.num_ports);
+
++ if (MLX4_IS_LEGACY_EQ_MODE(dev->caps))
++ shared_ports = true;
++
+ for (i = 0; i < dev->caps.num_comp_vectors + 1; i++) {
+ if (i == MLX4_EQ_ASYNC)
+ continue;
+@@ -2686,7 +2694,7 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
+ priv->eq_table.eq[i].irq =
+ entries[i + 1 - !!(i > MLX4_EQ_ASYNC)].vector;
+
+- if (MLX4_IS_LEGACY_EQ_MODE(dev->caps)) {
++ if (shared_ports) {
+ bitmap_fill(priv->eq_table.eq[i].actv_ports.ports,
+ dev->caps.num_ports);
+ /* We don't set affinity hint when there
+diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
+index edd77342773a..248478c6f6e4 100644
+--- a/drivers/net/macvtap.c
++++ b/drivers/net/macvtap.c
+@@ -1111,10 +1111,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 d7a65247f952..99d9bc19c94a 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/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
+index 46a14cbb0215..02a4615b65f8 100644
+--- a/drivers/net/phy/mdio_bus.c
++++ b/drivers/net/phy/mdio_bus.c
+@@ -303,12 +303,12 @@ void mdiobus_unregister(struct mii_bus *bus)
+ BUG_ON(bus->state != MDIOBUS_REGISTERED);
+ bus->state = MDIOBUS_UNREGISTERED;
+
+- device_del(&bus->dev);
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ if (bus->phy_map[i])
+ device_unregister(&bus->phy_map[i]->dev);
+ bus->phy_map[i] = NULL;
+ }
++ device_del(&bus->dev);
+ }
+ EXPORT_SYMBOL(mdiobus_unregister);
+
+diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
+index fa8f5046afe9..487be20b6b12 100644
+--- a/drivers/net/ppp/ppp_generic.c
++++ b/drivers/net/ppp/ppp_generic.c
+@@ -2742,6 +2742,7 @@ static struct ppp *ppp_create_interface(struct net *net, int unit,
+ */
+ dev_net_set(dev, net);
+
++ rtnl_lock();
+ mutex_lock(&pn->all_ppp_mutex);
+
+ if (unit < 0) {
+@@ -2772,7 +2773,7 @@ static struct ppp *ppp_create_interface(struct net *net, int unit,
+ ppp->file.index = unit;
+ sprintf(dev->name, "ppp%d", unit);
+
+- ret = register_netdev(dev);
++ ret = register_netdevice(dev);
+ if (ret != 0) {
+ unit_put(&pn->units_idr, unit);
+ netdev_err(ppp->dev, "PPP: couldn't register device %s (%d)\n",
+@@ -2784,6 +2785,7 @@ static struct ppp *ppp_create_interface(struct net *net, int unit,
+
+ atomic_inc(&ppp_unit_count);
+ mutex_unlock(&pn->all_ppp_mutex);
++ rtnl_unlock();
+
+ *retp = 0;
+ return ppp;
+diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
+index fdc60db60829..7c8c23cc6896 100644
+--- a/drivers/of/of_mdio.c
++++ b/drivers/of/of_mdio.c
+@@ -266,7 +266,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");
+@@ -275,6 +276,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)))
+@@ -289,8 +294,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 1285eaf5dc22..03cdb9e18d57 100644
+--- a/net/bridge/br_multicast.c
++++ b/net/bridge/br_multicast.c
+@@ -991,7 +991,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);
+@@ -1052,7 +1052,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/rtnetlink.c b/net/core/rtnetlink.c
+index dc004b1e1f85..0861018be708 100644
+--- a/net/core/rtnetlink.c
++++ b/net/core/rtnetlink.c
+@@ -3021,6 +3021,7 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
+ u32 portid = NETLINK_CB(cb->skb).portid;
+ u32 seq = cb->nlh->nlmsg_seq;
+ u32 filter_mask = 0;
++ int err;
+
+ if (nlmsg_len(cb->nlh) > sizeof(struct ifinfomsg)) {
+ struct nlattr *extfilt;
+@@ -3041,20 +3042,25 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
+ struct net_device *br_dev = netdev_master_upper_dev_get(dev);
+
+ if (br_dev && br_dev->netdev_ops->ndo_bridge_getlink) {
+- if (idx >= cb->args[0] &&
+- br_dev->netdev_ops->ndo_bridge_getlink(
+- skb, portid, seq, dev, filter_mask,
+- NLM_F_MULTI) < 0)
+- break;
++ if (idx >= cb->args[0]) {
++ err = br_dev->netdev_ops->ndo_bridge_getlink(
++ skb, portid, seq, dev,
++ filter_mask, NLM_F_MULTI);
++ if (err < 0 && err != -EOPNOTSUPP)
++ break;
++ }
+ idx++;
+ }
+
+ if (ops->ndo_bridge_getlink) {
+- if (idx >= cb->args[0] &&
+- ops->ndo_bridge_getlink(skb, portid, seq, dev,
+- filter_mask,
+- NLM_F_MULTI) < 0)
+- break;
++ if (idx >= cb->args[0]) {
++ err = ops->ndo_bridge_getlink(skb, portid,
++ seq, dev,
++ filter_mask,
++ NLM_F_MULTI);
++ if (err < 0 && err != -EOPNOTSUPP)
++ break;
++ }
+ idx++;
+ }
+ }
+diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
+index d79866c5f8bc..817622f3dbb7 100644
+--- a/net/core/sock_diag.c
++++ b/net/core/sock_diag.c
+@@ -90,6 +90,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 b1c218df2c85..b7dedd9d36d8 100644
+--- a/net/ipv4/tcp_output.c
++++ b/net/ipv4/tcp_output.c
+@@ -2898,6 +2898,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/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 d15586490cec..00b64d402a57 100644
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -1727,7 +1727,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;
+@@ -1735,7 +1735,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)
+@@ -1941,6 +1940,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;
+@@ -1948,14 +1973,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;
+ }
+
+@@ -2727,19 +2750,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)
+@@ -2755,22 +2837,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:
+@@ -2780,6 +2872,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);
+ }
+
+@@ -2796,7 +2945,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);
+ }
+@@ -2811,7 +2960,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 a774985489e2..0857f7243797 100644
+--- a/net/netlink/af_netlink.c
++++ b/net/netlink/af_netlink.c
+@@ -124,6 +124,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))
+@@ -205,7 +223,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);
+@@ -278,11 +300,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;
+@@ -834,7 +851,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
+@@ -1082,8 +1098,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;
+@@ -1103,10 +1119,14 @@ static int netlink_insert(struct sock *sk, u32 portid)
+ err = -EOVERFLOW;
+ if (err == -EEXIST)
+ err = -EADDRINUSE;
+- nlk_sk(sk)->portid = 0;
+ sock_put(sk);
++ goto err;
+ }
+
++ /* We need to ensure that the socket is hashed and visible. */
++ smp_wmb();
++ nlk_sk(sk)->bound = portid;
++
+ err:
+ release_sock(sk);
+ return err;
+@@ -1491,6 +1511,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;
+@@ -1507,9 +1528,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;
+@@ -1525,7 +1551,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);
+@@ -1573,7 +1602,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) {
+@@ -2391,10 +2423,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 ff8c4a4c1609..ff332d1b94bc 100644
+--- a/net/openvswitch/datapath.c
++++ b/net/openvswitch/datapath.c
+@@ -920,7 +920,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],
+@@ -1047,7 +1047,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 65523948fb95..b5c3bba87fc8 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/packet/af_packet.c b/net/packet/af_packet.c
+index ed458b315ef4..7851b1222a36 100644
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -229,6 +229,8 @@ struct packet_skb_cb {
+ } sa;
+ };
+
++#define vio_le() virtio_legacy_is_little_endian()
++
+ #define PACKET_SKB_CB(__skb) ((struct packet_skb_cb *)((__skb)->cb))
+
+ #define GET_PBDQC_FROM_RB(x) ((struct tpacket_kbdq_core *)(&(x)->prb_bdqc))
+@@ -2561,15 +2563,15 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
+ goto out_unlock;
+
+ if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
+- (__virtio16_to_cpu(false, vnet_hdr.csum_start) +
+- __virtio16_to_cpu(false, vnet_hdr.csum_offset) + 2 >
+- __virtio16_to_cpu(false, vnet_hdr.hdr_len)))
+- vnet_hdr.hdr_len = __cpu_to_virtio16(false,
+- __virtio16_to_cpu(false, vnet_hdr.csum_start) +
+- __virtio16_to_cpu(false, vnet_hdr.csum_offset) + 2);
++ (__virtio16_to_cpu(vio_le(), vnet_hdr.csum_start) +
++ __virtio16_to_cpu(vio_le(), vnet_hdr.csum_offset) + 2 >
++ __virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len)))
++ vnet_hdr.hdr_len = __cpu_to_virtio16(vio_le(),
++ __virtio16_to_cpu(vio_le(), vnet_hdr.csum_start) +
++ __virtio16_to_cpu(vio_le(), vnet_hdr.csum_offset) + 2);
+
+ err = -EINVAL;
+- if (__virtio16_to_cpu(false, vnet_hdr.hdr_len) > len)
++ if (__virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len) > len)
+ goto out_unlock;
+
+ if (vnet_hdr.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
+@@ -2612,7 +2614,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
+ hlen = LL_RESERVED_SPACE(dev);
+ tlen = dev->needed_tailroom;
+ skb = packet_alloc_skb(sk, hlen + tlen, hlen, len,
+- __virtio16_to_cpu(false, vnet_hdr.hdr_len),
++ __virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len),
+ msg->msg_flags & MSG_DONTWAIT, &err);
+ if (skb == NULL)
+ goto out_unlock;
+@@ -2659,8 +2661,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
+
+ if (po->has_vnet_hdr) {
+ if (vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
+- u16 s = __virtio16_to_cpu(false, vnet_hdr.csum_start);
+- u16 o = __virtio16_to_cpu(false, vnet_hdr.csum_offset);
++ u16 s = __virtio16_to_cpu(vio_le(), vnet_hdr.csum_start);
++ u16 o = __virtio16_to_cpu(vio_le(), vnet_hdr.csum_offset);
+ if (!skb_partial_csum_set(skb, s, o)) {
+ err = -EINVAL;
+ goto out_free;
+@@ -2668,7 +2670,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
+ }
+
+ skb_shinfo(skb)->gso_size =
+- __virtio16_to_cpu(false, vnet_hdr.gso_size);
++ __virtio16_to_cpu(vio_le(), vnet_hdr.gso_size);
+ skb_shinfo(skb)->gso_type = gso_type;
+
+ /* Header must be checked, and gso_segs computed. */
+@@ -3042,9 +3044,9 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
+
+ /* This is a hint as to how much should be linear. */
+ vnet_hdr.hdr_len =
+- __cpu_to_virtio16(false, skb_headlen(skb));
++ __cpu_to_virtio16(vio_le(), skb_headlen(skb));
+ vnet_hdr.gso_size =
+- __cpu_to_virtio16(false, sinfo->gso_size);
++ __cpu_to_virtio16(vio_le(), sinfo->gso_size);
+ if (sinfo->gso_type & SKB_GSO_TCPV4)
+ vnet_hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+ else if (sinfo->gso_type & SKB_GSO_TCPV6)
+@@ -3062,9 +3064,9 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ vnet_hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
+- vnet_hdr.csum_start = __cpu_to_virtio16(false,
++ vnet_hdr.csum_start = __cpu_to_virtio16(vio_le(),
+ skb_checksum_start_offset(skb));
+- vnet_hdr.csum_offset = __cpu_to_virtio16(false,
++ vnet_hdr.csum_offset = __cpu_to_virtio16(vio_le(),
+ skb->csum_offset);
+ } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+ vnet_hdr.flags = VIRTIO_NET_HDR_F_DATA_VALID;
+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/sctp/protocol.c b/net/sctp/protocol.c
+index 59e80356672b..3ac604f96da0 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();