commit:     bea0a2cdc30808ed55ebdaf1c1f96a3a14622cc9
Author:     Arisu Tachibana <alicef <AT> gentoo <DOT> org>
AuthorDate: Thu Aug 21 05:16:30 2025 +0000
Commit:     Arisu Tachibana <alicef <AT> gentoo <DOT> org>
CommitDate: Thu Aug 21 05:16:30 2025 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=bea0a2cd

Linux patch 5.4.277

Signed-off-by: Arisu Tachibana <alicef <AT> gentoo.org>

 0000_README              |   4 +
 1276_linux-5.4.277.patch | 672 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 676 insertions(+)

diff --git a/0000_README b/0000_README
index 45e0bd46..7d241cb7 100644
--- a/0000_README
+++ b/0000_README
@@ -1147,6 +1147,10 @@ Patch:  1275_linux-5.4.276.patch
 From:   https://www.kernel.org
 Desc:   Linux 5.4.276
 
+Patch:  1276_linux-5.4.277.patch
+From:   https://www.kernel.org
+Desc:   Linux 5.4.277
+
 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/1276_linux-5.4.277.patch b/1276_linux-5.4.277.patch
new file mode 100644
index 00000000..d06c01ba
--- /dev/null
+++ b/1276_linux-5.4.277.patch
@@ -0,0 +1,672 @@
+diff --git a/Documentation/sphinx/kernel_include.py 
b/Documentation/sphinx/kernel_include.py
+index f523aa68a36b3..cf601bd058abe 100755
+--- a/Documentation/sphinx/kernel_include.py
++++ b/Documentation/sphinx/kernel_include.py
+@@ -94,7 +94,6 @@ class KernelInclude(Include):
+         # HINT: this is the only line I had to change / commented out:
+         #path = utils.relative_path(None, path)
+ 
+-        path = nodes.reprunicode(path)
+         encoding = self.options.get(
+             'encoding', self.state.document.settings.input_encoding)
+         e_handler=self.state.document.settings.input_encoding_error_handler
+diff --git a/Makefile b/Makefile
+index b45c9b7543e51..99ea904294654 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 5
+ PATCHLEVEL = 4
+-SUBLEVEL = 276
++SUBLEVEL = 277
+ EXTRAVERSION =
+ NAME = Kleptomaniac Octopus
+ 
+diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi 
b/arch/arm64/boot/dts/qcom/msm8998.dtsi
+index 9cb7163c5714c..5c653ab907463 100644
+--- a/arch/arm64/boot/dts/qcom/msm8998.dtsi
++++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi
+@@ -872,10 +872,10 @@ pcie0: pci@1c00000 {
+                       interrupts = <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "msi";
+                       interrupt-map-mask = <0 0 0 0x7>;
+-                      interrupt-map = <0 0 0 1 &intc 0 135 
IRQ_TYPE_LEVEL_HIGH>,
+-                                      <0 0 0 2 &intc 0 136 
IRQ_TYPE_LEVEL_HIGH>,
+-                                      <0 0 0 3 &intc 0 138 
IRQ_TYPE_LEVEL_HIGH>,
+-                                      <0 0 0 4 &intc 0 139 
IRQ_TYPE_LEVEL_HIGH>;
++                      interrupt-map = <0 0 0 1 &intc 0 0 135 
IRQ_TYPE_LEVEL_HIGH>,
++                                      <0 0 0 2 &intc 0 0 136 
IRQ_TYPE_LEVEL_HIGH>,
++                                      <0 0 0 3 &intc 0 0 138 
IRQ_TYPE_LEVEL_HIGH>,
++                                      <0 0 0 4 &intc 0 0 139 
IRQ_TYPE_LEVEL_HIGH>;
+ 
+                       clocks = <&gcc GCC_PCIE_0_PIPE_CLK>,
+                                <&gcc GCC_PCIE_0_MSTR_AXI_CLK>,
+diff --git a/drivers/firmware/arm_scmi/reset.c 
b/drivers/firmware/arm_scmi/reset.c
+index 6d223f345b6c9..b45d3e9cee129 100644
+--- a/drivers/firmware/arm_scmi/reset.c
++++ b/drivers/firmware/arm_scmi/reset.c
+@@ -135,8 +135,12 @@ static int scmi_domain_reset(const struct scmi_handle 
*handle, u32 domain,
+       struct scmi_xfer *t;
+       struct scmi_msg_reset_domain_reset *dom;
+       struct scmi_reset_info *pi = handle->reset_priv;
+-      struct reset_dom_info *rdom = pi->dom_info + domain;
++      struct reset_dom_info *rdom;
+ 
++      if (domain >= pi->num_domains)
++              return -EINVAL;
++
++      rdom = pi->dom_info + domain;
+       if (rdom->async_reset)
+               flags |= ASYNCHRONOUS_RESET;
+ 
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+index 9c5cbc47edf1a..b6fc191c353a7 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c
+@@ -594,6 +594,9 @@ int amdgpu_ras_error_query(struct amdgpu_device *adev,
+       if (!obj)
+               return -EINVAL;
+ 
++      if (!info || info->head.block == AMDGPU_RAS_BLOCK_COUNT)
++              return -EINVAL;
++
+       switch (info->head.block) {
+       case AMDGPU_RAS_BLOCK__UMC:
+               if (adev->umc.funcs->query_ras_error_count)
+diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+index 469cfc74617a6..fd5f9a3a8352d 100644
+--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+@@ -1990,12 +1990,18 @@ static void umac_enable_set(struct bcmgenet_priv 
*priv, u32 mask, bool enable)
+ {
+       u32 reg;
+ 
++      spin_lock_bh(&priv->reg_lock);
+       reg = bcmgenet_umac_readl(priv, UMAC_CMD);
++      if (reg & CMD_SW_RESET) {
++              spin_unlock_bh(&priv->reg_lock);
++              return;
++      }
+       if (enable)
+               reg |= mask;
+       else
+               reg &= ~mask;
+       bcmgenet_umac_writel(priv, reg, UMAC_CMD);
++      spin_unlock_bh(&priv->reg_lock);
+ 
+       /* UniMAC stops on a packet boundary, wait for a full-size packet
+        * to be processed
+@@ -2010,11 +2016,11 @@ static void reset_umac(struct bcmgenet_priv *priv)
+       bcmgenet_rbuf_ctrl_set(priv, 0);
+       udelay(10);
+ 
+-      /* disable MAC while updating its registers */
+-      bcmgenet_umac_writel(priv, 0, UMAC_CMD);
+-
+-      /* issue soft reset with (rg)mii loopback to ensure a stable rxclk */
+-      bcmgenet_umac_writel(priv, CMD_SW_RESET | CMD_LCL_LOOP_EN, UMAC_CMD);
++      /* issue soft reset and disable MAC while updating its registers */
++      spin_lock_bh(&priv->reg_lock);
++      bcmgenet_umac_writel(priv, CMD_SW_RESET, UMAC_CMD);
++      udelay(2);
++      spin_unlock_bh(&priv->reg_lock);
+ }
+ 
+ static void bcmgenet_intr_disable(struct bcmgenet_priv *priv)
+@@ -2882,7 +2888,9 @@ static void bcmgenet_netif_start(struct net_device *dev)
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+ 
+       /* Start the network engine */
++      netif_addr_lock_bh(dev);
+       bcmgenet_set_rx_mode(dev);
++      netif_addr_unlock_bh(dev);
+       bcmgenet_enable_rx_napi(priv);
+ 
+       umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, true);
+@@ -3146,16 +3154,19 @@ static void bcmgenet_set_rx_mode(struct net_device 
*dev)
+        * 3. The number of filters needed exceeds the number filters
+        *    supported by the hardware.
+       */
++      spin_lock(&priv->reg_lock);
+       reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+       if ((dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) ||
+           (nfilter > MAX_MDF_FILTER)) {
+               reg |= CMD_PROMISC;
+               bcmgenet_umac_writel(priv, reg, UMAC_CMD);
++              spin_unlock(&priv->reg_lock);
+               bcmgenet_umac_writel(priv, 0, UMAC_MDF_CTRL);
+               return;
+       } else {
+               reg &= ~CMD_PROMISC;
+               bcmgenet_umac_writel(priv, reg, UMAC_CMD);
++              spin_unlock(&priv->reg_lock);
+       }
+ 
+       /* update MDF filter */
+@@ -3513,6 +3524,7 @@ static int bcmgenet_probe(struct platform_device *pdev)
+               goto err;
+       }
+ 
++      spin_lock_init(&priv->reg_lock);
+       spin_lock_init(&priv->lock);
+ 
+       SET_NETDEV_DEV(dev, &pdev->dev);
+diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h 
b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+index 29bf256d13f67..9efc503a9c8b2 100644
+--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+@@ -608,6 +608,8 @@ struct bcmgenet_rx_ring {
+ /* device context */
+ struct bcmgenet_priv {
+       void __iomem *base;
++      /* reg_lock: lock to serialize access to shared registers */
++      spinlock_t reg_lock;
+       enum bcmgenet_version version;
+       struct net_device *dev;
+ 
+diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c 
b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+index a2da09da4907b..973275d116b61 100644
+--- a/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
++++ b/drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
+@@ -132,10 +132,16 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv 
*priv,
+               return -EINVAL;
+       }
+ 
+-      /* disable RX */
++      /* Can't suspend with WoL if MAC is still in reset */
++      spin_lock_bh(&priv->reg_lock);
+       reg = bcmgenet_umac_readl(priv, UMAC_CMD);
++      if (reg & CMD_SW_RESET)
++              reg &= ~CMD_SW_RESET;
++
++      /* disable RX */
+       reg &= ~CMD_RX_EN;
+       bcmgenet_umac_writel(priv, reg, UMAC_CMD);
++      spin_unlock_bh(&priv->reg_lock);
+       mdelay(10);
+ 
+       reg = bcmgenet_umac_readl(priv, UMAC_MPD_CTRL);
+@@ -159,6 +165,7 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
+                 retries);
+ 
+       /* Enable CRC forward */
++      spin_lock_bh(&priv->reg_lock);
+       reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+       priv->crc_fwd_en = 1;
+       reg |= CMD_CRC_FWD;
+@@ -166,6 +173,7 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
+       /* Receiver must be enabled for WOL MP detection */
+       reg |= CMD_RX_EN;
+       bcmgenet_umac_writel(priv, reg, UMAC_CMD);
++      spin_unlock_bh(&priv->reg_lock);
+ 
+       return 0;
+ }
+@@ -187,8 +195,10 @@ void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
+       bcmgenet_umac_writel(priv, reg, UMAC_MPD_CTRL);
+ 
+       /* Disable CRC Forward */
++      spin_lock_bh(&priv->reg_lock);
+       reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+       reg &= ~CMD_CRC_FWD;
+       bcmgenet_umac_writel(priv, reg, UMAC_CMD);
++      spin_unlock_bh(&priv->reg_lock);
+       priv->crc_fwd_en = 0;
+ }
+diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c 
b/drivers/net/ethernet/broadcom/genet/bcmmii.c
+index 026f00ccaa0cd..bd532e5b9f73b 100644
+--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
++++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
+@@ -91,12 +91,20 @@ void bcmgenet_mii_setup(struct net_device *dev)
+               reg |= RGMII_LINK;
+               bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
+ 
++              spin_lock_bh(&priv->reg_lock);
+               reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+               reg &= ~((CMD_SPEED_MASK << CMD_SPEED_SHIFT) |
+                              CMD_HD_EN |
+                              CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE);
+               reg |= cmd_bits;
++              if (reg & CMD_SW_RESET) {
++                      reg &= ~CMD_SW_RESET;
++                      bcmgenet_umac_writel(priv, reg, UMAC_CMD);
++                      udelay(2);
++                      reg |= CMD_TX_EN | CMD_RX_EN;
++              }
+               bcmgenet_umac_writel(priv, reg, UMAC_CMD);
++              spin_unlock_bh(&priv->reg_lock);
+ 
+               priv->eee.eee_active = phy_init_eee(phydev, 0) >= 0;
+               bcmgenet_eee_enable_set(dev,
+@@ -187,38 +195,8 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
+       const char *phy_name = NULL;
+       u32 id_mode_dis = 0;
+       u32 port_ctrl;
+-      int bmcr = -1;
+-      int ret;
+       u32 reg;
+ 
+-      /* MAC clocking workaround during reset of umac state machines */
+-      reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+-      if (reg & CMD_SW_RESET) {
+-              /* An MII PHY must be isolated to prevent TXC contention */
+-              if (priv->phy_interface == PHY_INTERFACE_MODE_MII) {
+-                      ret = phy_read(phydev, MII_BMCR);
+-                      if (ret >= 0) {
+-                              bmcr = ret;
+-                              ret = phy_write(phydev, MII_BMCR,
+-                                              bmcr | BMCR_ISOLATE);
+-                      }
+-                      if (ret) {
+-                              netdev_err(dev, "failed to isolate PHY\n");
+-                              return ret;
+-                      }
+-              }
+-              /* Switch MAC clocking to RGMII generated clock */
+-              bcmgenet_sys_writel(priv, PORT_MODE_EXT_GPHY, SYS_PORT_CTRL);
+-              /* Ensure 5 clks with Rx disabled
+-               * followed by 5 clks with Reset asserted
+-               */
+-              udelay(4);
+-              reg &= ~(CMD_SW_RESET | CMD_LCL_LOOP_EN);
+-              bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+-              /* Ensure 5 more clocks before Rx is enabled */
+-              udelay(2);
+-      }
+-
+       priv->ext_phy = !priv->internal_phy &&
+                       (priv->phy_interface != PHY_INTERFACE_MODE_MOCA);
+ 
+@@ -250,9 +228,6 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
+               phy_set_max_speed(phydev, SPEED_100);
+               bcmgenet_sys_writel(priv,
+                                   PORT_MODE_EXT_EPHY, SYS_PORT_CTRL);
+-              /* Restore the MII PHY after isolation */
+-              if (bmcr >= 0)
+-                      phy_write(phydev, MII_BMCR, bmcr);
+               break;
+ 
+       case PHY_INTERFACE_MODE_REVMII:
+@@ -296,6 +271,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
+        * block for the interface to work
+        */
+       if (priv->ext_phy) {
++              mutex_lock(&phydev->lock);
+               reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
+               reg |= id_mode_dis;
+               if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv))
+@@ -303,6 +279,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
+               else
+                       reg |= RGMII_MODE_EN;
+               bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
++              mutex_unlock(&phydev->lock);
+       }
+ 
+       if (init)
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index 3947b7064bead..44802e5017945 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -203,6 +203,7 @@ static int pinctrl_register_one_pin(struct pinctrl_dev 
*pctldev,
+                                   const struct pinctrl_pin_desc *pin)
+ {
+       struct pin_desc *pindesc;
++      int error;
+ 
+       pindesc = pin_desc_get(pctldev, pin->number);
+       if (pindesc) {
+@@ -224,18 +225,25 @@ static int pinctrl_register_one_pin(struct pinctrl_dev 
*pctldev,
+       } else {
+               pindesc->name = kasprintf(GFP_KERNEL, "PIN%u", pin->number);
+               if (!pindesc->name) {
+-                      kfree(pindesc);
+-                      return -ENOMEM;
++                      error = -ENOMEM;
++                      goto failed;
+               }
+               pindesc->dynamic_name = true;
+       }
+ 
+       pindesc->drv_data = pin->drv_data;
+ 
+-      radix_tree_insert(&pctldev->pin_desc_tree, pin->number, pindesc);
++      error = radix_tree_insert(&pctldev->pin_desc_tree, pin->number, 
pindesc);
++      if (error)
++              goto failed;
++
+       pr_debug("registered pin %d (%s) on %s\n",
+                pin->number, pindesc->name, pctldev->desc->name);
+       return 0;
++
++failed:
++      kfree(pindesc);
++      return error;
+ }
+ 
+ static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
+diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
+index 6d4792ec9e5fa..2df77f894746d 100644
+--- a/drivers/tty/serial/kgdboc.c
++++ b/drivers/tty/serial/kgdboc.c
+@@ -19,6 +19,7 @@
+ #include <linux/console.h>
+ #include <linux/vt_kern.h>
+ #include <linux/input.h>
++#include <linux/irq_work.h>
+ #include <linux/module.h>
+ #include <linux/platform_device.h>
+ 
+@@ -42,6 +43,25 @@ static int                  kgdb_tty_line;
+ 
+ static struct platform_device *kgdboc_pdev;
+ 
++/*
++ * When we leave the debug trap handler we need to reset the keyboard status
++ * (since the original keyboard state gets partially clobbered by kdb use of
++ * the keyboard).
++ *
++ * The path to deliver the reset is somewhat circuitous.
++ *
++ * To deliver the reset we register an input handler, reset the keyboard and
++ * then deregister the input handler. However, to get this done right, we do
++ * have to carefully manage the calling context because we can only register
++ * input handlers from task context.
++ *
++ * In particular we need to trigger the action from the debug trap handler 
with
++ * all its NMI and/or NMI-like oddities. To solve this the kgdboc trap exit 
code
++ * (the "post_exception" callback) uses irq_work_queue(), which is NMI-safe, 
to
++ * schedule a callback from a hardirq context. From there we have to defer the
++ * work again, this time using schedule_work(), to get a callback using the
++ * system workqueue, which runs in task context.
++ */
+ #ifdef CONFIG_KDB_KEYBOARD
+ static int kgdboc_reset_connect(struct input_handler *handler,
+                               struct input_dev *dev,
+@@ -93,10 +113,17 @@ static void kgdboc_restore_input_helper(struct 
work_struct *dummy)
+ 
+ static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper);
+ 
++static void kgdboc_queue_restore_input_helper(struct irq_work *unused)
++{
++      schedule_work(&kgdboc_restore_input_work);
++}
++
++static DEFINE_IRQ_WORK(kgdboc_restore_input_irq_work, 
kgdboc_queue_restore_input_helper);
++
+ static void kgdboc_restore_input(void)
+ {
+       if (likely(system_state == SYSTEM_RUNNING))
+-              schedule_work(&kgdboc_restore_input_work);
++              irq_work_queue(&kgdboc_restore_input_irq_work);
+ }
+ 
+ static int kgdboc_register_kbd(char **cptr)
+@@ -127,6 +154,7 @@ static void kgdboc_unregister_kbd(void)
+                       i--;
+               }
+       }
++      irq_work_sync(&kgdboc_restore_input_irq_work);
+       flush_work(&kgdboc_restore_input_work);
+ }
+ #else /* ! CONFIG_KDB_KEYBOARD */
+diff --git a/drivers/usb/typec/ucsi/displayport.c 
b/drivers/usb/typec/ucsi/displayport.c
+index 166c2aabb512b..f67c5a3041559 100644
+--- a/drivers/usb/typec/ucsi/displayport.c
++++ b/drivers/usb/typec/ucsi/displayport.c
+@@ -251,8 +251,6 @@ static void ucsi_displayport_work(struct work_struct *work)
+       struct ucsi_dp *dp = container_of(work, struct ucsi_dp, work);
+       int ret;
+ 
+-      mutex_lock(&dp->con->lock);
+-
+       ret = typec_altmode_vdm(dp->alt, dp->header,
+                               dp->vdo_data, dp->vdo_size);
+       if (ret)
+@@ -261,8 +259,6 @@ static void ucsi_displayport_work(struct work_struct *work)
+       dp->vdo_data = NULL;
+       dp->vdo_size = 0;
+       dp->header = 0;
+-
+-      mutex_unlock(&dp->con->lock);
+ }
+ 
+ void ucsi_displayport_remove_partner(struct typec_altmode *alt)
+diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
+index d7014b2b28d6a..10cc12ad2a2bd 100644
+--- a/fs/btrfs/volumes.c
++++ b/fs/btrfs/volumes.c
+@@ -3277,6 +3277,7 @@ static int btrfs_relocate_sys_chunks(struct 
btrfs_fs_info *fs_info)
+                        * alignment and size).
+                        */
+                       ret = -EUCLEAN;
++                      mutex_unlock(&fs_info->delete_unused_bgs_mutex);
+                       goto error;
+               }
+ 
+diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
+index 5fea15a5f3419..b2e45e168548b 100644
+--- a/fs/cifs/smb2ops.c
++++ b/fs/cifs/smb2ops.c
+@@ -787,9 +787,11 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon,
+       /* BB TBD check to see if oplock level check can be removed below */
+       if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
+               kref_get(&tcon->crfid.refcount);
+-              smb2_parse_contexts(server, o_rsp,
++              rc = smb2_parse_contexts(server, rsp_iov,
+                               &oparms.fid->epoch,
+                               oparms.fid->lease_key, &oplock, NULL);
++              if (rc)
++                      goto oshr_exit;
+       } else
+               goto oshr_exit;
+ 
+diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
+index da1a1b531ca5e..667528132b692 100644
+--- a/fs/cifs/smb2pdu.c
++++ b/fs/cifs/smb2pdu.c
+@@ -1929,48 +1929,73 @@ parse_query_id_ctxt(struct create_context *cc, struct 
smb2_file_all_info *buf)
+       buf->IndexNumber = pdisk_id->DiskFileId;
+ }
+ 
+-void
+-smb2_parse_contexts(struct TCP_Server_Info *server,
+-                     struct smb2_create_rsp *rsp,
+-                     unsigned int *epoch, char *lease_key, __u8 *oplock,
+-                     struct smb2_file_all_info *buf)
++int smb2_parse_contexts(struct TCP_Server_Info *server,
++                      struct kvec *rsp_iov,
++                      unsigned int *epoch,
++                      char *lease_key, __u8 *oplock,
++                      struct smb2_file_all_info *buf)
+ {
+-      char *data_offset;
++      struct smb2_create_rsp *rsp = rsp_iov->iov_base;
+       struct create_context *cc;
+-      unsigned int next;
+-      unsigned int remaining;
++      size_t rem, off, len;
++      size_t doff, dlen;
++      size_t noff, nlen;
+       char *name;
+ 
+       *oplock = 0;
+-      data_offset = (char *)rsp + le32_to_cpu(rsp->CreateContextsOffset);
+-      remaining = le32_to_cpu(rsp->CreateContextsLength);
+-      cc = (struct create_context *)data_offset;
++
++      off = le32_to_cpu(rsp->CreateContextsOffset);
++      rem = le32_to_cpu(rsp->CreateContextsLength);
++      if (check_add_overflow(off, rem, &len) || len > rsp_iov->iov_len)
++              return -EINVAL;
++      cc = (struct create_context *)((u8 *)rsp + off);
+ 
+       /* Initialize inode number to 0 in case no valid data in qfid context */
+       if (buf)
+               buf->IndexNumber = 0;
+ 
+-      while (remaining >= sizeof(struct create_context)) {
+-              name = le16_to_cpu(cc->NameOffset) + (char *)cc;
+-              if (le16_to_cpu(cc->NameLength) == 4 &&
+-                  strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4) == 0)
+-                      *oplock = server->ops->parse_lease_buf(cc, epoch,
+-                                                         lease_key);
+-              else if (buf && (le16_to_cpu(cc->NameLength) == 4) &&
+-                  strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4) == 0)
+-                      parse_query_id_ctxt(cc, buf);
+-
+-              next = le32_to_cpu(cc->Next);
+-              if (!next)
++      while (rem >= sizeof(*cc)) {
++              doff = le16_to_cpu(cc->DataOffset);
++              dlen = le32_to_cpu(cc->DataLength);
++              if (check_add_overflow(doff, dlen, &len) || len > rem)
++                      return -EINVAL;
++
++              noff = le16_to_cpu(cc->NameOffset);
++              nlen = le16_to_cpu(cc->NameLength);
++              if (noff + nlen >= doff)
++                      return -EINVAL;
++
++              name = (char *)cc + noff;
++              switch (nlen) {
++              case 4:
++                      if (!strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4)) {
++                              *oplock = server->ops->parse_lease_buf(cc, 
epoch,
++                                                                     
lease_key);
++                      } else if (buf &&
++                                 !strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 
4)) {
++                              parse_query_id_ctxt(cc, buf);
++                      }
++                      break;
++              default:
++                      cifs_dbg(FYI, "%s: unhandled context (nlen=%zu 
dlen=%zu)\n",
++                               __func__, nlen, dlen);
++                      if (IS_ENABLED(CONFIG_CIFS_DEBUG2))
++                              cifs_dump_mem("context data: ", cc, dlen);
++                      break;
++              }
++
++              off = le32_to_cpu(cc->Next);
++              if (!off)
+                       break;
+-              remaining -= next;
+-              cc = (struct create_context *)((char *)cc + next);
++              if (check_sub_overflow(rem, off, &rem))
++                      return -EINVAL;
++              cc = (struct create_context *)((u8 *)cc + off);
+       }
+ 
+       if (rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE)
+               *oplock = rsp->OplockLevel;
+ 
+-      return;
++      return 0;
+ }
+ 
+ static int
+@@ -2680,8 +2705,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms 
*oparms, __le16 *path,
+       }
+ 
+ 
+-      smb2_parse_contexts(server, rsp, &oparms->fid->epoch,
+-                          oparms->fid->lease_key, oplock, buf);
++      rc = smb2_parse_contexts(server, &rsp_iov, &oparms->fid->epoch,
++                               oparms->fid->lease_key, oplock, buf);
+ creat_exit:
+       SMB2_open_free(&rqst);
+       free_rsp_buf(resp_buftype, rsp);
+diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
+index 4d4c0faa3d8a3..2f08f7f13ced7 100644
+--- a/fs/cifs/smb2proto.h
++++ b/fs/cifs/smb2proto.h
+@@ -238,10 +238,12 @@ extern int smb3_validate_negotiate(const unsigned int, 
struct cifs_tcon *);
+ 
+ extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
+                                       enum securityEnum);
+-extern void smb2_parse_contexts(struct TCP_Server_Info *server,
+-                              struct smb2_create_rsp *rsp,
+-                              unsigned int *epoch, char *lease_key,
+-                              __u8 *oplock, struct smb2_file_all_info *buf);
++int smb2_parse_contexts(struct TCP_Server_Info *server,
++                      struct kvec *rsp_iov,
++                      unsigned int *epoch,
++                      char *lease_key, __u8 *oplock,
++                      struct smb2_file_all_info *buf);
++
+ extern int smb3_encryption_required(const struct cifs_tcon *tcon);
+ extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
+                            struct kvec *iov, unsigned int min_buf_size);
+diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
+index 98e1b1ddb4ec7..90b12c7c0f20a 100644
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -409,7 +409,7 @@ static int ext4_valid_extent_entries(struct inode *inode,
+ {
+       unsigned short entries;
+       ext4_lblk_t lblock = 0;
+-      ext4_lblk_t prev = 0;
++      ext4_lblk_t cur = 0;
+ 
+       if (eh->eh_entries == 0)
+               return 1;
+@@ -435,12 +435,12 @@ static int ext4_valid_extent_entries(struct inode *inode,
+ 
+                       /* Check for overlapping extents */
+                       lblock = le32_to_cpu(ext->ee_block);
+-                      if ((lblock <= prev) && prev) {
++                      if (lblock < cur) {
+                               pblock = ext4_ext_pblock(ext);
+                               es->s_last_error_block = cpu_to_le64(pblock);
+                               return 0;
+                       }
+-                      prev = lblock + ext4_ext_get_actual_len(ext) - 1;
++                      cur = lblock + ext4_ext_get_actual_len(ext);
+                       ext++;
+                       entries--;
+               }
+@@ -460,13 +460,13 @@ static int ext4_valid_extent_entries(struct inode *inode,
+ 
+                       /* Check for overlapping index extents */
+                       lblock = le32_to_cpu(ext_idx->ei_block);
+-                      if ((lblock <= prev) && prev) {
++                      if (lblock < cur) {
+                               *pblk = ext4_idx_pblock(ext_idx);
+                               return 0;
+                       }
+                       ext_idx++;
+                       entries--;
+-                      prev = lblock;
++                      cur = lblock + 1;
+               }
+       }
+       return 1;
+diff --git a/tools/testing/selftests/vm/map_hugetlb.c 
b/tools/testing/selftests/vm/map_hugetlb.c
+index c65c55b7a789f..312889edb84ab 100644
+--- a/tools/testing/selftests/vm/map_hugetlb.c
++++ b/tools/testing/selftests/vm/map_hugetlb.c
+@@ -15,7 +15,6 @@
+ #include <unistd.h>
+ #include <sys/mman.h>
+ #include <fcntl.h>
+-#include "vm_util.h"
+ 
+ #define LENGTH (256UL*1024*1024)
+ #define PROTECTION (PROT_READ | PROT_WRITE)
+@@ -71,16 +70,10 @@ int main(int argc, char **argv)
+ {
+       void *addr;
+       int ret;
+-      size_t hugepage_size;
+       size_t length = LENGTH;
+       int flags = FLAGS;
+       int shift = 0;
+ 
+-      hugepage_size = default_huge_page_size();
+-      /* munmap with fail if the length is not page aligned */
+-      if (hugepage_size > length)
+-              length = hugepage_size;
+-
+       if (argc > 1)
+               length = atol(argv[1]) << 20;
+       if (argc > 2) {

Reply via email to