diff options
Diffstat (limited to '4.9.9/1007_linux-4.9.8.patch')
-rw-r--r-- | 4.9.9/1007_linux-4.9.8.patch | 2048 |
1 files changed, 2048 insertions, 0 deletions
diff --git a/4.9.9/1007_linux-4.9.8.patch b/4.9.9/1007_linux-4.9.8.patch new file mode 100644 index 0000000..a93aab4 --- /dev/null +++ b/4.9.9/1007_linux-4.9.8.patch @@ -0,0 +1,2048 @@ +diff --git a/Makefile b/Makefile +index da704d9..1130803 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,6 +1,6 @@ + VERSION = 4 + PATCHLEVEL = 9 +-SUBLEVEL = 7 ++SUBLEVEL = 8 + EXTRAVERSION = + NAME = Roaring Lionus + +diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c +index 25d1eb4..be7ec5a 100644 +--- a/drivers/net/ethernet/broadcom/bcmsysport.c ++++ b/drivers/net/ethernet/broadcom/bcmsysport.c +@@ -710,11 +710,8 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, + unsigned int c_index, last_c_index, last_tx_cn, num_tx_cbs; + unsigned int pkts_compl = 0, bytes_compl = 0; + struct bcm_sysport_cb *cb; +- struct netdev_queue *txq; + u32 hw_ind; + +- txq = netdev_get_tx_queue(ndev, ring->index); +- + /* Compute how many descriptors have been processed since last call */ + hw_ind = tdma_readl(priv, TDMA_DESC_RING_PROD_CONS_INDEX(ring->index)); + c_index = (hw_ind >> RING_CONS_INDEX_SHIFT) & RING_CONS_INDEX_MASK; +@@ -745,9 +742,6 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, + + ring->c_index = c_index; + +- if (netif_tx_queue_stopped(txq) && pkts_compl) +- netif_tx_wake_queue(txq); +- + netif_dbg(priv, tx_done, ndev, + "ring=%d c_index=%d pkts_compl=%d, bytes_compl=%d\n", + ring->index, ring->c_index, pkts_compl, bytes_compl); +@@ -759,16 +753,33 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, + static unsigned int bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, + struct bcm_sysport_tx_ring *ring) + { ++ struct netdev_queue *txq; + unsigned int released; + unsigned long flags; + ++ txq = netdev_get_tx_queue(priv->netdev, ring->index); ++ + spin_lock_irqsave(&ring->lock, flags); + released = __bcm_sysport_tx_reclaim(priv, ring); ++ if (released) ++ netif_tx_wake_queue(txq); ++ + spin_unlock_irqrestore(&ring->lock, flags); + + return released; + } + ++/* Locked version of the per-ring TX reclaim, but does not wake the queue */ ++static void bcm_sysport_tx_clean(struct bcm_sysport_priv *priv, ++ struct bcm_sysport_tx_ring *ring) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&ring->lock, flags); ++ __bcm_sysport_tx_reclaim(priv, ring); ++ spin_unlock_irqrestore(&ring->lock, flags); ++} ++ + static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget) + { + struct bcm_sysport_tx_ring *ring = +@@ -1253,7 +1264,7 @@ static void bcm_sysport_fini_tx_ring(struct bcm_sysport_priv *priv, + napi_disable(&ring->napi); + netif_napi_del(&ring->napi); + +- bcm_sysport_tx_reclaim(priv, ring); ++ bcm_sysport_tx_clean(priv, ring); + + kfree(ring->cbs); + ring->cbs = NULL; +diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +index fb8bb02..d223e7c 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c ++++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +@@ -1740,8 +1740,11 @@ int mlx4_en_start_port(struct net_device *dev) + /* Process all completions if exist to prevent + * the queues freezing if they are full + */ +- for (i = 0; i < priv->rx_ring_num; i++) ++ for (i = 0; i < priv->rx_ring_num; i++) { ++ local_bh_disable(); + napi_schedule(&priv->rx_cq[i]->napi); ++ local_bh_enable(); ++ } + + netif_tx_start_all_queues(dev); + netif_device_attach(dev); +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +index 33495d8..e7b2158 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +@@ -193,6 +193,9 @@ static inline bool mlx5e_rx_cache_put(struct mlx5e_rq *rq, + return false; + } + ++ if (unlikely(page_is_pfmemalloc(dma_info->page))) ++ return false; ++ + cache->page_cache[cache->tail] = *dma_info; + cache->tail = tail_next; + return true; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.h b/drivers/net/ethernet/mellanox/mlxsw/pci.h +index d942a3e..846fd4d 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/pci.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/pci.h +@@ -211,21 +211,21 @@ MLXSW_ITEM32(pci, eqe, owner, 0x0C, 0, 1); + /* pci_eqe_cmd_token + * Command completion event - token + */ +-MLXSW_ITEM32(pci, eqe, cmd_token, 0x08, 16, 16); ++MLXSW_ITEM32(pci, eqe, cmd_token, 0x00, 16, 16); + + /* pci_eqe_cmd_status + * Command completion event - status + */ +-MLXSW_ITEM32(pci, eqe, cmd_status, 0x08, 0, 8); ++MLXSW_ITEM32(pci, eqe, cmd_status, 0x00, 0, 8); + + /* pci_eqe_cmd_out_param_h + * Command completion event - output parameter - higher part + */ +-MLXSW_ITEM32(pci, eqe, cmd_out_param_h, 0x0C, 0, 32); ++MLXSW_ITEM32(pci, eqe, cmd_out_param_h, 0x04, 0, 32); + + /* pci_eqe_cmd_out_param_l + * Command completion event - output parameter - lower part + */ +-MLXSW_ITEM32(pci, eqe, cmd_out_param_l, 0x10, 0, 32); ++MLXSW_ITEM32(pci, eqe, cmd_out_param_l, 0x08, 0, 32); + + #endif +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +index dda5761..f902c4d 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +@@ -684,6 +684,7 @@ static netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb, + dev_kfree_skb_any(skb_orig); + return NETDEV_TX_OK; + } ++ dev_consume_skb_any(skb_orig); + } + + if (eth_skb_pad(skb)) { +diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +index 92bda87..d548f0a 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +@@ -314,6 +314,7 @@ static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb, + dev_kfree_skb_any(skb_orig); + return NETDEV_TX_OK; + } ++ dev_consume_skb_any(skb_orig); + } + mlxsw_sx_txhdr_construct(skb, &tx_info); + /* TX header is consumed by HW on the way so we shouldn't count its +diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c +index d6a2178..862f18e 100644 +--- a/drivers/net/ethernet/renesas/ravb_main.c ++++ b/drivers/net/ethernet/renesas/ravb_main.c +@@ -1508,6 +1508,19 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) + buffer = PTR_ALIGN(priv->tx_align[q], DPTR_ALIGN) + + entry / NUM_TX_DESC * DPTR_ALIGN; + len = PTR_ALIGN(skb->data, DPTR_ALIGN) - skb->data; ++ /* Zero length DMA descriptors are problematic as they seem to ++ * terminate DMA transfers. Avoid them by simply using a length of ++ * DPTR_ALIGN (4) when skb data is aligned to DPTR_ALIGN. ++ * ++ * As skb is guaranteed to have at least ETH_ZLEN (60) bytes of ++ * data by the call to skb_put_padto() above this is safe with ++ * respect to both the length of the first DMA descriptor (len) ++ * overflowing the available data and the length of the second DMA ++ * descriptor (skb->len - len) being negative. ++ */ ++ if (len == 0) ++ len = DPTR_ALIGN; ++ + memcpy(buffer, skb->data, len); + dma_addr = dma_map_single(ndev->dev.parent, buffer, len, DMA_TO_DEVICE); + if (dma_mapping_error(ndev->dev.parent, dma_addr)) +diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c +index c9140c3..ff038e5 100644 +--- a/drivers/net/hyperv/netvsc_drv.c ++++ b/drivers/net/hyperv/netvsc_drv.c +@@ -659,6 +659,7 @@ int netvsc_recv_callback(struct hv_device *device_obj, + * policy filters on the host). Deliver these via the VF + * interface in the guest. + */ ++ rcu_read_lock(); + vf_netdev = rcu_dereference(net_device_ctx->vf_netdev); + if (vf_netdev && (vf_netdev->flags & IFF_UP)) + net = vf_netdev; +@@ -667,6 +668,7 @@ int netvsc_recv_callback(struct hv_device *device_obj, + skb = netvsc_alloc_recv_skb(net, packet, csum_info, *data, vlan_tci); + if (unlikely(!skb)) { + ++net->stats.rx_dropped; ++ rcu_read_unlock(); + return NVSP_STAT_FAIL; + } + +@@ -696,6 +698,7 @@ int netvsc_recv_callback(struct hv_device *device_obj, + * TODO - use NAPI? + */ + netif_rx(skb); ++ rcu_read_unlock(); + + return 0; + } +diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c +index 7869b06..6f38daf 100644 +--- a/drivers/net/macvtap.c ++++ b/drivers/net/macvtap.c +@@ -827,7 +827,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, + return -EINVAL; + + ret = virtio_net_hdr_from_skb(skb, &vnet_hdr, +- macvtap_is_little_endian(q)); ++ macvtap_is_little_endian(q), true); + if (ret) + BUG(); + +diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c +index e741bf6..b0492ef 100644 +--- a/drivers/net/phy/bcm63xx.c ++++ b/drivers/net/phy/bcm63xx.c +@@ -21,6 +21,23 @@ MODULE_DESCRIPTION("Broadcom 63xx internal PHY driver"); + MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>"); + MODULE_LICENSE("GPL"); + ++static int bcm63xx_config_intr(struct phy_device *phydev) ++{ ++ int reg, err; ++ ++ reg = phy_read(phydev, MII_BCM63XX_IR); ++ if (reg < 0) ++ return reg; ++ ++ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) ++ reg &= ~MII_BCM63XX_IR_GMASK; ++ else ++ reg |= MII_BCM63XX_IR_GMASK; ++ ++ err = phy_write(phydev, MII_BCM63XX_IR, reg); ++ return err; ++} ++ + static int bcm63xx_config_init(struct phy_device *phydev) + { + int reg, err; +@@ -55,7 +72,7 @@ static struct phy_driver bcm63xx_driver[] = { + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm_phy_ack_intr, +- .config_intr = bcm_phy_config_intr, ++ .config_intr = bcm63xx_config_intr, + }, { + /* same phy as above, with just a different OUI */ + .phy_id = 0x002bdc00, +@@ -67,7 +84,7 @@ static struct phy_driver bcm63xx_driver[] = { + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm_phy_ack_intr, +- .config_intr = bcm_phy_config_intr, ++ .config_intr = bcm63xx_config_intr, + } }; + + module_phy_driver(bcm63xx_driver); +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index db6acec..18402d7 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -1374,7 +1374,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, + return -EINVAL; + + ret = virtio_net_hdr_from_skb(skb, &gso, +- tun_is_little_endian(tun)); ++ tun_is_little_endian(tun), true); + if (ret) { + struct skb_shared_info *sinfo = skb_shinfo(skb); + pr_err("unexpected GSO type: " +diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c +index dd623f6..b82be81 100644 +--- a/drivers/net/usb/cdc_ether.c ++++ b/drivers/net/usb/cdc_ether.c +@@ -531,6 +531,7 @@ static const struct driver_info wwan_info = { + #define SAMSUNG_VENDOR_ID 0x04e8 + #define LENOVO_VENDOR_ID 0x17ef + #define NVIDIA_VENDOR_ID 0x0955 ++#define HP_VENDOR_ID 0x03f0 + + static const struct usb_device_id products[] = { + /* BLACKLIST !! +@@ -677,6 +678,13 @@ static const struct usb_device_id products[] = { + .driver_info = 0, + }, + ++/* HP lt2523 (Novatel E371) - handled by qmi_wwan */ ++{ ++ USB_DEVICE_AND_INTERFACE_INFO(HP_VENDOR_ID, 0x421d, USB_CLASS_COMM, ++ USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), ++ .driver_info = 0, ++}, ++ + /* AnyDATA ADU960S - handled by qmi_wwan */ + { + USB_DEVICE_AND_INTERFACE_INFO(0x16d5, 0x650a, USB_CLASS_COMM, +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index 6fe1cdb..24d5272 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -654,6 +654,13 @@ static const struct usb_device_id products[] = { + USB_CDC_PROTO_NONE), + .driver_info = (unsigned long)&qmi_wwan_info, + }, ++ { /* HP lt2523 (Novatel E371) */ ++ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x421d, ++ USB_CLASS_COMM, ++ USB_CDC_SUBCLASS_ETHERNET, ++ USB_CDC_PROTO_NONE), ++ .driver_info = (unsigned long)&qmi_wwan_info, ++ }, + { /* HP lt4112 LTE/HSPA+ Gobi 4G Module (Huawei me906e) */ + USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7), + .driver_info = (unsigned long)&qmi_wwan_info, +diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c +index 4b5cb16..90b426c 100644 +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -32,7 +32,7 @@ + #define NETNEXT_VERSION "08" + + /* Information for net */ +-#define NET_VERSION "6" ++#define NET_VERSION "7" + + #define DRIVER_VERSION "v1." NETNEXT_VERSION "." NET_VERSION + #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" +@@ -1730,7 +1730,7 @@ static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc) + u8 checksum = CHECKSUM_NONE; + u32 opts2, opts3; + +- if (tp->version == RTL_VER_01 || tp->version == RTL_VER_02) ++ if (!(tp->netdev->features & NETIF_F_RXCSUM)) + goto return_result; + + opts2 = le32_to_cpu(rx_desc->opts2); +@@ -3572,6 +3572,8 @@ static bool delay_autosuspend(struct r8152 *tp) + */ + if (!sw_linking && tp->rtl_ops.in_nway(tp)) + return true; ++ else if (!skb_queue_empty(&tp->tx_queue)) ++ return true; + else + return false; + } +@@ -4358,6 +4360,11 @@ static int rtl8152_probe(struct usb_interface *intf, + NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | + NETIF_F_IPV6_CSUM | NETIF_F_TSO6; + ++ if (tp->version == RTL_VER_01) { ++ netdev->features &= ~NETIF_F_RXCSUM; ++ netdev->hw_features &= ~NETIF_F_RXCSUM; ++ } ++ + netdev->ethtool_ops = &ops; + netif_set_gso_max_size(netdev, RTL_LIMITED_TSO_SIZE); + +diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c +index cbf1c61..51fc0c3 100644 +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -840,7 +840,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) + hdr = skb_vnet_hdr(skb); + + if (virtio_net_hdr_from_skb(skb, &hdr->hdr, +- virtio_is_little_endian(vi->vdev))) ++ virtio_is_little_endian(vi->vdev), false)) + BUG(); + + if (vi->mergeable_rx_bufs) +diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c +index 2ba01ca..0fafaa9 100644 +--- a/drivers/net/vxlan.c ++++ b/drivers/net/vxlan.c +@@ -2887,7 +2887,7 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, + memcpy(&vxlan->cfg, conf, sizeof(*conf)); + if (!vxlan->cfg.dst_port) { + if (conf->flags & VXLAN_F_GPE) +- vxlan->cfg.dst_port = 4790; /* IANA assigned VXLAN-GPE port */ ++ vxlan->cfg.dst_port = htons(4790); /* IANA VXLAN-GPE port */ + else + vxlan->cfg.dst_port = default_port; + } +diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c +index 5050056..9f06a21 100644 +--- a/fs/xfs/libxfs/xfs_alloc.c ++++ b/fs/xfs/libxfs/xfs_alloc.c +@@ -95,10 +95,7 @@ unsigned int + xfs_alloc_set_aside( + struct xfs_mount *mp) + { +- unsigned int blocks; +- +- blocks = 4 + (mp->m_sb.sb_agcount * XFS_ALLOC_AGFL_RESERVE); +- return blocks; ++ return mp->m_sb.sb_agcount * (XFS_ALLOC_AGFL_RESERVE + 4); + } + + /* +@@ -365,36 +362,12 @@ xfs_alloc_fix_len( + return; + ASSERT(rlen >= args->minlen && rlen <= args->maxlen); + ASSERT(rlen % args->prod == args->mod); ++ ASSERT(args->pag->pagf_freeblks + args->pag->pagf_flcount >= ++ rlen + args->minleft); + args->len = rlen; + } + + /* +- * Fix up length if there is too little space left in the a.g. +- * Return 1 if ok, 0 if too little, should give up. +- */ +-STATIC int +-xfs_alloc_fix_minleft( +- xfs_alloc_arg_t *args) /* allocation argument structure */ +-{ +- xfs_agf_t *agf; /* a.g. freelist header */ +- int diff; /* free space difference */ +- +- if (args->minleft == 0) +- return 1; +- agf = XFS_BUF_TO_AGF(args->agbp); +- diff = be32_to_cpu(agf->agf_freeblks) +- - args->len - args->minleft; +- if (diff >= 0) +- return 1; +- args->len += diff; /* shrink the allocated space */ +- /* casts to (int) catch length underflows */ +- if ((int)args->len >= (int)args->minlen) +- return 1; +- args->agbno = NULLAGBLOCK; +- return 0; +-} +- +-/* + * Update the two btrees, logically removing from freespace the extent + * starting at rbno, rlen blocks. The extent is contained within the + * actual (current) free extent fbno for flen blocks. +@@ -689,8 +662,6 @@ xfs_alloc_ag_vextent( + xfs_alloc_arg_t *args) /* argument structure for allocation */ + { + int error=0; +- xfs_extlen_t reservation; +- xfs_extlen_t oldmax; + + ASSERT(args->minlen > 0); + ASSERT(args->maxlen > 0); +@@ -699,20 +670,6 @@ xfs_alloc_ag_vextent( + ASSERT(args->alignment > 0); + + /* +- * Clamp maxlen to the amount of free space minus any reservations +- * that have been made. +- */ +- oldmax = args->maxlen; +- reservation = xfs_ag_resv_needed(args->pag, args->resv); +- if (args->maxlen > args->pag->pagf_freeblks - reservation) +- args->maxlen = args->pag->pagf_freeblks - reservation; +- if (args->maxlen == 0) { +- args->agbno = NULLAGBLOCK; +- args->maxlen = oldmax; +- return 0; +- } +- +- /* + * Branch to correct routine based on the type. + */ + args->wasfromfl = 0; +@@ -731,8 +688,6 @@ xfs_alloc_ag_vextent( + /* NOTREACHED */ + } + +- args->maxlen = oldmax; +- + if (error || args->agbno == NULLAGBLOCK) + return error; + +@@ -841,9 +796,6 @@ xfs_alloc_ag_vextent_exact( + args->len = XFS_AGBLOCK_MIN(tend, args->agbno + args->maxlen) + - args->agbno; + xfs_alloc_fix_len(args); +- if (!xfs_alloc_fix_minleft(args)) +- goto not_found; +- + ASSERT(args->agbno + args->len <= tend); + + /* +@@ -1149,12 +1101,7 @@ xfs_alloc_ag_vextent_near( + XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); + ASSERT(ltbno + ltlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length)); + args->len = blen; +- if (!xfs_alloc_fix_minleft(args)) { +- xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); +- trace_xfs_alloc_near_nominleft(args); +- return 0; +- } +- blen = args->len; ++ + /* + * We are allocating starting at bnew for blen blocks. + */ +@@ -1346,12 +1293,6 @@ xfs_alloc_ag_vextent_near( + */ + args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); + xfs_alloc_fix_len(args); +- if (!xfs_alloc_fix_minleft(args)) { +- trace_xfs_alloc_near_nominleft(args); +- xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); +- xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); +- return 0; +- } + rlen = args->len; + (void)xfs_alloc_compute_diff(args->agbno, rlen, args->alignment, + args->datatype, ltbnoa, ltlena, <new); +@@ -1553,8 +1494,6 @@ xfs_alloc_ag_vextent_size( + } + xfs_alloc_fix_len(args); + +- if (!xfs_alloc_fix_minleft(args)) +- goto out_nominleft; + rlen = args->len; + XFS_WANT_CORRUPTED_GOTO(args->mp, rlen <= flen, error0); + /* +@@ -2056,7 +1995,7 @@ xfs_alloc_space_available( + int flags) + { + struct xfs_perag *pag = args->pag; +- xfs_extlen_t longest; ++ xfs_extlen_t alloc_len, longest; + xfs_extlen_t reservation; /* blocks that are still reserved */ + int available; + +@@ -2066,17 +2005,28 @@ xfs_alloc_space_available( + reservation = xfs_ag_resv_needed(pag, args->resv); + + /* do we have enough contiguous free space for the allocation? */ ++ alloc_len = args->minlen + (args->alignment - 1) + args->minalignslop; + longest = xfs_alloc_longest_free_extent(args->mp, pag, min_free, + reservation); +- if ((args->minlen + args->alignment + args->minalignslop - 1) > longest) ++ if (longest < alloc_len) + return false; + + /* do we have enough free space remaining for the allocation? */ + available = (int)(pag->pagf_freeblks + pag->pagf_flcount - +- reservation - min_free - args->total); +- if (available < (int)args->minleft || available <= 0) ++ reservation - min_free - args->minleft); ++ if (available < (int)max(args->total, alloc_len)) + return false; + ++ /* ++ * Clamp maxlen to the amount of free space available for the actual ++ * extent allocation. ++ */ ++ if (available < (int)args->maxlen && !(flags & XFS_ALLOC_FLAG_CHECK)) { ++ args->maxlen = available; ++ ASSERT(args->maxlen > 0); ++ ASSERT(args->maxlen >= args->minlen); ++ } ++ + return true; + } + +@@ -2122,7 +2072,8 @@ xfs_alloc_fix_freelist( + } + + need = xfs_alloc_min_freelist(mp, pag); +- if (!xfs_alloc_space_available(args, need, flags)) ++ if (!xfs_alloc_space_available(args, need, flags | ++ XFS_ALLOC_FLAG_CHECK)) + goto out_agbp_relse; + + /* +@@ -2638,12 +2589,10 @@ xfs_alloc_vextent( + xfs_agblock_t agsize; /* allocation group size */ + int error; + int flags; /* XFS_ALLOC_FLAG_... locking flags */ +- xfs_extlen_t minleft;/* minimum left value, temp copy */ + xfs_mount_t *mp; /* mount structure pointer */ + xfs_agnumber_t sagno; /* starting allocation group number */ + xfs_alloctype_t type; /* input allocation type */ + int bump_rotor = 0; +- int no_min = 0; + xfs_agnumber_t rotorstep = xfs_rotorstep; /* inode32 agf stepper */ + + mp = args->mp; +@@ -2672,7 +2621,6 @@ xfs_alloc_vextent( + trace_xfs_alloc_vextent_badargs(args); + return 0; + } +- minleft = args->minleft; + + switch (type) { + case XFS_ALLOCTYPE_THIS_AG: +@@ -2683,9 +2631,7 @@ xfs_alloc_vextent( + */ + args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); + args->pag = xfs_perag_get(mp, args->agno); +- args->minleft = 0; + error = xfs_alloc_fix_freelist(args, 0); +- args->minleft = minleft; + if (error) { + trace_xfs_alloc_vextent_nofix(args); + goto error0; +@@ -2750,9 +2696,7 @@ xfs_alloc_vextent( + */ + for (;;) { + args->pag = xfs_perag_get(mp, args->agno); +- if (no_min) args->minleft = 0; + error = xfs_alloc_fix_freelist(args, flags); +- args->minleft = minleft; + if (error) { + trace_xfs_alloc_vextent_nofix(args); + goto error0; +@@ -2792,20 +2736,17 @@ xfs_alloc_vextent( + * or switch to non-trylock mode. + */ + if (args->agno == sagno) { +- if (no_min == 1) { ++ if (flags == 0) { + args->agbno = NULLAGBLOCK; + trace_xfs_alloc_vextent_allfailed(args); + break; + } +- if (flags == 0) { +- no_min = 1; +- } else { +- flags = 0; +- if (type == XFS_ALLOCTYPE_START_BNO) { +- args->agbno = XFS_FSB_TO_AGBNO(mp, +- args->fsbno); +- args->type = XFS_ALLOCTYPE_NEAR_BNO; +- } ++ ++ flags = 0; ++ if (type == XFS_ALLOCTYPE_START_BNO) { ++ args->agbno = XFS_FSB_TO_AGBNO(mp, ++ args->fsbno); ++ args->type = XFS_ALLOCTYPE_NEAR_BNO; + } + } + xfs_perag_put(args->pag); +diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h +index 7c404a6..1d0f48a 100644 +--- a/fs/xfs/libxfs/xfs_alloc.h ++++ b/fs/xfs/libxfs/xfs_alloc.h +@@ -56,7 +56,7 @@ typedef unsigned int xfs_alloctype_t; + #define XFS_ALLOC_FLAG_FREEING 0x00000002 /* indicate caller is freeing extents*/ + #define XFS_ALLOC_FLAG_NORMAP 0x00000004 /* don't modify the rmapbt */ + #define XFS_ALLOC_FLAG_NOSHRINK 0x00000008 /* don't shrink the freelist */ +- ++#define XFS_ALLOC_FLAG_CHECK 0x00000010 /* test only, don't modify args */ + + /* + * Argument structure for xfs_alloc routines. +diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c +index af1ecb1..6622d46 100644 +--- a/fs/xfs/libxfs/xfs_attr.c ++++ b/fs/xfs/libxfs/xfs_attr.c +@@ -131,9 +131,6 @@ xfs_attr_get( + if (XFS_FORCED_SHUTDOWN(ip->i_mount)) + return -EIO; + +- if (!xfs_inode_hasattr(ip)) +- return -ENOATTR; +- + error = xfs_attr_args_init(&args, ip, name, flags); + if (error) + return error; +@@ -392,9 +389,6 @@ xfs_attr_remove( + if (XFS_FORCED_SHUTDOWN(dp->i_mount)) + return -EIO; + +- if (!xfs_inode_hasattr(dp)) +- return -ENOATTR; +- + error = xfs_attr_args_init(&args, dp, name, flags); + if (error) + return error; +diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c +index 89d727b..f52fd63 100644 +--- a/fs/xfs/libxfs/xfs_bmap.c ++++ b/fs/xfs/libxfs/xfs_bmap.c +@@ -3720,7 +3720,7 @@ xfs_bmap_btalloc( + align = xfs_get_cowextsz_hint(ap->ip); + else if (xfs_alloc_is_userdata(ap->datatype)) + align = xfs_get_extsz_hint(ap->ip); +- if (unlikely(align)) { ++ if (align) { + error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev, + align, 0, ap->eof, 0, ap->conv, + &ap->offset, &ap->length); +@@ -3792,7 +3792,7 @@ xfs_bmap_btalloc( + args.minlen = ap->minlen; + } + /* apply extent size hints if obtained earlier */ +- if (unlikely(align)) { ++ if (align) { + args.prod = align; + if ((args.mod = (xfs_extlen_t)do_mod(ap->offset, args.prod))) + args.mod = (xfs_extlen_t)(args.prod - args.mod); +@@ -3903,7 +3903,6 @@ xfs_bmap_btalloc( + args.fsbno = 0; + args.type = XFS_ALLOCTYPE_FIRST_AG; + args.total = ap->minlen; +- args.minleft = 0; + if ((error = xfs_alloc_vextent(&args))) + return error; + ap->dfops->dop_low = true; +@@ -4437,8 +4436,6 @@ xfs_bmapi_allocate( + if (error) + return error; + +- if (bma->dfops->dop_low) +- bma->minleft = 0; + if (bma->cur) + bma->cur->bc_private.b.firstblock = *bma->firstblock; + if (bma->blkno == NULLFSBLOCK) +@@ -4610,8 +4607,6 @@ xfs_bmapi_write( + int n; /* current extent index */ + xfs_fileoff_t obno; /* old block number (offset) */ + int whichfork; /* data or attr fork */ +- char inhole; /* current location is hole in file */ +- char wasdelay; /* old extent was delayed */ + + #ifdef DEBUG + xfs_fileoff_t orig_bno; /* original block number value */ +@@ -4697,22 +4692,44 @@ xfs_bmapi_write( + bma.firstblock = firstblock; + + while (bno < end && n < *nmap) { +- inhole = eof || bma.got.br_startoff > bno; +- wasdelay = !inhole && isnullstartblock(bma.got.br_startblock); ++ bool need_alloc = false, wasdelay = false; + +- /* +- * Make sure we only reflink into a hole. +- */ +- if (flags & XFS_BMAPI_REMAP) +- ASSERT(inhole); +- if (flags & XFS_BMAPI_COWFORK) +- ASSERT(!inhole); ++ /* in hole or beyoned EOF? */ ++ if (eof || bma.got.br_startoff > bno) { ++ if (flags & XFS_BMAPI_DELALLOC) { ++ /* ++ * For the COW fork we can reasonably get a ++ * request for converting an extent that races ++ * with other threads already having converted ++ * part of it, as there converting COW to ++ * regular blocks is not protected using the ++ * IOLOCK. ++ */ ++ ASSERT(flags & XFS_BMAPI_COWFORK); ++ if (!(flags & XFS_BMAPI_COWFORK)) { ++ error = -EIO; ++ goto error0; ++ } ++ ++ if (eof || bno >= end) ++ break; ++ } else { ++ need_alloc = true; ++ } ++ } else { ++ /* ++ * Make sure we only reflink into a hole. ++ */ ++ ASSERT(!(flags & XFS_BMAPI_REMAP)); ++ if (isnullstartblock(bma.got.br_startblock)) ++ wasdelay = true; ++ } + + /* + * First, deal with the hole before the allocated space + * that we found, if any. + */ +- if (inhole || wasdelay) { ++ if (need_alloc || wasdelay) { + bma.eof = eof; + bma.conv = !!(flags & XFS_BMAPI_CONVERT); + bma.wasdel = wasdelay; +diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h +index d6d175a..e7d40b3 100644 +--- a/fs/xfs/libxfs/xfs_bmap.h ++++ b/fs/xfs/libxfs/xfs_bmap.h +@@ -110,6 +110,9 @@ struct xfs_extent_free_item + /* Map something in the CoW fork. */ + #define XFS_BMAPI_COWFORK 0x200 + ++/* Only convert delalloc space, don't allocate entirely new extents */ ++#define XFS_BMAPI_DELALLOC 0x400 ++ + #define XFS_BMAPI_FLAGS \ + { XFS_BMAPI_ENTIRE, "ENTIRE" }, \ + { XFS_BMAPI_METADATA, "METADATA" }, \ +@@ -120,7 +123,8 @@ struct xfs_extent_free_item + { XFS_BMAPI_CONVERT, "CONVERT" }, \ + { XFS_BMAPI_ZERO, "ZERO" }, \ + { XFS_BMAPI_REMAP, "REMAP" }, \ +- { XFS_BMAPI_COWFORK, "COWFORK" } ++ { XFS_BMAPI_COWFORK, "COWFORK" }, \ ++ { XFS_BMAPI_DELALLOC, "DELALLOC" } + + + static inline int xfs_bmapi_aflag(int w) +diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c +index 049fa59..f76c169 100644 +--- a/fs/xfs/libxfs/xfs_bmap_btree.c ++++ b/fs/xfs/libxfs/xfs_bmap_btree.c +@@ -502,12 +502,11 @@ xfs_bmbt_alloc_block( + if (args.fsbno == NULLFSBLOCK && args.minleft) { + /* + * Could not find an AG with enough free space to satisfy +- * a full btree split. Try again without minleft and if ++ * a full btree split. Try again and if + * successful activate the lowspace algorithm. + */ + args.fsbno = 0; + args.type = XFS_ALLOCTYPE_FIRST_AG; +- args.minleft = 0; + error = xfs_alloc_vextent(&args); + if (error) + goto error0; +diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c +index 20a96dd..7825d78 100644 +--- a/fs/xfs/libxfs/xfs_dir2.c ++++ b/fs/xfs/libxfs/xfs_dir2.c +@@ -36,21 +36,29 @@ + struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR }; + + /* +- * @mode, if set, indicates that the type field needs to be set up. +- * This uses the transformation from file mode to DT_* as defined in linux/fs.h +- * for file type specification. This will be propagated into the directory +- * structure if appropriate for the given operation and filesystem config. ++ * Convert inode mode to directory entry filetype + */ +-const unsigned char xfs_mode_to_ftype[S_IFMT >> S_SHIFT] = { +- [0] = XFS_DIR3_FT_UNKNOWN, +- [S_IFREG >> S_SHIFT] = XFS_DIR3_FT_REG_FILE, +- [S_IFDIR >> S_SHIFT] = XFS_DIR3_FT_DIR, +- [S_IFCHR >> S_SHIFT] = XFS_DIR3_FT_CHRDEV, +- [S_IFBLK >> S_SHIFT] = XFS_DIR3_FT_BLKDEV, +- [S_IFIFO >> S_SHIFT] = XFS_DIR3_FT_FIFO, +- [S_IFSOCK >> S_SHIFT] = XFS_DIR3_FT_SOCK, +- [S_IFLNK >> S_SHIFT] = XFS_DIR3_FT_SYMLINK, +-}; ++unsigned char xfs_mode_to_ftype(int mode) ++{ ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ return XFS_DIR3_FT_REG_FILE; ++ case S_IFDIR: ++ return XFS_DIR3_FT_DIR; ++ case S_IFCHR: ++ return XFS_DIR3_FT_CHRDEV; ++ case S_IFBLK: ++ return XFS_DIR3_FT_BLKDEV; ++ case S_IFIFO: ++ return XFS_DIR3_FT_FIFO; ++ case S_IFSOCK: ++ return XFS_DIR3_FT_SOCK; ++ case S_IFLNK: ++ return XFS_DIR3_FT_SYMLINK; ++ default: ++ return XFS_DIR3_FT_UNKNOWN; ++ } ++} + + /* + * ASCII case-insensitive (ie. A-Z) support for directories that was +@@ -631,7 +639,8 @@ xfs_dir2_isblock( + if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK))) + return rval; + rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize; +- ASSERT(rval == 0 || args->dp->i_d.di_size == args->geo->blksize); ++ if (rval != 0 && args->dp->i_d.di_size != args->geo->blksize) ++ return -EFSCORRUPTED; + *vp = rval; + return 0; + } +diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h +index becc926..ae0d55b 100644 +--- a/fs/xfs/libxfs/xfs_dir2.h ++++ b/fs/xfs/libxfs/xfs_dir2.h +@@ -18,6 +18,9 @@ + #ifndef __XFS_DIR2_H__ + #define __XFS_DIR2_H__ + ++#include "xfs_da_format.h" ++#include "xfs_da_btree.h" ++ + struct xfs_defer_ops; + struct xfs_da_args; + struct xfs_inode; +@@ -32,10 +35,9 @@ struct xfs_dir2_data_unused; + extern struct xfs_name xfs_name_dotdot; + + /* +- * directory filetype conversion tables. ++ * Convert inode mode to directory entry filetype + */ +-#define S_SHIFT 12 +-extern const unsigned char xfs_mode_to_ftype[]; ++extern unsigned char xfs_mode_to_ftype(int mode); + + /* + * directory operations vector for encode/decode routines +diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c +index c906e50..37ee7f0 100644 +--- a/fs/xfs/libxfs/xfs_inode_buf.c ++++ b/fs/xfs/libxfs/xfs_inode_buf.c +@@ -29,6 +29,7 @@ + #include "xfs_icache.h" + #include "xfs_trans.h" + #include "xfs_ialloc.h" ++#include "xfs_dir2.h" + + /* + * Check that none of the inode's in the buffer have a next +@@ -386,6 +387,7 @@ xfs_dinode_verify( + struct xfs_inode *ip, + struct xfs_dinode *dip) + { ++ uint16_t mode; + uint16_t flags; + uint64_t flags2; + +@@ -396,8 +398,12 @@ xfs_dinode_verify( + if (be64_to_cpu(dip->di_size) & (1ULL << 63)) + return false; + +- /* No zero-length symlinks. */ +- if (S_ISLNK(be16_to_cpu(dip->di_mode)) && dip->di_size == 0) ++ mode = be16_to_cpu(dip->di_mode); ++ if (mode && xfs_mode_to_ftype(mode) == XFS_DIR3_FT_UNKNOWN) ++ return false; ++ ++ /* No zero-length symlinks/dirs. */ ++ if ((S_ISLNK(mode) || S_ISDIR(mode)) && dip->di_size == 0) + return false; + + /* only version 3 or greater inodes are extensively verified here */ +diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c +index 2580262..584ec89 100644 +--- a/fs/xfs/libxfs/xfs_sb.c ++++ b/fs/xfs/libxfs/xfs_sb.c +@@ -242,7 +242,7 @@ xfs_mount_validate_sb( + sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || + sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || + sbp->sb_blocksize != (1 << sbp->sb_blocklog) || +- sbp->sb_dirblklog > XFS_MAX_BLOCKSIZE_LOG || ++ sbp->sb_dirblklog + sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || + sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || + sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || + sbp->sb_inodelog < XFS_DINODE_MIN_LOG || +diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c +index 0670a8b..efb8ccd 100644 +--- a/fs/xfs/xfs_bmap_util.c ++++ b/fs/xfs/xfs_bmap_util.c +@@ -528,7 +528,6 @@ xfs_getbmap( + xfs_bmbt_irec_t *map; /* buffer for user's data */ + xfs_mount_t *mp; /* file system mount point */ + int nex; /* # of user extents can do */ +- int nexleft; /* # of user extents left */ + int subnex; /* # of bmapi's can do */ + int nmap; /* number of map entries */ + struct getbmapx *out; /* output structure */ +@@ -686,10 +685,8 @@ xfs_getbmap( + goto out_free_map; + } + +- nexleft = nex; +- + do { +- nmap = (nexleft > subnex) ? subnex : nexleft; ++ nmap = (nex> subnex) ? subnex : nex; + error = xfs_bmapi_read(ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset), + XFS_BB_TO_FSB(mp, bmv->bmv_length), + map, &nmap, bmapi_flags); +@@ -697,8 +694,8 @@ xfs_getbmap( + goto out_free_map; + ASSERT(nmap <= subnex); + +- for (i = 0; i < nmap && nexleft && bmv->bmv_length && +- cur_ext < bmv->bmv_count; i++) { ++ for (i = 0; i < nmap && bmv->bmv_length && ++ cur_ext < bmv->bmv_count - 1; i++) { + out[cur_ext].bmv_oflags = 0; + if (map[i].br_state == XFS_EXT_UNWRITTEN) + out[cur_ext].bmv_oflags |= BMV_OF_PREALLOC; +@@ -760,16 +757,27 @@ xfs_getbmap( + continue; + } + ++ /* ++ * In order to report shared extents accurately, ++ * we report each distinct shared/unshared part ++ * of a single bmbt record using multiple bmap ++ * extents. To make that happen, we iterate the ++ * same map array item multiple times, each ++ * time trimming out the subextent that we just ++ * reported. ++ * ++ * Because of this, we must check the out array ++ * index (cur_ext) directly against bmv_count-1 ++ * to avoid overflows. ++ */ + if (inject_map.br_startblock != NULLFSBLOCK) { + map[i] = inject_map; + i--; +- } else +- nexleft--; ++ } + bmv->bmv_entries++; + cur_ext++; + } +- } while (nmap && nexleft && bmv->bmv_length && +- cur_ext < bmv->bmv_count); ++ } while (nmap && bmv->bmv_length && cur_ext < bmv->bmv_count - 1); + + out_free_map: + kmem_free(map); +diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c +index b5b9bff..d7a67d7 100644 +--- a/fs/xfs/xfs_buf.c ++++ b/fs/xfs/xfs_buf.c +@@ -423,6 +423,7 @@ xfs_buf_allocate_memory( + out_free_pages: + for (i = 0; i < bp->b_page_count; i++) + __free_page(bp->b_pages[i]); ++ bp->b_flags &= ~_XBF_PAGES; + return error; + } + +diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c +index 7a30b8f..9d06cc3 100644 +--- a/fs/xfs/xfs_dquot.c ++++ b/fs/xfs/xfs_dquot.c +@@ -710,6 +710,10 @@ xfs_dq_get_next_id( + /* Simple advance */ + next_id = *id + 1; + ++ /* If we'd wrap past the max ID, stop */ ++ if (next_id < *id) ++ return -ENOENT; ++ + /* If new ID is within the current chunk, advancing it sufficed */ + if (next_id % mp->m_quotainfo->qi_dqperchunk) { + *id = next_id; +diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c +index 15a83813..cdc6bdd 100644 +--- a/fs/xfs/xfs_iomap.c ++++ b/fs/xfs/xfs_iomap.c +@@ -681,7 +681,7 @@ xfs_iomap_write_allocate( + xfs_trans_t *tp; + int nimaps; + int error = 0; +- int flags = 0; ++ int flags = XFS_BMAPI_DELALLOC; + int nres; + + if (whichfork == XFS_COW_FORK) +diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c +index 405a65c..f5e0f60 100644 +--- a/fs/xfs/xfs_iops.c ++++ b/fs/xfs/xfs_iops.c +@@ -98,12 +98,27 @@ xfs_init_security( + static void + xfs_dentry_to_name( + struct xfs_name *namep, ++ struct dentry *dentry) ++{ ++ namep->name = dentry->d_name.name; ++ namep->len = dentry->d_name.len; ++ namep->type = XFS_DIR3_FT_UNKNOWN; ++} ++ ++static int ++xfs_dentry_mode_to_name( ++ struct xfs_name *namep, + struct dentry *dentry, + int mode) + { + namep->name = dentry->d_name.name; + namep->len = dentry->d_name.len; +- namep->type = xfs_mode_to_ftype[(mode & S_IFMT) >> S_SHIFT]; ++ namep->type = xfs_mode_to_ftype(mode); ++ ++ if (unlikely(namep->type == XFS_DIR3_FT_UNKNOWN)) ++ return -EFSCORRUPTED; ++ ++ return 0; + } + + STATIC void +@@ -119,7 +134,7 @@ xfs_cleanup_inode( + * xfs_init_security we must back out. + * ENOSPC can hit here, among other things. + */ +- xfs_dentry_to_name(&teardown, dentry, 0); ++ xfs_dentry_to_name(&teardown, dentry); + + xfs_remove(XFS_I(dir), &teardown, XFS_I(inode)); + } +@@ -154,8 +169,12 @@ xfs_generic_create( + if (error) + return error; + ++ /* Verify mode is valid also for tmpfile case */ ++ error = xfs_dentry_mode_to_name(&name, dentry, mode); ++ if (unlikely(error)) ++ goto out_free_acl; ++ + if (!tmpfile) { +- xfs_dentry_to_name(&name, dentry, mode); + error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip); + } else { + error = xfs_create_tmpfile(XFS_I(dir), dentry, mode, &ip); +@@ -248,7 +267,7 @@ xfs_vn_lookup( + if (dentry->d_name.len >= MAXNAMELEN) + return ERR_PTR(-ENAMETOOLONG); + +- xfs_dentry_to_name(&name, dentry, 0); ++ xfs_dentry_to_name(&name, dentry); + error = xfs_lookup(XFS_I(dir), &name, &cip, NULL); + if (unlikely(error)) { + if (unlikely(error != -ENOENT)) +@@ -275,7 +294,7 @@ xfs_vn_ci_lookup( + if (dentry->d_name.len >= MAXNAMELEN) + return ERR_PTR(-ENAMETOOLONG); + +- xfs_dentry_to_name(&xname, dentry, 0); ++ xfs_dentry_to_name(&xname, dentry); + error = xfs_lookup(XFS_I(dir), &xname, &ip, &ci_name); + if (unlikely(error)) { + if (unlikely(error != -ENOENT)) +@@ -310,7 +329,9 @@ xfs_vn_link( + struct xfs_name name; + int error; + +- xfs_dentry_to_name(&name, dentry, inode->i_mode); ++ error = xfs_dentry_mode_to_name(&name, dentry, inode->i_mode); ++ if (unlikely(error)) ++ return error; + + error = xfs_link(XFS_I(dir), XFS_I(inode), &name); + if (unlikely(error)) +@@ -329,7 +350,7 @@ xfs_vn_unlink( + struct xfs_name name; + int error; + +- xfs_dentry_to_name(&name, dentry, 0); ++ xfs_dentry_to_name(&name, dentry); + + error = xfs_remove(XFS_I(dir), &name, XFS_I(d_inode(dentry))); + if (error) +@@ -359,7 +380,9 @@ xfs_vn_symlink( + + mode = S_IFLNK | + (irix_symlink_mode ? 0777 & ~current_umask() : S_IRWXUGO); +- xfs_dentry_to_name(&name, dentry, mode); ++ error = xfs_dentry_mode_to_name(&name, dentry, mode); ++ if (unlikely(error)) ++ goto out; + + error = xfs_symlink(XFS_I(dir), &name, symname, mode, &cip); + if (unlikely(error)) +@@ -395,6 +418,7 @@ xfs_vn_rename( + { + struct inode *new_inode = d_inode(ndentry); + int omode = 0; ++ int error; + struct xfs_name oname; + struct xfs_name nname; + +@@ -405,8 +429,14 @@ xfs_vn_rename( + if (flags & RENAME_EXCHANGE) + omode = d_inode(ndentry)->i_mode; + +- xfs_dentry_to_name(&oname, odentry, omode); +- xfs_dentry_to_name(&nname, ndentry, d_inode(odentry)->i_mode); ++ error = xfs_dentry_mode_to_name(&oname, odentry, omode); ++ if (omode && unlikely(error)) ++ return error; ++ ++ error = xfs_dentry_mode_to_name(&nname, ndentry, ++ d_inode(odentry)->i_mode); ++ if (unlikely(error)) ++ return error; + + return xfs_rename(XFS_I(odir), &oname, XFS_I(d_inode(odentry)), + XFS_I(ndir), &nname, +diff --git a/fs/xfs/xfs_linux.h b/fs/xfs/xfs_linux.h +index 68640fb..1455b2520 100644 +--- a/fs/xfs/xfs_linux.h ++++ b/fs/xfs/xfs_linux.h +@@ -330,11 +330,11 @@ static inline __uint64_t howmany_64(__uint64_t x, __uint32_t y) + } + + #define ASSERT_ALWAYS(expr) \ +- (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) ++ (likely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) + + #ifdef DEBUG + #define ASSERT(expr) \ +- (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) ++ (likely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) + + #ifndef STATIC + # define STATIC noinline +@@ -345,7 +345,7 @@ static inline __uint64_t howmany_64(__uint64_t x, __uint32_t y) + #ifdef XFS_WARN + + #define ASSERT(expr) \ +- (unlikely(expr) ? (void)0 : asswarn(#expr, __FILE__, __LINE__)) ++ (likely(expr) ? (void)0 : asswarn(#expr, __FILE__, __LINE__)) + + #ifndef STATIC + # define STATIC static noinline +diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c +index 3b74fa0..4017aa9 100644 +--- a/fs/xfs/xfs_log.c ++++ b/fs/xfs/xfs_log.c +@@ -3324,12 +3324,8 @@ xfs_log_force( + xfs_mount_t *mp, + uint flags) + { +- int error; +- + trace_xfs_log_force(mp, 0, _RET_IP_); +- error = _xfs_log_force(mp, flags, NULL); +- if (error) +- xfs_warn(mp, "%s: error %d returned.", __func__, error); ++ _xfs_log_force(mp, flags, NULL); + } + + /* +@@ -3473,12 +3469,8 @@ xfs_log_force_lsn( + xfs_lsn_t lsn, + uint flags) + { +- int error; +- + trace_xfs_log_force(mp, lsn, _RET_IP_); +- error = _xfs_log_force_lsn(mp, lsn, flags, NULL); +- if (error) +- xfs_warn(mp, "%s: error %d returned.", __func__, error); ++ _xfs_log_force_lsn(mp, lsn, flags, NULL); + } + + /* +diff --git a/include/linux/tcp.h b/include/linux/tcp.h +index a17ae7b..647532b 100644 +--- a/include/linux/tcp.h ++++ b/include/linux/tcp.h +@@ -62,8 +62,13 @@ static inline unsigned int tcp_optlen(const struct sk_buff *skb) + + /* TCP Fast Open Cookie as stored in memory */ + struct tcp_fastopen_cookie { ++ union { ++ u8 val[TCP_FASTOPEN_COOKIE_MAX]; ++#if IS_ENABLED(CONFIG_IPV6) ++ struct in6_addr addr; ++#endif ++ }; + s8 len; +- u8 val[TCP_FASTOPEN_COOKIE_MAX]; + bool exp; /* In RFC6994 experimental option format */ + }; + +diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h +index 1c912f8..f211c34 100644 +--- a/include/linux/virtio_net.h ++++ b/include/linux/virtio_net.h +@@ -56,7 +56,8 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb, + + static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb, + struct virtio_net_hdr *hdr, +- bool little_endian) ++ bool little_endian, ++ bool has_data_valid) + { + memset(hdr, 0, sizeof(*hdr)); + +@@ -91,7 +92,8 @@ static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb, + skb_checksum_start_offset(skb)); + hdr->csum_offset = __cpu_to_virtio16(little_endian, + skb->csum_offset); +- } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { ++ } else if (has_data_valid && ++ skb->ip_summed == CHECKSUM_UNNECESSARY) { + hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID; + } /* else everything is zero */ + +diff --git a/include/net/lwtunnel.h b/include/net/lwtunnel.h +index ea3f80f..fc7c0db 100644 +--- a/include/net/lwtunnel.h ++++ b/include/net/lwtunnel.h +@@ -43,13 +43,12 @@ struct lwtunnel_encap_ops { + int (*get_encap_size)(struct lwtunnel_state *lwtstate); + int (*cmp_encap)(struct lwtunnel_state *a, struct lwtunnel_state *b); + int (*xmit)(struct sk_buff *skb); ++ ++ struct module *owner; + }; + + #ifdef CONFIG_LWTUNNEL +-static inline void lwtstate_free(struct lwtunnel_state *lws) +-{ +- kfree(lws); +-} ++void lwtstate_free(struct lwtunnel_state *lws); + + static inline struct lwtunnel_state * + lwtstate_get(struct lwtunnel_state *lws) +@@ -106,6 +105,8 @@ int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op, + unsigned int num); + int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op, + unsigned int num); ++int lwtunnel_valid_encap_type(u16 encap_type); ++int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len); + int lwtunnel_build_state(struct net_device *dev, u16 encap_type, + struct nlattr *encap, + unsigned int family, const void *cfg, +@@ -169,6 +170,15 @@ static inline int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op, + return -EOPNOTSUPP; + } + ++static inline int lwtunnel_valid_encap_type(u16 encap_type) ++{ ++ return -EOPNOTSUPP; ++} ++static inline int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len) ++{ ++ return -EOPNOTSUPP; ++} ++ + static inline int lwtunnel_build_state(struct net_device *dev, u16 encap_type, + struct nlattr *encap, + unsigned int family, const void *cfg, +diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c +index 655a7d4..983f0b5 100644 +--- a/net/ax25/ax25_subr.c ++++ b/net/ax25/ax25_subr.c +@@ -264,7 +264,7 @@ void ax25_disconnect(ax25_cb *ax25, int reason) + { + ax25_clear_queues(ax25); + +- if (!sock_flag(ax25->sk, SOCK_DESTROY)) ++ if (!ax25->sk || !sock_flag(ax25->sk, SOCK_DESTROY)) + ax25_stop_heartbeat(ax25); + ax25_stop_t1timer(ax25); + ax25_stop_t2timer(ax25); +diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c +index e99037c..0474106 100644 +--- a/net/bridge/br_netlink.c ++++ b/net/bridge/br_netlink.c +@@ -781,20 +781,6 @@ static int br_validate(struct nlattr *tb[], struct nlattr *data[]) + return 0; + } + +-static int br_dev_newlink(struct net *src_net, struct net_device *dev, +- struct nlattr *tb[], struct nlattr *data[]) +-{ +- struct net_bridge *br = netdev_priv(dev); +- +- if (tb[IFLA_ADDRESS]) { +- spin_lock_bh(&br->lock); +- br_stp_change_bridge_id(br, nla_data(tb[IFLA_ADDRESS])); +- spin_unlock_bh(&br->lock); +- } +- +- return register_netdevice(dev); +-} +- + static int br_port_slave_changelink(struct net_device *brdev, + struct net_device *dev, + struct nlattr *tb[], +@@ -1093,6 +1079,25 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[], + return 0; + } + ++static int br_dev_newlink(struct net *src_net, struct net_device *dev, ++ struct nlattr *tb[], struct nlattr *data[]) ++{ ++ struct net_bridge *br = netdev_priv(dev); ++ int err; ++ ++ if (tb[IFLA_ADDRESS]) { ++ spin_lock_bh(&br->lock); ++ br_stp_change_bridge_id(br, nla_data(tb[IFLA_ADDRESS])); ++ spin_unlock_bh(&br->lock); ++ } ++ ++ err = br_changelink(dev, tb, data); ++ if (err) ++ return err; ++ ++ return register_netdevice(dev); ++} ++ + static size_t br_get_size(const struct net_device *brdev) + { + return nla_total_size(sizeof(u32)) + /* IFLA_BR_FORWARD_DELAY */ +diff --git a/net/core/dev.c b/net/core/dev.c +index e1d731f..df51c50 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -2815,9 +2815,9 @@ static netdev_features_t harmonize_features(struct sk_buff *skb, + if (skb->ip_summed != CHECKSUM_NONE && + !can_checksum_protocol(features, type)) { + features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); +- } else if (illegal_highdma(skb->dev, skb)) { +- features &= ~NETIF_F_SG; + } ++ if (illegal_highdma(skb->dev, skb)) ++ features &= ~NETIF_F_SG; + + return features; + } +diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c +index e5f84c2..afa64f0 100644 +--- a/net/core/lwtunnel.c ++++ b/net/core/lwtunnel.c +@@ -26,6 +26,7 @@ + #include <net/lwtunnel.h> + #include <net/rtnetlink.h> + #include <net/ip6_fib.h> ++#include <net/nexthop.h> + + #ifdef CONFIG_MODULES + +@@ -65,6 +66,15 @@ EXPORT_SYMBOL(lwtunnel_state_alloc); + static const struct lwtunnel_encap_ops __rcu * + lwtun_encaps[LWTUNNEL_ENCAP_MAX + 1] __read_mostly; + ++void lwtstate_free(struct lwtunnel_state *lws) ++{ ++ const struct lwtunnel_encap_ops *ops = lwtun_encaps[lws->type]; ++ ++ kfree(lws); ++ module_put(ops->owner); ++} ++EXPORT_SYMBOL(lwtstate_free); ++ + int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *ops, + unsigned int num) + { +@@ -110,25 +120,77 @@ int lwtunnel_build_state(struct net_device *dev, u16 encap_type, + ret = -EOPNOTSUPP; + rcu_read_lock(); + ops = rcu_dereference(lwtun_encaps[encap_type]); ++ if (likely(ops && ops->build_state && try_module_get(ops->owner))) { ++ ret = ops->build_state(dev, encap, family, cfg, lws); ++ if (ret) ++ module_put(ops->owner); ++ } ++ rcu_read_unlock(); ++ ++ return ret; ++} ++EXPORT_SYMBOL(lwtunnel_build_state); ++ ++int lwtunnel_valid_encap_type(u16 encap_type) ++{ ++ const struct lwtunnel_encap_ops *ops; ++ int ret = -EINVAL; ++ ++ if (encap_type == LWTUNNEL_ENCAP_NONE || ++ encap_type > LWTUNNEL_ENCAP_MAX) ++ return ret; ++ ++ rcu_read_lock(); ++ ops = rcu_dereference(lwtun_encaps[encap_type]); ++ rcu_read_unlock(); + #ifdef CONFIG_MODULES + if (!ops) { + const char *encap_type_str = lwtunnel_encap_str(encap_type); + + if (encap_type_str) { +- rcu_read_unlock(); ++ __rtnl_unlock(); + request_module("rtnl-lwt-%s", encap_type_str); ++ rtnl_lock(); ++ + rcu_read_lock(); + ops = rcu_dereference(lwtun_encaps[encap_type]); ++ rcu_read_unlock(); + } + } + #endif +- if (likely(ops && ops->build_state)) +- ret = ops->build_state(dev, encap, family, cfg, lws); +- rcu_read_unlock(); ++ return ops ? 0 : -EOPNOTSUPP; ++} ++EXPORT_SYMBOL(lwtunnel_valid_encap_type); + +- return ret; ++int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int remaining) ++{ ++ struct rtnexthop *rtnh = (struct rtnexthop *)attr; ++ struct nlattr *nla_entype; ++ struct nlattr *attrs; ++ struct nlattr *nla; ++ u16 encap_type; ++ int attrlen; ++ ++ while (rtnh_ok(rtnh, remaining)) { ++ attrlen = rtnh_attrlen(rtnh); ++ if (attrlen > 0) { ++ attrs = rtnh_attrs(rtnh); ++ nla = nla_find(attrs, attrlen, RTA_ENCAP); ++ nla_entype = nla_find(attrs, attrlen, RTA_ENCAP_TYPE); ++ ++ if (nla_entype) { ++ encap_type = nla_get_u16(nla_entype); ++ ++ if (lwtunnel_valid_encap_type(encap_type) != 0) ++ return -EOPNOTSUPP; ++ } ++ } ++ rtnh = rtnh_next(rtnh, &remaining); ++ } ++ ++ return 0; + } +-EXPORT_SYMBOL(lwtunnel_build_state); ++EXPORT_SYMBOL(lwtunnel_valid_encap_type_attr); + + int lwtunnel_fill_encap(struct sk_buff *skb, struct lwtunnel_state *lwtstate) + { +diff --git a/net/dsa/slave.c b/net/dsa/slave.c +index 30e2e21..3ff9d97 100644 +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -1201,6 +1201,8 @@ int dsa_slave_suspend(struct net_device *slave_dev) + { + struct dsa_slave_priv *p = netdev_priv(slave_dev); + ++ netif_device_detach(slave_dev); ++ + if (p->phy) { + phy_stop(p->phy); + p->old_pause = -1; +diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c +index 3e4f183..5b03d7f 100644 +--- a/net/ipv4/fib_frontend.c ++++ b/net/ipv4/fib_frontend.c +@@ -46,6 +46,7 @@ + #include <net/rtnetlink.h> + #include <net/xfrm.h> + #include <net/l3mdev.h> ++#include <net/lwtunnel.h> + #include <trace/events/fib.h> + + #ifndef CONFIG_IP_MULTIPLE_TABLES +@@ -676,6 +677,10 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb, + cfg->fc_mx_len = nla_len(attr); + break; + case RTA_MULTIPATH: ++ err = lwtunnel_valid_encap_type_attr(nla_data(attr), ++ nla_len(attr)); ++ if (err < 0) ++ goto errout; + cfg->fc_mp = nla_data(attr); + cfg->fc_mp_len = nla_len(attr); + break; +@@ -690,6 +695,9 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb, + break; + case RTA_ENCAP_TYPE: + cfg->fc_encap_type = nla_get_u16(attr); ++ err = lwtunnel_valid_encap_type(cfg->fc_encap_type); ++ if (err < 0) ++ goto errout; + break; + } + } +diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c +index a8508b7..6a40680 100644 +--- a/net/ipv4/fib_semantics.c ++++ b/net/ipv4/fib_semantics.c +@@ -1278,8 +1278,9 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event, + nla_put_u32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid)) + goto nla_put_failure; + #endif +- if (fi->fib_nh->nh_lwtstate) +- lwtunnel_fill_encap(skb, fi->fib_nh->nh_lwtstate); ++ if (fi->fib_nh->nh_lwtstate && ++ lwtunnel_fill_encap(skb, fi->fib_nh->nh_lwtstate) < 0) ++ goto nla_put_failure; + } + #ifdef CONFIG_IP_ROUTE_MULTIPATH + if (fi->fib_nhs > 1) { +@@ -1315,8 +1316,10 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event, + nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid)) + goto nla_put_failure; + #endif +- if (nh->nh_lwtstate) +- lwtunnel_fill_encap(skb, nh->nh_lwtstate); ++ if (nh->nh_lwtstate && ++ lwtunnel_fill_encap(skb, nh->nh_lwtstate) < 0) ++ goto nla_put_failure; ++ + /* length of rtnetlink header + attributes */ + rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *) rtnh; + } endfor_nexthops(fi); +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index fed3d29..0fd1976 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -313,6 +313,7 @@ static const struct lwtunnel_encap_ops ip_tun_lwt_ops = { + .fill_encap = ip_tun_fill_encap_info, + .get_encap_size = ip_tun_encap_nlsize, + .cmp_encap = ip_tun_cmp_encap, ++ .owner = THIS_MODULE, + }; + + static const struct nla_policy ip6_tun_policy[LWTUNNEL_IP6_MAX + 1] = { +@@ -403,6 +404,7 @@ static const struct lwtunnel_encap_ops ip6_tun_lwt_ops = { + .fill_encap = ip6_tun_fill_encap_info, + .get_encap_size = ip6_tun_encap_nlsize, + .cmp_encap = ip_tun_cmp_encap, ++ .owner = THIS_MODULE, + }; + + void __init ip_tunnel_core_init(void) +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index 8197b06..d851cae 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -2440,7 +2440,7 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src, u32 table_id, + r->rtm_dst_len = 32; + r->rtm_src_len = 0; + r->rtm_tos = fl4->flowi4_tos; +- r->rtm_table = table_id; ++ r->rtm_table = table_id < 256 ? table_id : RT_TABLE_COMPAT; + if (nla_put_u32(skb, RTA_TABLE, table_id)) + goto nla_put_failure; + r->rtm_type = rt->rt_type; +diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c +index 4e777a3..dd2560c 100644 +--- a/net/ipv4/tcp_fastopen.c ++++ b/net/ipv4/tcp_fastopen.c +@@ -113,7 +113,7 @@ static bool tcp_fastopen_cookie_gen(struct request_sock *req, + struct tcp_fastopen_cookie tmp; + + if (__tcp_fastopen_cookie_gen(&ip6h->saddr, &tmp)) { +- struct in6_addr *buf = (struct in6_addr *) tmp.val; ++ struct in6_addr *buf = &tmp.addr; + int i; + + for (i = 0; i < 4; i++) +@@ -205,6 +205,7 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk, + * scaled. So correct it appropriately. + */ + tp->snd_wnd = ntohs(tcp_hdr(skb)->window); ++ tp->max_window = tp->snd_wnd; + + /* Activate the retrans timer so that SYNACK can be retransmitted. + * The request socket is not added to the ehash +diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c +index 4bc5ba3..95dfcba 100644 +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -5515,8 +5515,7 @@ static void addrconf_disable_change(struct net *net, __s32 newf) + struct net_device *dev; + struct inet6_dev *idev; + +- rcu_read_lock(); +- for_each_netdev_rcu(net, dev) { ++ for_each_netdev(net, dev) { + idev = __in6_dev_get(dev); + if (idev) { + int changed = (!idev->cnf.disable_ipv6) ^ (!newf); +@@ -5525,7 +5524,6 @@ static void addrconf_disable_change(struct net *net, __s32 newf) + dev_disable_change(idev); + } + } +- rcu_read_unlock(); + } + + static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int newf) +diff --git a/net/ipv6/ila/ila_lwt.c b/net/ipv6/ila/ila_lwt.c +index e50c27a..f3db364 100644 +--- a/net/ipv6/ila/ila_lwt.c ++++ b/net/ipv6/ila/ila_lwt.c +@@ -164,6 +164,7 @@ static const struct lwtunnel_encap_ops ila_encap_ops = { + .fill_encap = ila_fill_encap_info, + .get_encap_size = ila_encap_nlsize, + .cmp_encap = ila_encap_cmp, ++ .owner = THIS_MODULE, + }; + + int ila_lwt_init(void) +diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c +index d76674e..f95437f 100644 +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -1108,7 +1108,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield, + t->parms.name); + goto tx_err_dst_release; + } +- mtu = dst_mtu(dst) - psh_hlen; ++ mtu = dst_mtu(dst) - psh_hlen - t->tun_hlen; + if (encap_limit >= 0) { + max_headroom += 8; + mtu -= 8; +@@ -1117,7 +1117,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield, + mtu = IPV6_MIN_MTU; + if (skb_dst(skb) && !t->parms.collect_md) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); +- if (skb->len > mtu && !skb_is_gso(skb)) { ++ if (skb->len - t->tun_hlen > mtu && !skb_is_gso(skb)) { + *pmtu = mtu; + err = -EMSGSIZE; + goto tx_err_dst_release; +diff --git a/net/ipv6/route.c b/net/ipv6/route.c +index 1b57e11..bff4460 100644 +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -2885,6 +2885,11 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, + if (tb[RTA_MULTIPATH]) { + cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]); + cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]); ++ ++ err = lwtunnel_valid_encap_type_attr(cfg->fc_mp, ++ cfg->fc_mp_len); ++ if (err < 0) ++ goto errout; + } + + if (tb[RTA_PREF]) { +@@ -2898,9 +2903,14 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, + if (tb[RTA_ENCAP]) + cfg->fc_encap = tb[RTA_ENCAP]; + +- if (tb[RTA_ENCAP_TYPE]) ++ if (tb[RTA_ENCAP_TYPE]) { + cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]); + ++ err = lwtunnel_valid_encap_type(cfg->fc_encap_type); ++ if (err < 0) ++ goto errout; ++ } ++ + if (tb[RTA_EXPIRES]) { + unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ); + +@@ -3306,7 +3316,8 @@ static int rt6_fill_node(struct net *net, + if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags))) + goto nla_put_failure; + +- lwtunnel_fill_encap(skb, rt->dst.lwtstate); ++ if (lwtunnel_fill_encap(skb, rt->dst.lwtstate) < 0) ++ goto nla_put_failure; + + nlmsg_end(skb, nlh); + return 0; +diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c +index 15fe976..5b77377 100644 +--- a/net/mpls/af_mpls.c ++++ b/net/mpls/af_mpls.c +@@ -98,18 +98,19 @@ bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) + } + EXPORT_SYMBOL_GPL(mpls_pkt_too_big); + +-static u32 mpls_multipath_hash(struct mpls_route *rt, +- struct sk_buff *skb, bool bos) ++static u32 mpls_multipath_hash(struct mpls_route *rt, struct sk_buff *skb) + { + struct mpls_entry_decoded dec; ++ unsigned int mpls_hdr_len = 0; + struct mpls_shim_hdr *hdr; + bool eli_seen = false; + int label_index; + u32 hash = 0; + +- for (label_index = 0; label_index < MAX_MP_SELECT_LABELS && !bos; ++ for (label_index = 0; label_index < MAX_MP_SELECT_LABELS; + label_index++) { +- if (!pskb_may_pull(skb, sizeof(*hdr) * label_index)) ++ mpls_hdr_len += sizeof(*hdr); ++ if (!pskb_may_pull(skb, mpls_hdr_len)) + break; + + /* Read and decode the current label */ +@@ -134,37 +135,38 @@ static u32 mpls_multipath_hash(struct mpls_route *rt, + eli_seen = true; + } + +- bos = dec.bos; +- if (bos && pskb_may_pull(skb, sizeof(*hdr) * label_index + +- sizeof(struct iphdr))) { ++ if (!dec.bos) ++ continue; ++ ++ /* found bottom label; does skb have room for a header? */ ++ if (pskb_may_pull(skb, mpls_hdr_len + sizeof(struct iphdr))) { + const struct iphdr *v4hdr; + +- v4hdr = (const struct iphdr *)(mpls_hdr(skb) + +- label_index); ++ v4hdr = (const struct iphdr *)(hdr + 1); + if (v4hdr->version == 4) { + hash = jhash_3words(ntohl(v4hdr->saddr), + ntohl(v4hdr->daddr), + v4hdr->protocol, hash); + } else if (v4hdr->version == 6 && +- pskb_may_pull(skb, sizeof(*hdr) * label_index + +- sizeof(struct ipv6hdr))) { ++ pskb_may_pull(skb, mpls_hdr_len + ++ sizeof(struct ipv6hdr))) { + const struct ipv6hdr *v6hdr; + +- v6hdr = (const struct ipv6hdr *)(mpls_hdr(skb) + +- label_index); +- ++ v6hdr = (const struct ipv6hdr *)(hdr + 1); + hash = __ipv6_addr_jhash(&v6hdr->saddr, hash); + hash = __ipv6_addr_jhash(&v6hdr->daddr, hash); + hash = jhash_1word(v6hdr->nexthdr, hash); + } + } ++ ++ break; + } + + return hash; + } + + static struct mpls_nh *mpls_select_multipath(struct mpls_route *rt, +- struct sk_buff *skb, bool bos) ++ struct sk_buff *skb) + { + int alive = ACCESS_ONCE(rt->rt_nhn_alive); + u32 hash = 0; +@@ -180,7 +182,7 @@ static struct mpls_nh *mpls_select_multipath(struct mpls_route *rt, + if (alive <= 0) + return NULL; + +- hash = mpls_multipath_hash(rt, skb, bos); ++ hash = mpls_multipath_hash(rt, skb); + nh_index = hash % alive; + if (alive == rt->rt_nhn) + goto out; +@@ -278,17 +280,11 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev, + hdr = mpls_hdr(skb); + dec = mpls_entry_decode(hdr); + +- /* Pop the label */ +- skb_pull(skb, sizeof(*hdr)); +- skb_reset_network_header(skb); +- +- skb_orphan(skb); +- + rt = mpls_route_input_rcu(net, dec.label); + if (!rt) + goto drop; + +- nh = mpls_select_multipath(rt, skb, dec.bos); ++ nh = mpls_select_multipath(rt, skb); + if (!nh) + goto drop; + +@@ -297,6 +293,12 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev, + if (!mpls_output_possible(out_dev)) + goto drop; + ++ /* Pop the label */ ++ skb_pull(skb, sizeof(*hdr)); ++ skb_reset_network_header(skb); ++ ++ skb_orphan(skb); ++ + if (skb_warn_if_lro(skb)) + goto drop; + +diff --git a/net/mpls/mpls_iptunnel.c b/net/mpls/mpls_iptunnel.c +index cf52cf3..bc9aaf5 100644 +--- a/net/mpls/mpls_iptunnel.c ++++ b/net/mpls/mpls_iptunnel.c +@@ -218,6 +218,7 @@ static const struct lwtunnel_encap_ops mpls_iptun_ops = { + .fill_encap = mpls_fill_encap_info, + .get_encap_size = mpls_encap_nlsize, + .cmp_encap = mpls_encap_cmp, ++ .owner = THIS_MODULE, + }; + + static int __init mpls_iptunnel_init(void) +diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c +index fecefa2..eab210b 100644 +--- a/net/openvswitch/conntrack.c ++++ b/net/openvswitch/conntrack.c +@@ -514,7 +514,7 @@ static int ovs_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct, + int hooknum, nh_off, err = NF_ACCEPT; + + nh_off = skb_network_offset(skb); +- skb_pull(skb, nh_off); ++ skb_pull_rcsum(skb, nh_off); + + /* See HOOK2MANIP(). */ + if (maniptype == NF_NAT_MANIP_SRC) +@@ -579,6 +579,7 @@ static int ovs_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct, + err = nf_nat_packet(ct, ctinfo, hooknum, skb); + push: + skb_push(skb, nh_off); ++ skb_postpush_rcsum(skb, skb->data, nh_off); + + return err; + } +@@ -890,7 +891,7 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb, + + /* The conntrack module expects to be working at L3. */ + nh_ofs = skb_network_offset(skb); +- skb_pull(skb, nh_ofs); ++ skb_pull_rcsum(skb, nh_ofs); + + if (key->ip.frag != OVS_FRAG_TYPE_NONE) { + err = handle_fragments(net, key, info->zone.id, skb); +@@ -904,6 +905,7 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb, + err = ovs_ct_lookup(net, key, info, skb); + + skb_push(skb, nh_ofs); ++ skb_postpush_rcsum(skb, skb->data, nh_ofs); + if (err) + kfree_skb(skb); + return err; +diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c +index dd23323..94e4a59 100644 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -1972,7 +1972,7 @@ static int __packet_rcv_vnet(const struct sk_buff *skb, + { + *vnet_hdr = (const struct virtio_net_hdr) { 0 }; + +- if (virtio_net_hdr_from_skb(skb, vnet_hdr, vio_le())) ++ if (virtio_net_hdr_from_skb(skb, vnet_hdr, vio_le(), true)) + BUG(); + + return 0; +diff --git a/net/sched/act_api.c b/net/sched/act_api.c +index f893d18..c6c2a93 100644 +--- a/net/sched/act_api.c ++++ b/net/sched/act_api.c +@@ -903,8 +903,6 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, + goto err; + } + act->order = i; +- if (event == RTM_GETACTION) +- act->tcfa_refcnt++; + list_add_tail(&act->list, &actions); + } + +@@ -917,7 +915,8 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, + return ret; + } + err: +- tcf_action_destroy(&actions, 0); ++ if (event != RTM_GETACTION) ++ tcf_action_destroy(&actions, 0); + return ret; + } + +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 2358f26..2d03d5b 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -995,6 +995,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + unsigned int hash; + struct unix_address *addr; + struct hlist_head *list; ++ struct path path = { NULL, NULL }; + + err = -EINVAL; + if (sunaddr->sun_family != AF_UNIX) +@@ -1010,9 +1011,20 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + goto out; + addr_len = err; + ++ if (sun_path[0]) { ++ umode_t mode = S_IFSOCK | ++ (SOCK_INODE(sock)->i_mode & ~current_umask()); ++ err = unix_mknod(sun_path, mode, &path); ++ if (err) { ++ if (err == -EEXIST) ++ err = -EADDRINUSE; ++ goto out; ++ } ++ } ++ + err = mutex_lock_interruptible(&u->bindlock); + if (err) +- goto out; ++ goto out_put; + + err = -EINVAL; + if (u->addr) +@@ -1029,16 +1041,6 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + atomic_set(&addr->refcnt, 1); + + if (sun_path[0]) { +- struct path path; +- umode_t mode = S_IFSOCK | +- (SOCK_INODE(sock)->i_mode & ~current_umask()); +- err = unix_mknod(sun_path, mode, &path); +- if (err) { +- if (err == -EEXIST) +- err = -EADDRINUSE; +- unix_release_addr(addr); +- goto out_up; +- } + addr->hash = UNIX_HASH_SIZE; + hash = d_real_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1); + spin_lock(&unix_table_lock); +@@ -1065,6 +1067,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) + spin_unlock(&unix_table_lock); + out_up: + mutex_unlock(&u->bindlock); ++out_put: ++ if (err) ++ path_put(&path); + out: + return err; + } |