commit: 2c0f6c3b92e2248ee19155496c89a7eead78472a Author: Mike Pagano <mpagano <AT> gentoo <DOT> org> AuthorDate: Sat Oct 3 16:12:47 2015 +0000 Commit: Mike Pagano <mpagano <AT> gentoo <DOT> org> CommitDate: Sat Oct 3 16:12:47 2015 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=2c0f6c3b
Linux patch 4.2.3 0000_README | 4 + 1002_linux-4.2.3.patch | 1532 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1536 insertions(+) diff --git a/0000_README b/0000_README index 9428abc..5a14372 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 0000000..018e36c --- /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();