From 49400b701eca849c1b53717b1f5d779a8d066ec0 Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Thu, 18 Sep 2025 22:27:27 +0800 Subject: [PATCH 001/443] dmaengine: mmp_pdma: fix DMA mask handling The driver's existing logic for setting the DMA mask for "marvell,pdma-1.0" was flawed. It incorrectly relied on pdev->dev->coherent_dma_mask instead of declaring the hardware's fixed addressing capability. A cleaner and more correct approach is to define the mask directly based on the hardware limitations. The MMP/PXA PDMA controller is a 32-bit DMA engine. This is supported by datasheets and various dtsi files for PXA25x, PXA27x, PXA3xx, and MMP2, all of which are 32-bit systems. This patch simplifies the driver's logic by replacing the 'u64 dma_mask' field with a simpler 'u32 dma_width' to store the addressing capability in bits. The complex if/else block in probe() is then replaced with a single, clear call to dma_set_mask_and_coherent(). This sets a fixed 32-bit DMA mask for "marvell,pdma-1.0" and a 64-bit mask for "spacemit,k1-pdma," matching each device's hardware capabilities. Finally, this change also works around a specific build error encountered with clang-20 on x86_64 allyesconfig. The shift-count-overflow error is caused by a known clang compiler issue where the DMA_BIT_MASK(n) macro's ternary operator is not correctly evaluated in static initializers. By moving the macro's evaluation into the probe() function, the driver avoids this compiler bug. Fixes: 5cfe585d8624 ("dmaengine: mmp_pdma: Add SpacemiT K1 PDMA support with 64-bit addressing") Reported-by: Naresh Kamboju Closes: https://lore.kernel.org/lkml/CA+G9fYsPcMfW-e_0_TRqu4cnwqOqYF3aJOeKUYk6Z4qRStdFvg@mail.gmail.com Suggested-by: Arnd Bergmann Signed-off-by: Guodong Xu Reviewed-by: Arnd Bergmann Tested-by: Nathan Chancellor # build Tested-by: Naresh Kamboju Signed-off-by: Vinod Koul --- drivers/dma/mmp_pdma.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index d07229a74886..86661eb3cde1 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -152,8 +152,8 @@ struct mmp_pdma_phy { * * Controller Configuration: * @run_bits: Control bits in DCSR register for channel start/stop - * @dma_mask: DMA addressing capability of controller. 0 to use OF/platform - * settings, or explicit mask like DMA_BIT_MASK(32/64) + * @dma_width: DMA addressing width in bits (32 or 64). Determines the + * DMA mask capability of the controller hardware. */ struct mmp_pdma_ops { /* Hardware Register Operations */ @@ -173,7 +173,7 @@ struct mmp_pdma_ops { /* Controller Configuration */ u32 run_bits; - u64 dma_mask; + u32 dma_width; }; struct mmp_pdma_device { @@ -1172,7 +1172,7 @@ static const struct mmp_pdma_ops marvell_pdma_v1_ops = { .get_desc_src_addr = get_desc_src_addr_32, .get_desc_dst_addr = get_desc_dst_addr_32, .run_bits = (DCSR_RUN), - .dma_mask = 0, /* let OF/platform set DMA mask */ + .dma_width = 32, }; static const struct mmp_pdma_ops spacemit_k1_pdma_ops = { @@ -1185,7 +1185,7 @@ static const struct mmp_pdma_ops spacemit_k1_pdma_ops = { .get_desc_src_addr = get_desc_src_addr_64, .get_desc_dst_addr = get_desc_dst_addr_64, .run_bits = (DCSR_RUN | DCSR_LPAEEN), - .dma_mask = DMA_BIT_MASK(64), /* force 64-bit DMA addr capability */ + .dma_width = 64, }; static const struct of_device_id mmp_pdma_dt_ids[] = { @@ -1314,13 +1314,9 @@ static int mmp_pdma_probe(struct platform_device *op) pdev->device.directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM); pdev->device.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR; - /* Set DMA mask based on ops->dma_mask, or OF/platform */ - if (pdev->ops->dma_mask) - dma_set_mask(pdev->dev, pdev->ops->dma_mask); - else if (pdev->dev->coherent_dma_mask) - dma_set_mask(pdev->dev, pdev->dev->coherent_dma_mask); - else - dma_set_mask(pdev->dev, DMA_BIT_MASK(64)); + /* Set DMA mask based on controller hardware capabilities */ + dma_set_mask_and_coherent(pdev->dev, + DMA_BIT_MASK(pdev->ops->dma_width)); ret = dma_async_device_register(&pdev->device); if (ret) { From c7d436a6c1a274c1ac28d5fb3b8eb8f03b6d0e10 Mon Sep 17 00:00:00 2001 From: Anthony Brandon Date: Mon, 13 Oct 2025 17:48:49 +0200 Subject: [PATCH 002/443] dmaengine: xilinx: xdma: Fix regmap max_register The max_register field is assigned the size of the register memory region instead of the offset of the last register. The result is that reading from the regmap via debugfs can cause a segmentation fault: tail /sys/kernel/debug/regmap/xdma.1.auto/registers Unable to handle kernel paging request at virtual address ffff800082f70000 Mem abort info: ESR = 0x0000000096000007 EC = 0x25: DABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 FSC = 0x07: level 3 translation fault [...] Call trace: regmap_mmio_read32le+0x10/0x30 _regmap_bus_reg_read+0x74/0xc0 _regmap_read+0x68/0x198 regmap_read+0x54/0x88 regmap_read_debugfs+0x140/0x380 regmap_map_read_file+0x30/0x48 full_proxy_read+0x68/0xc8 vfs_read+0xcc/0x310 ksys_read+0x7c/0x120 __arm64_sys_read+0x24/0x40 invoke_syscall.constprop.0+0x64/0x108 do_el0_svc+0xb0/0xd8 el0_svc+0x38/0x130 el0t_64_sync_handler+0x120/0x138 el0t_64_sync+0x194/0x198 Code: aa1e03e9 d503201f f9400000 8b214000 (b9400000) ---[ end trace 0000000000000000 ]--- note: tail[1217] exited with irqs disabled note: tail[1217] exited with preempt_count 1 Segmentation fault Fixes: 17ce252266c7 ("dmaengine: xilinx: xdma: Add xilinx xdma driver") Reviewed-by: Lizhi Hou Reviewed-by: Radhey Shyam Pandey Reviewed-by: Alexander Stein Signed-off-by: Anthony Brandon Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xdma-regs.h | 1 + drivers/dma/xilinx/xdma.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dma/xilinx/xdma-regs.h b/drivers/dma/xilinx/xdma-regs.h index 6ad08878e938..70bca92621aa 100644 --- a/drivers/dma/xilinx/xdma-regs.h +++ b/drivers/dma/xilinx/xdma-regs.h @@ -9,6 +9,7 @@ /* The length of register space exposed to host */ #define XDMA_REG_SPACE_LEN 65536 +#define XDMA_MAX_REG_OFFSET (XDMA_REG_SPACE_LEN - 4) /* * maximum number of DMA channels for each direction: diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c index 0d88b1a670e1..5ecf8223c112 100644 --- a/drivers/dma/xilinx/xdma.c +++ b/drivers/dma/xilinx/xdma.c @@ -38,7 +38,7 @@ static const struct regmap_config xdma_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .max_register = XDMA_REG_SPACE_LEN, + .max_register = XDMA_MAX_REG_OFFSET, }; /** From b9074b2d7a230b6e28caa23165e9d8bc0677d333 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:43 +0100 Subject: [PATCH 003/443] dmaengine: at_hdmac: fix device leak on of_dma_xlate() Make sure to drop the reference taken when looking up the DMA platform device during of_dma_xlate() when releasing channel resources. Note that commit 3832b78b3ec2 ("dmaengine: at_hdmac: add missing put_device() call in at_dma_xlate()") fixed the leak in a couple of error paths but the reference is still leaking on successful allocation. Fixes: bbe89c8e3d59 ("at_hdmac: move to generic DMA binding") Fixes: 3832b78b3ec2 ("dmaengine: at_hdmac: add missing put_device() call in at_dma_xlate()") Cc: stable@vger.kernel.org # 3.10: 3832b78b3ec2 Cc: Yu Kuai Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251117161258.10679-2-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 7d226453961f..22bb604a3f97 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -1765,6 +1765,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan) static void atc_free_chan_resources(struct dma_chan *chan) { struct at_dma_chan *atchan = to_at_dma_chan(chan); + struct at_dma_slave *atslave; BUG_ON(atc_chan_is_enabled(atchan)); @@ -1774,8 +1775,12 @@ static void atc_free_chan_resources(struct dma_chan *chan) /* * Free atslave allocated in at_dma_xlate() */ - kfree(chan->private); - chan->private = NULL; + atslave = chan->private; + if (atslave) { + put_device(atslave->dma_dev); + kfree(atslave); + chan->private = NULL; + } dev_vdbg(chan2dev(chan), "free_chan_resources: done\n"); } From 7c3a46ebf15a9796b763a54272407fdbf945bed8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:45 +0100 Subject: [PATCH 004/443] dmaengine: bcm-sba-raid: fix device leak on probe Make sure to drop the reference taken when looking up the mailbox device during probe on probe failures and on driver unbind. Fixes: 743e1c8ffe4e ("dmaengine: Add Broadcom SBA RAID driver") Cc: stable@vger.kernel.org # 4.13 Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251117161258.10679-4-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/bcm-sba-raid.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/dma/bcm-sba-raid.c b/drivers/dma/bcm-sba-raid.c index 7f0e76439ce5..ed037fa883f6 100644 --- a/drivers/dma/bcm-sba-raid.c +++ b/drivers/dma/bcm-sba-raid.c @@ -1699,7 +1699,7 @@ static int sba_probe(struct platform_device *pdev) /* Prealloc channel resource */ ret = sba_prealloc_channel_resources(sba); if (ret) - goto fail_free_mchan; + goto fail_put_mbox; /* Check availability of debugfs */ if (!debugfs_initialized()) @@ -1729,6 +1729,8 @@ skip_debugfs: fail_free_resources: debugfs_remove_recursive(sba->root); sba_freeup_channel_resources(sba); +fail_put_mbox: + put_device(sba->mbox_dev); fail_free_mchan: mbox_free_channel(sba->mchan); return ret; @@ -1744,6 +1746,8 @@ static void sba_remove(struct platform_device *pdev) sba_freeup_channel_resources(sba); + put_device(sba->mbox_dev); + mbox_free_channel(sba->mchan); } From 7bb7d696e0361bbfc1411462c784998cca0afcbb Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:46 +0100 Subject: [PATCH 005/443] dmaengine: cv1800b-dmamux: fix device leak on route allocation Make sure to drop the reference taken when looking up the DMA mux platform device during route allocation. Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference. Fixes: db7d07b5add4 ("dmaengine: add driver for Sophgo CV18XX/SG200X dmamux") Cc: stable@vger.kernel.org # 6.17 Cc: Inochi Amaoto Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251117161258.10679-5-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/cv1800b-dmamux.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/dma/cv1800b-dmamux.c b/drivers/dma/cv1800b-dmamux.c index e900d6595617..f7a952fcbc7d 100644 --- a/drivers/dma/cv1800b-dmamux.c +++ b/drivers/dma/cv1800b-dmamux.c @@ -102,11 +102,11 @@ static void *cv1800_dmamux_route_allocate(struct of_phandle_args *dma_spec, struct llist_node *node; unsigned long flags; unsigned int chid, devid, cpuid; - int ret; + int ret = -EINVAL; if (dma_spec->args_count != DMAMUX_NCELLS) { dev_err(&pdev->dev, "invalid number of dma mux args\n"); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } devid = dma_spec->args[0]; @@ -115,18 +115,18 @@ static void *cv1800_dmamux_route_allocate(struct of_phandle_args *dma_spec, if (devid > MAX_DMA_MAPPING_ID) { dev_err(&pdev->dev, "invalid device id: %u\n", devid); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } if (cpuid > MAX_DMA_CPU_ID) { dev_err(&pdev->dev, "invalid cpu id: %u\n", cpuid); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0); if (!dma_spec->np) { dev_err(&pdev->dev, "can't get dma master\n"); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } spin_lock_irqsave(&dmamux->lock, flags); @@ -136,8 +136,6 @@ static void *cv1800_dmamux_route_allocate(struct of_phandle_args *dma_spec, if (map->peripheral == devid && map->cpu == cpuid) goto found; } - - ret = -EINVAL; goto failed; } else { node = llist_del_first(&dmamux->free_maps); @@ -171,12 +169,17 @@ found: dev_dbg(&pdev->dev, "register channel %u for req %u (cpu %u)\n", chid, devid, cpuid); + put_device(&pdev->dev); + return map; failed: spin_unlock_irqrestore(&dmamux->lock, flags); of_node_put(dma_spec->np); dev_err(&pdev->dev, "errno %d\n", ret); +err_put_pdev: + put_device(&pdev->dev); + return ERR_PTR(ret); } From ec25e60f9f95464aa11411db31d0906b3fb7b9f2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:47 +0100 Subject: [PATCH 006/443] dmaengine: dw: dmamux: fix OF node leak on route allocation failure Make sure to drop the reference taken to the DMA master OF node also on late route allocation failures. Fixes: 134d9c52fca2 ("dmaengine: dw: dmamux: Introduce RZN1 DMA router support") Cc: stable@vger.kernel.org # 5.19 Cc: Miquel Raynal Signed-off-by: Johan Hovold Reviewed-by: Miquel Raynal Link: https://patch.msgid.link/20251117161258.10679-6-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/dw/rzn1-dmamux.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/dma/dw/rzn1-dmamux.c b/drivers/dma/dw/rzn1-dmamux.c index deadf135681b..cbec277af4dd 100644 --- a/drivers/dma/dw/rzn1-dmamux.c +++ b/drivers/dma/dw/rzn1-dmamux.c @@ -90,7 +90,7 @@ static void *rzn1_dmamux_route_allocate(struct of_phandle_args *dma_spec, if (test_and_set_bit(map->req_idx, dmamux->used_chans)) { ret = -EBUSY; - goto free_map; + goto put_dma_spec_np; } mask = BIT(map->req_idx); @@ -103,6 +103,8 @@ static void *rzn1_dmamux_route_allocate(struct of_phandle_args *dma_spec, clear_bitmap: clear_bit(map->req_idx, dmamux->used_chans); +put_dma_spec_np: + of_node_put(dma_spec->np); free_map: kfree(map); put_device: From 799900f01792cf8b525a44764f065f83fcafd468 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:48 +0100 Subject: [PATCH 007/443] dmaengine: idxd: fix device leaks on compat bind and unbind Make sure to drop the reference taken when looking up the idxd device as part of the compat bind and unbind sysfs interface. Fixes: 6e7f3ee97bbe ("dmaengine: idxd: move dsa_drv support to compatible mode") Cc: stable@vger.kernel.org # 5.15 Cc: Dave Jiang Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251117161258.10679-7-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/idxd/compat.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/dma/idxd/compat.c b/drivers/dma/idxd/compat.c index eff9943f1a42..95b8ef958633 100644 --- a/drivers/dma/idxd/compat.c +++ b/drivers/dma/idxd/compat.c @@ -20,11 +20,16 @@ static ssize_t unbind_store(struct device_driver *drv, const char *buf, size_t c int rc = -ENODEV; dev = bus_find_device_by_name(bus, NULL, buf); - if (dev && dev->driver) { + if (!dev) + return -ENODEV; + + if (dev->driver) { device_driver_detach(dev); rc = count; } + put_device(dev); + return rc; } static DRIVER_ATTR_IGNORE_LOCKDEP(unbind, 0200, NULL, unbind_store); @@ -38,9 +43,12 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf, size_t cou struct idxd_dev *idxd_dev; dev = bus_find_device_by_name(bus, NULL, buf); - if (!dev || dev->driver || drv != &dsa_drv.drv) + if (!dev) return -ENODEV; + if (dev->driver || drv != &dsa_drv.drv) + goto err_put_dev; + idxd_dev = confdev_to_idxd_dev(dev); if (is_idxd_dev(idxd_dev)) { alt_drv = driver_find("idxd", bus); @@ -53,13 +61,20 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf, size_t cou alt_drv = driver_find("user", bus); } if (!alt_drv) - return -ENODEV; + goto err_put_dev; rc = device_driver_attach(alt_drv, dev); if (rc < 0) - return rc; + goto err_put_dev; + + put_device(dev); return count; + +err_put_dev: + put_device(dev); + + return rc; } static DRIVER_ATTR_IGNORE_LOCKDEP(bind, 0200, NULL, bind_store); From d4d63059dee7e7cae0c4d9a532ed558bc90efb55 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:49 +0100 Subject: [PATCH 008/443] dmaengine: lpc18xx-dmamux: fix device leak on route allocation Make sure to drop the reference taken when looking up the DMA mux platform device during route allocation. Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference. Fixes: e5f4ae84be74 ("dmaengine: add driver for lpc18xx dmamux") Cc: stable@vger.kernel.org # 4.3 Signed-off-by: Johan Hovold Reviewed-by: Vladimir Zapolskiy Link: https://patch.msgid.link/20251117161258.10679-8-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/lpc18xx-dmamux.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/dma/lpc18xx-dmamux.c b/drivers/dma/lpc18xx-dmamux.c index 2b6436f4b193..d3ff521951b8 100644 --- a/drivers/dma/lpc18xx-dmamux.c +++ b/drivers/dma/lpc18xx-dmamux.c @@ -57,30 +57,31 @@ static void *lpc18xx_dmamux_reserve(struct of_phandle_args *dma_spec, struct lpc18xx_dmamux_data *dmamux = platform_get_drvdata(pdev); unsigned long flags; unsigned mux; + int ret = -EINVAL; if (dma_spec->args_count != 3) { dev_err(&pdev->dev, "invalid number of dma mux args\n"); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } mux = dma_spec->args[0]; if (mux >= dmamux->dma_master_requests) { dev_err(&pdev->dev, "invalid mux number: %d\n", dma_spec->args[0]); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } if (dma_spec->args[1] > LPC18XX_DMAMUX_MAX_VAL) { dev_err(&pdev->dev, "invalid dma mux value: %d\n", dma_spec->args[1]); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } /* The of_node_put() will be done in the core for the node */ dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0); if (!dma_spec->np) { dev_err(&pdev->dev, "can't get dma master\n"); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } spin_lock_irqsave(&dmamux->lock, flags); @@ -89,7 +90,8 @@ static void *lpc18xx_dmamux_reserve(struct of_phandle_args *dma_spec, dev_err(&pdev->dev, "dma request %u busy with %u.%u\n", mux, mux, dmamux->muxes[mux].value); of_node_put(dma_spec->np); - return ERR_PTR(-EBUSY); + ret = -EBUSY; + goto err_put_pdev; } dmamux->muxes[mux].busy = true; @@ -106,7 +108,14 @@ static void *lpc18xx_dmamux_reserve(struct of_phandle_args *dma_spec, dev_dbg(&pdev->dev, "mapping dmamux %u.%u to dma request %u\n", mux, dmamux->muxes[mux].value, mux); + put_device(&pdev->dev); + return &dmamux->muxes[mux]; + +err_put_pdev: + put_device(&pdev->dev); + + return ERR_PTR(ret); } static int lpc18xx_dmamux_probe(struct platform_device *pdev) From d9847e6d1d91462890ba297f7888fa598d47e76e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:50 +0100 Subject: [PATCH 009/443] dmaengine: lpc32xx-dmamux: fix device leak on route allocation Make sure to drop the reference taken when looking up the DMA mux platform device during route allocation. Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference. Fixes: 5d318b595982 ("dmaengine: Add dma router for pl08x in LPC32XX SoC") Cc: stable@vger.kernel.org # 6.12 Cc: Piotr Wojtaszczyk Signed-off-by: Johan Hovold Reviewed-by: Vladimir Zapolskiy Link: https://patch.msgid.link/20251117161258.10679-9-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/lpc32xx-dmamux.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/dma/lpc32xx-dmamux.c b/drivers/dma/lpc32xx-dmamux.c index 351d7e23e615..33be714740dd 100644 --- a/drivers/dma/lpc32xx-dmamux.c +++ b/drivers/dma/lpc32xx-dmamux.c @@ -95,11 +95,12 @@ static void *lpc32xx_dmamux_reserve(struct of_phandle_args *dma_spec, struct lpc32xx_dmamux_data *dmamux = platform_get_drvdata(pdev); unsigned long flags; struct lpc32xx_dmamux *mux = NULL; + int ret = -EINVAL; int i; if (dma_spec->args_count != 3) { dev_err(&pdev->dev, "invalid number of dma mux args\n"); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } for (i = 0; i < ARRAY_SIZE(lpc32xx_muxes); i++) { @@ -111,20 +112,20 @@ static void *lpc32xx_dmamux_reserve(struct of_phandle_args *dma_spec, if (!mux) { dev_err(&pdev->dev, "invalid mux request number: %d\n", dma_spec->args[0]); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } if (dma_spec->args[2] > 1) { dev_err(&pdev->dev, "invalid dma mux value: %d\n", dma_spec->args[1]); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } /* The of_node_put() will be done in the core for the node */ dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0); if (!dma_spec->np) { dev_err(&pdev->dev, "can't get dma master\n"); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } spin_lock_irqsave(&dmamux->lock, flags); @@ -133,7 +134,8 @@ static void *lpc32xx_dmamux_reserve(struct of_phandle_args *dma_spec, dev_err(dev, "dma request signal %d busy, routed to %s\n", mux->signal, mux->muxval ? mux->name_sel1 : mux->name_sel1); of_node_put(dma_spec->np); - return ERR_PTR(-EBUSY); + ret = -EBUSY; + goto err_put_pdev; } mux->busy = true; @@ -148,7 +150,14 @@ static void *lpc32xx_dmamux_reserve(struct of_phandle_args *dma_spec, dev_dbg(dev, "dma request signal %d routed to %s\n", mux->signal, mux->muxval ? mux->name_sel1 : mux->name_sel1); + put_device(&pdev->dev); + return mux; + +err_put_pdev: + put_device(&pdev->dev); + + return ERR_PTR(ret); } static int lpc32xx_dmamux_probe(struct platform_device *pdev) From 9fb490323997dcb6f749cd2660a17a39854600cd Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:51 +0100 Subject: [PATCH 010/443] dmaengine: sh: rz-dmac: fix device leak on probe failure Make sure to drop the reference taken when looking up the ICU device during probe also on probe failures (e.g. probe deferral). Fixes: 7de873201c44 ("dmaengine: sh: rz-dmac: Add RZ/V2H(P) support") Cc: stable@vger.kernel.org # 6.16 Cc: Fabrizio Castro Signed-off-by: Johan Hovold Reviewed-by: Fabrizio Castro Link: https://patch.msgid.link/20251117161258.10679-10-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/sh/rz-dmac.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c index 1f687b08d6b8..38137e8d80b9 100644 --- a/drivers/dma/sh/rz-dmac.c +++ b/drivers/dma/sh/rz-dmac.c @@ -854,6 +854,13 @@ static int rz_dmac_chan_probe(struct rz_dmac *dmac, return 0; } +static void rz_dmac_put_device(void *_dev) +{ + struct device *dev = _dev; + + put_device(dev); +} + static int rz_dmac_parse_of_icu(struct device *dev, struct rz_dmac *dmac) { struct device_node *np = dev->of_node; @@ -876,6 +883,10 @@ static int rz_dmac_parse_of_icu(struct device *dev, struct rz_dmac *dmac) return -ENODEV; } + ret = devm_add_action_or_reset(dev, rz_dmac_put_device, &dmac->icu.pdev->dev); + if (ret) + return ret; + dmac_index = args.args[0]; if (dmac_index > RZV2H_MAX_DMAC_INDEX) { dev_err(dev, "DMAC index %u invalid.\n", dmac_index); @@ -1055,8 +1066,6 @@ static void rz_dmac_remove(struct platform_device *pdev) reset_control_assert(dmac->rstc); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - - platform_device_put(dmac->icu.pdev); } static const struct of_device_id of_rz_dmac_match[] = { From dd6e4943889fb354efa3f700e42739da9bddb6ef Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:52 +0100 Subject: [PATCH 011/443] dmaengine: stm32: dmamux: fix device leak on route allocation Make sure to drop the reference taken when looking up the DMA mux platform device during route allocation. Note that holding a reference to a device does not prevent its driver data from going away so there is no point in keeping the reference. Fixes: df7e762db5f6 ("dmaengine: Add STM32 DMAMUX driver") Cc: stable@vger.kernel.org # 4.15 Cc: Pierre-Yves MORDRET Signed-off-by: Johan Hovold Reviewed-by: Amelie Delaunay Link: https://patch.msgid.link/20251117161258.10679-11-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/stm32/stm32-dmamux.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/dma/stm32/stm32-dmamux.c b/drivers/dma/stm32/stm32-dmamux.c index 8d77e2a7939a..791179760782 100644 --- a/drivers/dma/stm32/stm32-dmamux.c +++ b/drivers/dma/stm32/stm32-dmamux.c @@ -90,23 +90,25 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, struct stm32_dmamux_data *dmamux = platform_get_drvdata(pdev); struct stm32_dmamux *mux; u32 i, min, max; - int ret; + int ret = -EINVAL; unsigned long flags; if (dma_spec->args_count != 3) { dev_err(&pdev->dev, "invalid number of dma mux args\n"); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } if (dma_spec->args[0] > dmamux->dmamux_requests) { dev_err(&pdev->dev, "invalid mux request number: %d\n", dma_spec->args[0]); - return ERR_PTR(-EINVAL); + goto err_put_pdev; } mux = kzalloc(sizeof(*mux), GFP_KERNEL); - if (!mux) - return ERR_PTR(-ENOMEM); + if (!mux) { + ret = -ENOMEM; + goto err_put_pdev; + } spin_lock_irqsave(&dmamux->lock, flags); mux->chan_id = find_first_zero_bit(dmamux->dma_inuse, @@ -133,7 +135,6 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", i - 1); if (!dma_spec->np) { dev_err(&pdev->dev, "can't get dma master\n"); - ret = -EINVAL; goto error; } @@ -160,6 +161,8 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, dev_dbg(&pdev->dev, "Mapping DMAMUX(%u) to DMA%u(%u)\n", mux->request, mux->master, mux->chan_id); + put_device(&pdev->dev); + return mux; error: @@ -167,6 +170,9 @@ error: error_chan_id: kfree(mux); +err_put_pdev: + put_device(&pdev->dev); + return ERR_PTR(ret); } From b1b590a590af13ded598e70f0b72bc1e515787a1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:53 +0100 Subject: [PATCH 012/443] dmaengine: stm32: dmamux: fix OF node leak on route allocation failure Make sure to drop the reference taken to the DMA master OF node also on late route allocation failures. Fixes: df7e762db5f6 ("dmaengine: Add STM32 DMAMUX driver") Cc: stable@vger.kernel.org # 4.15 Cc: Pierre-Yves MORDRET Signed-off-by: Johan Hovold Reviewed-by: Amelie Delaunay Link: https://patch.msgid.link/20251117161258.10679-12-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/stm32/stm32-dmamux.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/dma/stm32/stm32-dmamux.c b/drivers/dma/stm32/stm32-dmamux.c index 791179760782..2bd218dbabbb 100644 --- a/drivers/dma/stm32/stm32-dmamux.c +++ b/drivers/dma/stm32/stm32-dmamux.c @@ -143,7 +143,7 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, ret = pm_runtime_resume_and_get(&pdev->dev); if (ret < 0) { spin_unlock_irqrestore(&dmamux->lock, flags); - goto error; + goto err_put_dma_spec_np; } spin_unlock_irqrestore(&dmamux->lock, flags); @@ -165,6 +165,8 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, return mux; +err_put_dma_spec_np: + of_node_put(dma_spec->np); error: clear_bit(mux->chan_id, dmamux->dma_inuse); From 10bf494fd77b34d0749e098c939f85abf52801d1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:54 +0100 Subject: [PATCH 013/443] dmaengine: stm32: dmamux: clean up route allocation error labels Error labels should be named after what they do (and not after wherefrom they are jumped to). Signed-off-by: Johan Hovold Reviewed-by: Amelie Delaunay Link: https://patch.msgid.link/20251117161258.10679-13-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/stm32/stm32-dmamux.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/dma/stm32/stm32-dmamux.c b/drivers/dma/stm32/stm32-dmamux.c index 2bd218dbabbb..db13498b9c9f 100644 --- a/drivers/dma/stm32/stm32-dmamux.c +++ b/drivers/dma/stm32/stm32-dmamux.c @@ -118,7 +118,7 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, spin_unlock_irqrestore(&dmamux->lock, flags); dev_err(&pdev->dev, "Run out of free DMA requests\n"); ret = -ENOMEM; - goto error_chan_id; + goto err_free_mux; } set_bit(mux->chan_id, dmamux->dma_inuse); spin_unlock_irqrestore(&dmamux->lock, flags); @@ -135,7 +135,7 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", i - 1); if (!dma_spec->np) { dev_err(&pdev->dev, "can't get dma master\n"); - goto error; + goto err_clear_inuse; } /* Set dma request */ @@ -167,10 +167,9 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec, err_put_dma_spec_np: of_node_put(dma_spec->np); -error: +err_clear_inuse: clear_bit(mux->chan_id, dmamux->dma_inuse); - -error_chan_id: +err_free_mux: kfree(mux); err_put_pdev: put_device(&pdev->dev); From dc7e44db01fc2498644e3106db3e62a9883a93d5 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:55 +0100 Subject: [PATCH 014/443] dmaengine: ti: dma-crossbar: fix device leak on dra7x route allocation Make sure to drop the reference taken when looking up the crossbar platform device during dra7x route allocation. Note that commit 615a4bfc426e ("dmaengine: ti: Add missing put_device in ti_dra7_xbar_route_allocate") fixed the leak in the error paths but the reference is still leaking on successful allocation. Fixes: a074ae38f859 ("dmaengine: Add driver for TI DMA crossbar on DRA7x") Fixes: 615a4bfc426e ("dmaengine: ti: Add missing put_device in ti_dra7_xbar_route_allocate") Cc: stable@vger.kernel.org # 4.2: 615a4bfc426e Cc: Peter Ujfalusi Cc: Miaoqian Lin Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251117161258.10679-14-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/ti/dma-crossbar.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/dma/ti/dma-crossbar.c b/drivers/dma/ti/dma-crossbar.c index 7f17ee87a6dc..e52b0e139900 100644 --- a/drivers/dma/ti/dma-crossbar.c +++ b/drivers/dma/ti/dma-crossbar.c @@ -288,6 +288,8 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec, ti_dra7_xbar_write(xbar->iomem, map->xbar_out, map->xbar_in); + put_device(&pdev->dev); + return map; } From 4fc17b1c6d2e04ad13fd6c21cfbac68043ec03f9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:56 +0100 Subject: [PATCH 015/443] dmaengine: ti: dma-crossbar: fix device leak on am335x route allocation Make sure to drop the reference taken when looking up the crossbar platform device during am335x route allocation. Fixes: 42dbdcc6bf96 ("dmaengine: ti-dma-crossbar: Add support for crossbar on AM33xx/AM43xx") Cc: stable@vger.kernel.org # 4.4 Cc: Peter Ujfalusi Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251117161258.10679-15-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/ti/dma-crossbar.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/dma/ti/dma-crossbar.c b/drivers/dma/ti/dma-crossbar.c index e52b0e139900..ff05b150ad37 100644 --- a/drivers/dma/ti/dma-crossbar.c +++ b/drivers/dma/ti/dma-crossbar.c @@ -79,34 +79,35 @@ static void *ti_am335x_xbar_route_allocate(struct of_phandle_args *dma_spec, { struct platform_device *pdev = of_find_device_by_node(ofdma->of_node); struct ti_am335x_xbar_data *xbar = platform_get_drvdata(pdev); - struct ti_am335x_xbar_map *map; + struct ti_am335x_xbar_map *map = ERR_PTR(-EINVAL); if (dma_spec->args_count != 3) - return ERR_PTR(-EINVAL); + goto out_put_pdev; if (dma_spec->args[2] >= xbar->xbar_events) { dev_err(&pdev->dev, "Invalid XBAR event number: %d\n", dma_spec->args[2]); - return ERR_PTR(-EINVAL); + goto out_put_pdev; } if (dma_spec->args[0] >= xbar->dma_requests) { dev_err(&pdev->dev, "Invalid DMA request line number: %d\n", dma_spec->args[0]); - return ERR_PTR(-EINVAL); + goto out_put_pdev; } /* The of_node_put() will be done in the core for the node */ dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0); if (!dma_spec->np) { dev_err(&pdev->dev, "Can't get DMA master\n"); - return ERR_PTR(-EINVAL); + goto out_put_pdev; } map = kzalloc(sizeof(*map), GFP_KERNEL); if (!map) { of_node_put(dma_spec->np); - return ERR_PTR(-ENOMEM); + map = ERR_PTR(-ENOMEM); + goto out_put_pdev; } map->dma_line = (u16)dma_spec->args[0]; @@ -120,6 +121,9 @@ static void *ti_am335x_xbar_route_allocate(struct of_phandle_args *dma_spec, ti_am335x_xbar_write(xbar->iomem, map->dma_line, map->mux_val); +out_put_pdev: + put_device(&pdev->dev); + return map; } From 646ff780338bd7305c9f2fdeb418fdb01623a71c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:57 +0100 Subject: [PATCH 016/443] dmaengine: ti: dma-crossbar: clean up dra7x route allocation error paths Use a common exit path to drop the cross platform device reference on errors for consistency with am335x. Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251117161258.10679-16-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/ti/dma-crossbar.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/dma/ti/dma-crossbar.c b/drivers/dma/ti/dma-crossbar.c index ff05b150ad37..e04077d542d2 100644 --- a/drivers/dma/ti/dma-crossbar.c +++ b/drivers/dma/ti/dma-crossbar.c @@ -245,28 +245,26 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec, { struct platform_device *pdev = of_find_device_by_node(ofdma->of_node); struct ti_dra7_xbar_data *xbar = platform_get_drvdata(pdev); - struct ti_dra7_xbar_map *map; + struct ti_dra7_xbar_map *map = ERR_PTR(-EINVAL); if (dma_spec->args[0] >= xbar->xbar_requests) { dev_err(&pdev->dev, "Invalid XBAR request number: %d\n", dma_spec->args[0]); - put_device(&pdev->dev); - return ERR_PTR(-EINVAL); + goto out_put_pdev; } /* The of_node_put() will be done in the core for the node */ dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0); if (!dma_spec->np) { dev_err(&pdev->dev, "Can't get DMA master\n"); - put_device(&pdev->dev); - return ERR_PTR(-EINVAL); + goto out_put_pdev; } map = kzalloc(sizeof(*map), GFP_KERNEL); if (!map) { of_node_put(dma_spec->np); - put_device(&pdev->dev); - return ERR_PTR(-ENOMEM); + map = ERR_PTR(-ENOMEM); + goto out_put_pdev; } mutex_lock(&xbar->mutex); @@ -277,8 +275,8 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec, dev_err(&pdev->dev, "Run out of free DMA requests\n"); kfree(map); of_node_put(dma_spec->np); - put_device(&pdev->dev); - return ERR_PTR(-ENOMEM); + map = ERR_PTR(-ENOMEM); + goto out_put_pdev; } set_bit(map->xbar_out, xbar->dma_inuse); mutex_unlock(&xbar->mutex); @@ -292,6 +290,7 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec, ti_dra7_xbar_write(xbar->iomem, map->xbar_out, map->xbar_in); +out_put_pdev: put_device(&pdev->dev); return map; From 430f7803b69cd5e5694e5dfc884c6628870af36e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 17 Nov 2025 17:12:58 +0100 Subject: [PATCH 017/443] dmaengine: ti: k3-udma: fix device leak on udma lookup Make sure to drop the reference taken when looking up the UDMA platform device. Note that holding a reference to a platform device does not prevent its driver data from going away so there is no point in keeping the reference after the lookup helper returns. Fixes: d70241913413 ("dmaengine: ti: k3-udma: Add glue layer for non DMAengine users") Fixes: 1438cde8fe9c ("dmaengine: ti: k3-udma: add missing put_device() call in of_xudma_dev_get()") Cc: stable@vger.kernel.org # 5.6: 1438cde8fe9c Cc: Grygorii Strashko Cc: Yu Kuai Signed-off-by: Johan Hovold Link: https://patch.msgid.link/20251117161258.10679-17-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/ti/k3-udma-private.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/ti/k3-udma-private.c b/drivers/dma/ti/k3-udma-private.c index 05228bf00033..624360423ef1 100644 --- a/drivers/dma/ti/k3-udma-private.c +++ b/drivers/dma/ti/k3-udma-private.c @@ -42,9 +42,9 @@ struct udma_dev *of_xudma_dev_get(struct device_node *np, const char *property) } ud = platform_get_drvdata(pdev); + put_device(&pdev->dev); if (!ud) { pr_debug("UDMA has not been probed\n"); - put_device(&pdev->dev); return ERR_PTR(-EPROBE_DEFER); } From 5497ffe305b2ea31ae62d4a311d7cabfb671f54a Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Mon, 24 Nov 2025 19:47:03 -0800 Subject: [PATCH 018/443] arm64: dts: rockchip: Fix voltage threshold for volume keys for Pinephone Pro Previously sometimes pressing the volume-down button would register as a volume-up button. Match the thresholds as shown in the Pinephone Pro schematic. Tests: ~ $ evtest // Mashed the volume down ~100 times with varying intensity Event: time xxx, type 1 (EV_KEY), code 114 (KEY_VOLUMEDOWN), value 1 Event: time xxx, type 1 (EV_KEY), code 114 (KEY_VOLUMEDOWN), value 0 // Mashed the volume up ~100 times with varying intensity Event: time xxx, type 1 (EV_KEY), code 115 (KEY_VOLUMEUP), value 1 Event: time xxx, type 1 (EV_KEY), code 115 (KEY_VOLUMEUP), value 0 Fixes: d3150ed53580 ("arm64: dts: rockchip: Add support for volume keys to rk3399-pinephone-pro") Cc: stable@vger.kernel.org Signed-off-by: Ondrej Jirman Signed-off-by: Rudraksha Gupta Reviewed-by: Pavel Machek Link: https://patch.msgid.link/20251124-ppp_light_accel_mag_vol-down-v5-4-f9a10a0a50eb@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts index 2dca1dca20b8..5de964d369b0 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts @@ -40,13 +40,13 @@ button-up { label = "Volume Up"; linux,code = ; - press-threshold-microvolt = <100000>; + press-threshold-microvolt = <2000>; }; button-down { label = "Volume Down"; linux,code = ; - press-threshold-microvolt = <600000>; + press-threshold-microvolt = <300000>; }; }; From 340f4fc5508c2905a1f30de229e2a4b299d55735 Mon Sep 17 00:00:00 2001 From: Ilikara Zheng Date: Mon, 8 Dec 2025 21:23:40 +0800 Subject: [PATCH 019/443] nvme-pci: disable secondary temp for Wodposit WPBSNM8 Secondary temperature thresholds (temp2_{min,max}) were not reported properly on this NVMe SSD. This resulted in an error while attempting to read these values with sensors(1): ERROR: Can't get value of subfeature temp2_min: I/O error ERROR: Can't get value of subfeature temp2_max: I/O error Add the device to the nvme_id_table with the NVME_QUIRK_NO_SECONDARY_TEMP_THRESH flag to suppress access to all non- composite temperature thresholds. Cc: stable@vger.kernel.org Tested-by: Wu Haotian Signed-off-by: Ilikara Zheng Signed-off-by: Keith Busch --- drivers/nvme/host/pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 0e4caeab739c..29e715d5b8f3 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -3999,6 +3999,8 @@ static const struct pci_device_id nvme_id_table[] = { .driver_data = NVME_QUIRK_NO_DEEPEST_PS, }, { PCI_DEVICE(0x1e49, 0x0041), /* ZHITAI TiPro7000 NVMe SSD */ .driver_data = NVME_QUIRK_NO_DEEPEST_PS, }, + { PCI_DEVICE(0x1fa0, 0x2283), /* Wodposit WPBSNM8-256GTP */ + .driver_data = NVME_QUIRK_NO_SECONDARY_TEMP_THRESH, }, { PCI_DEVICE(0x025e, 0xf1ac), /* SOLIDIGM P44 pro SSDPFKKW020X7 */ .driver_data = NVME_QUIRK_NO_DEEPEST_PS, }, { PCI_DEVICE(0xc0a9, 0x540a), /* Crucial P2 */ From 9bd18e1262c0fec6d76ffe6e2eae2b5f6cc08e3e Mon Sep 17 00:00:00 2001 From: Petr Mladek Date: Fri, 12 Dec 2025 13:45:20 +0100 Subject: [PATCH 020/443] printk/nbcon: Restore IRQ in atomic flush after each emitted record The commit d5d399efff6577 ("printk/nbcon: Release nbcon consoles ownership in atomic flush after each emitted record") prevented stall of a CPU which lost nbcon console ownership because another CPU entered an emergency flush. But there is still the problem that the CPU doing the emergency flush might cause a stall on its own. Let's go even further and restore IRQ in the atomic flush after each emitted record. It is not a complete solution. The interrupts and/or scheduling might still be blocked when the emergency atomic flush was called with IRQs and/or scheduling disabled. But it should remove the following lockup: mlx5_core 0000:03:00.0: Shutdown was called kvm: exiting hardware virtualization arm-smmu-v3 arm-smmu-v3.10.auto: CMD_SYNC timeout at 0x00000103 [hwprod 0x00000104, hwcons 0x00000102] smp: csd: Detected non-responsive CSD lock (#1) on CPU#4, waiting 5000000032 ns for CPU#00 do_nothing (kernel/smp.c:1057) smp: csd: CSD lock (#1) unresponsive. [...] Call trace: pl011_console_write_atomic (./arch/arm64/include/asm/vdso/processor.h:12 drivers/tty/serial/amba-pl011.c:2540) (P) nbcon_emit_next_record (kernel/printk/nbcon.c:1049) __nbcon_atomic_flush_pending_con (kernel/printk/nbcon.c:1517) __nbcon_atomic_flush_pending.llvm.15488114865160659019 (./arch/arm64/include/asm/alternative-macros.h:254 ./arch/arm64/include/asm/cpufeature.h:808 ./arch/arm64/include/asm/irqflags.h:192 kernel/printk/nbcon.c:1562 kernel/printk/nbcon.c:1612) nbcon_atomic_flush_pending (kernel/printk/nbcon.c:1629) printk_kthreads_shutdown (kernel/printk/printk.c:?) syscore_shutdown (drivers/base/syscore.c:120) kernel_kexec (kernel/kexec_core.c:1045) __arm64_sys_reboot (kernel/reboot.c:794 kernel/reboot.c:722 kernel/reboot.c:722) invoke_syscall (arch/arm64/kernel/syscall.c:50) el0_svc_common.llvm.14158405452757855239 (arch/arm64/kernel/syscall.c:?) do_el0_svc (arch/arm64/kernel/syscall.c:152) el0_svc (./arch/arm64/include/asm/alternative-macros.h:254 ./arch/arm64/include/asm/cpufeature.h:808 ./arch/arm64/include/asm/irqflags.h:73 arch/arm64/kernel/entry-common.c:169 arch/arm64/kernel/entry-common.c:182 arch/arm64/kernel/entry-common.c:749) el0t_64_sync_handler (arch/arm64/kernel/entry-common.c:820) el0t_64_sync (arch/arm64/kernel/entry.S:600) In this case, nbcon_atomic_flush_pending() is called from printk_kthreads_shutdown() with IRQs and scheduling enabled. Note that __nbcon_atomic_flush_pending_con() is directly called also from nbcon_device_release() where the disabled IRQs might break PREEMPT_RT guarantees. But the atomic flush is called only in emergency or panic situations where the latencies are irrelevant anyway. An ultimate solution would be a touching of watchdogs. But it would hide all problems. Let's do it later when anyone reports a stall which does not have a better solution. Closes: https://lore.kernel.org/r/sqwajvt7utnt463tzxgwu2yctyn5m6bjwrslsnupfexeml6hkd@v6sqmpbu3vvu Tested-by: Breno Leitao Reviewed-by: John Ogness Link: https://patch.msgid.link/20251212124520.244483-1-pmladek@suse.com Signed-off-by: Petr Mladek --- kernel/printk/nbcon.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c index 3fa403f9831f..32fc12e53675 100644 --- a/kernel/printk/nbcon.c +++ b/kernel/printk/nbcon.c @@ -1557,18 +1557,27 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq) ctxt->allow_unsafe_takeover = nbcon_allow_unsafe_takeover(); while (nbcon_seq_read(con) < stop_seq) { - if (!nbcon_context_try_acquire(ctxt, false)) - return -EPERM; - /* - * nbcon_emit_next_record() returns false when the console was - * handed over or taken over. In both cases the context is no - * longer valid. + * Atomic flushing does not use console driver synchronization + * (i.e. it does not hold the port lock for uart consoles). + * Therefore IRQs must be disabled to avoid being interrupted + * and then calling into a driver that will deadlock trying + * to acquire console ownership. */ - if (!nbcon_emit_next_record(&wctxt, true)) - return -EAGAIN; + scoped_guard(irqsave) { + if (!nbcon_context_try_acquire(ctxt, false)) + return -EPERM; - nbcon_context_release(ctxt); + /* + * nbcon_emit_next_record() returns false when + * the console was handed over or taken over. + * In both cases the context is no longer valid. + */ + if (!nbcon_emit_next_record(&wctxt, true)) + return -EAGAIN; + + nbcon_context_release(ctxt); + } if (!ctxt->backlog) { /* Are there reserved but not yet finalized records? */ @@ -1595,22 +1604,11 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq) static void nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq) { struct console_flush_type ft; - unsigned long flags; int err; again: - /* - * Atomic flushing does not use console driver synchronization (i.e. - * it does not hold the port lock for uart consoles). Therefore IRQs - * must be disabled to avoid being interrupted and then calling into - * a driver that will deadlock trying to acquire console ownership. - */ - local_irq_save(flags); - err = __nbcon_atomic_flush_pending_con(con, stop_seq); - local_irq_restore(flags); - /* * If there was a new owner (-EPERM, -EAGAIN), that context is * responsible for completing. From a143545855bc2c6e1330f6f57ae375ac44af00a7 Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Tue, 16 Dec 2025 22:10:06 +0800 Subject: [PATCH 021/443] dmaengine: mmp_pdma: Fix race condition in mmp_pdma_residue() Add proper locking in mmp_pdma_residue() to prevent use-after-free when accessing descriptor list and descriptor contents. The race occurs when multiple threads call tx_status() while the tasklet on another CPU is freeing completed descriptors: CPU 0 CPU 1 ----- ----- mmp_pdma_tx_status() mmp_pdma_residue() -> NO LOCK held list_for_each_entry(sw, ..) DMA interrupt dma_do_tasklet() -> spin_lock(&desc_lock) list_move(sw->node, ...) spin_unlock(&desc_lock) | dma_pool_free(sw) <- FREED! -> access sw->desc <- UAF! This issue can be reproduced when running dmatest on the same channel with multiple threads (threads_per_chan > 1). Fix by protecting the chain_running list iteration and descriptor access with the chan->desc_lock spinlock. Signed-off-by: Juan Li Signed-off-by: Guodong Xu Link: https://patch.msgid.link/20251216-mmp-pdma-race-v1-1-976a224bb622@riscstar.com Signed-off-by: Vinod Koul --- drivers/dma/mmp_pdma.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index 86661eb3cde1..d12e729ee12c 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -928,6 +928,7 @@ static unsigned int mmp_pdma_residue(struct mmp_pdma_chan *chan, { struct mmp_pdma_desc_sw *sw; struct mmp_pdma_device *pdev = to_mmp_pdma_dev(chan->chan.device); + unsigned long flags; u64 curr; u32 residue = 0; bool passed = false; @@ -945,6 +946,8 @@ static unsigned int mmp_pdma_residue(struct mmp_pdma_chan *chan, else curr = pdev->ops->read_src_addr(chan->phy); + spin_lock_irqsave(&chan->desc_lock, flags); + list_for_each_entry(sw, &chan->chain_running, node) { u64 start, end; u32 len; @@ -989,6 +992,7 @@ static unsigned int mmp_pdma_residue(struct mmp_pdma_chan *chan, continue; if (sw->async_tx.cookie == cookie) { + spin_unlock_irqrestore(&chan->desc_lock, flags); return residue; } else { residue = 0; @@ -996,6 +1000,8 @@ static unsigned int mmp_pdma_residue(struct mmp_pdma_chan *chan, } } + spin_unlock_irqrestore(&chan->desc_lock, flags); + /* We should only get here in case of cyclic transactions */ return residue; } From b18cd8b210417f90537d914ffb96e390c85a7379 Mon Sep 17 00:00:00 2001 From: Zhen Ni Date: Tue, 14 Oct 2025 17:05:22 +0800 Subject: [PATCH 022/443] dmaengine: fsl-edma: Fix clk leak on alloc_chan_resources failure When fsl_edma_alloc_chan_resources() fails after clk_prepare_enable(), the error paths only free IRQs and destroy the TCD pool, but forget to call clk_disable_unprepare(). This causes the channel clock to remain enabled, leaking power and resources. Fix it by disabling the channel clock in the error unwind path. Fixes: d8d4355861d8 ("dmaengine: fsl-edma: add i.MX8ULP edma support") Cc: stable@vger.kernel.org Suggested-by: Frank Li Signed-off-by: Zhen Ni Reviewed-by: Frank Li Link: https://patch.msgid.link/20251014090522.827726-1-zhen.ni@easystack.cn Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma-common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index a59212758029..7137f51ff6a0 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -873,6 +873,7 @@ err_errirq: free_irq(fsl_chan->txirq, fsl_chan); err_txirq: dma_pool_destroy(fsl_chan->tcd_pool); + clk_disable_unprepare(fsl_chan->clk); return ret; } From 2efd07a7c36949e6fa36a69183df24d368bf9e96 Mon Sep 17 00:00:00 2001 From: Sheetal Date: Mon, 10 Nov 2025 19:54:45 +0530 Subject: [PATCH 023/443] dmaengine: tegra-adma: Fix use-after-free A use-after-free bug exists in the Tegra ADMA driver when audio streams are terminated, particularly during XRUN conditions. The issue occurs when the DMA buffer is freed by tegra_adma_terminate_all() before the vchan completion tasklet finishes accessing it. The race condition follows this sequence: 1. DMA transfer completes, triggering an interrupt that schedules the completion tasklet (tasklet has not executed yet) 2. Audio playback stops, calling tegra_adma_terminate_all() which frees the DMA buffer memory via kfree() 3. The scheduled tasklet finally executes, calling vchan_complete() which attempts to access the already-freed memory Since tasklets can execute at any time after being scheduled, there is no guarantee that the buffer will remain valid when vchan_complete() runs. Fix this by properly synchronizing the virtual channel completion: - Calling vchan_terminate_vdesc() in tegra_adma_stop() to mark the descriptors as terminated instead of freeing the descriptor. - Add the callback tegra_adma_synchronize() that calls vchan_synchronize() which kills any pending tasklets and frees any terminated descriptors. Crash logs: [ 337.427523] BUG: KASAN: use-after-free in vchan_complete+0x124/0x3b0 [ 337.427544] Read of size 8 at addr ffff000132055428 by task swapper/0/0 [ 337.427562] Call trace: [ 337.427564] dump_backtrace+0x0/0x320 [ 337.427571] show_stack+0x20/0x30 [ 337.427575] dump_stack_lvl+0x68/0x84 [ 337.427584] print_address_description.constprop.0+0x74/0x2b8 [ 337.427590] kasan_report+0x1f4/0x210 [ 337.427598] __asan_load8+0xa0/0xd0 [ 337.427603] vchan_complete+0x124/0x3b0 [ 337.427609] tasklet_action_common.constprop.0+0x190/0x1d0 [ 337.427617] tasklet_action+0x30/0x40 [ 337.427623] __do_softirq+0x1a0/0x5c4 [ 337.427628] irq_exit+0x110/0x140 [ 337.427633] handle_domain_irq+0xa4/0xe0 [ 337.427640] gic_handle_irq+0x64/0x160 [ 337.427644] call_on_irq_stack+0x20/0x4c [ 337.427649] do_interrupt_handler+0x7c/0x90 [ 337.427654] el1_interrupt+0x30/0x80 [ 337.427659] el1h_64_irq_handler+0x18/0x30 [ 337.427663] el1h_64_irq+0x7c/0x80 [ 337.427667] cpuidle_enter_state+0xe4/0x540 [ 337.427674] cpuidle_enter+0x54/0x80 [ 337.427679] do_idle+0x2e0/0x380 [ 337.427685] cpu_startup_entry+0x2c/0x70 [ 337.427690] rest_init+0x114/0x130 [ 337.427695] arch_call_rest_init+0x18/0x24 [ 337.427702] start_kernel+0x380/0x3b4 [ 337.427706] __primary_switched+0xc0/0xc8 Fixes: f46b195799b5 ("dmaengine: tegra-adma: Add support for Tegra210 ADMA") Signed-off-by: Sheetal Acked-by: Thierry Reding Link: https://patch.msgid.link/20251110142445.3842036-1-sheetal@nvidia.com Signed-off-by: Vinod Koul --- drivers/dma/tegra210-adma.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index d0e8bb27a03b..215bfef37ec6 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -429,10 +429,17 @@ static void tegra_adma_stop(struct tegra_adma_chan *tdc) return; } - kfree(tdc->desc); + vchan_terminate_vdesc(&tdc->desc->vd); tdc->desc = NULL; } +static void tegra_adma_synchronize(struct dma_chan *dc) +{ + struct tegra_adma_chan *tdc = to_tegra_adma_chan(dc); + + vchan_synchronize(&tdc->vc); +} + static void tegra_adma_start(struct tegra_adma_chan *tdc) { struct virt_dma_desc *vd = vchan_next_desc(&tdc->vc); @@ -1155,6 +1162,7 @@ static int tegra_adma_probe(struct platform_device *pdev) tdma->dma_dev.device_config = tegra_adma_slave_config; tdma->dma_dev.device_tx_status = tegra_adma_tx_status; tdma->dma_dev.device_terminate_all = tegra_adma_terminate_all; + tdma->dma_dev.device_synchronize = tegra_adma_synchronize; tdma->dma_dev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); tdma->dma_dev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); tdma->dma_dev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); From c0732fe78728718c853ef8e7af5bbb05262acbd1 Mon Sep 17 00:00:00 2001 From: Suraj Gupta Date: Wed, 22 Oct 2025 00:00:06 +0530 Subject: [PATCH 024/443] dmaengine: xilinx_dma: Fix uninitialized addr_width when "xlnx,addrwidth" property is missing When device tree lacks optional "xlnx,addrwidth" property, the addr_width variable remained uninitialized with garbage values, causing incorrect DMA mask configuration and subsequent probe failure. The fix ensures a fallback to the default 32-bit address width when this property is missing. Signed-off-by: Suraj Gupta Fixes: b72db4005fe4 ("dmaengine: vdma: Add 64 bit addressing support to the driver") Reviewed-by: Radhey Shyam Pandey Reviewed-by: Folker Schwesinger Link: https://patch.msgid.link/20251021183006.3434495-1-suraj.gupta2@amd.com Signed-off-by: Vinod Koul --- drivers/dma/xilinx/xilinx_dma.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index fabff602065f..89a8254d9cdc 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -131,6 +131,7 @@ #define XILINX_MCDMA_MAX_CHANS_PER_DEVICE 0x20 #define XILINX_DMA_MAX_CHANS_PER_DEVICE 0x2 #define XILINX_CDMA_MAX_CHANS_PER_DEVICE 0x1 +#define XILINX_DMA_DFAULT_ADDRWIDTH 0x20 #define XILINX_DMA_DMAXR_ALL_IRQ_MASK \ (XILINX_DMA_DMASR_FRM_CNT_IRQ | \ @@ -3159,7 +3160,7 @@ static int xilinx_dma_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; struct xilinx_dma_device *xdev; struct device_node *child, *np = pdev->dev.of_node; - u32 num_frames, addr_width, len_width; + u32 num_frames, addr_width = XILINX_DMA_DFAULT_ADDRWIDTH, len_width; int i, err; /* Allocate and initialize the DMA engine structure */ @@ -3235,7 +3236,9 @@ static int xilinx_dma_probe(struct platform_device *pdev) err = of_property_read_u32(node, "xlnx,addrwidth", &addr_width); if (err < 0) - dev_warn(xdev->dev, "missing xlnx,addrwidth property\n"); + dev_warn(xdev->dev, + "missing xlnx,addrwidth property, using default value %d\n", + XILINX_DMA_DFAULT_ADDRWIDTH); if (addr_width > 32) xdev->ext_addr = true; From 747213b08a1ab6a76e3e3b3e7a209cc1d402b5d0 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Thu, 13 Nov 2025 19:50:48 +0000 Subject: [PATCH 025/443] dmaengine: sh: rz-dmac: Fix rz_dmac_terminate_all() After audio full duplex testing, playing the recorded file contains a few playback frames from the previous time. The rz_dmac_terminate_all() does not reset all the hardware descriptors queued previously, leading to the wrong descriptor being picked up during the next DMA transfer. Fix the above issue by resetting all the descriptor headers for a channel in rz_dmac_terminate_all() as rz_dmac_lmdesc_recycle() points to the proper descriptor header filled by the rz_dmac_prepare_descs_for_slave_sg(). Cc: stable@kernel.org Fixes: 5000d37042a6 ("dmaengine: sh: Add DMAC driver for RZ/G2L SoC") Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Reviewed-by: Claudiu Beznea Tested-by: Claudiu Beznea Link: https://patch.msgid.link/20251113195052.564338-1-biju.das.jz@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/dma/sh/rz-dmac.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c index 38137e8d80b9..9e5f088355e2 100644 --- a/drivers/dma/sh/rz-dmac.c +++ b/drivers/dma/sh/rz-dmac.c @@ -557,11 +557,16 @@ rz_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, static int rz_dmac_terminate_all(struct dma_chan *chan) { struct rz_dmac_chan *channel = to_rz_dmac_chan(chan); + struct rz_lmdesc *lmdesc = channel->lmdesc.base; unsigned long flags; + unsigned int i; LIST_HEAD(head); rz_dmac_disable_hw(channel); spin_lock_irqsave(&channel->vc.lock, flags); + for (i = 0; i < DMAC_NR_LMDESC; i++) + lmdesc[i].header = 0; + list_splice_tail_init(&channel->ld_active, &channel->ld_free); list_splice_tail_init(&channel->ld_queue, &channel->ld_free); vchan_get_all_descriptors(&channel->vc, &head); From 8bb3754909cde5df4f8c1012bde220b97d8ee3bc Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Wed, 26 Nov 2025 18:41:46 +0530 Subject: [PATCH 026/443] arm64: dts: qcom: talos: Correct UFS clocks ordering The current UFS clocks does not align with their respective names, causing the ref_clk to be set to an incorrect frequency as below, which results in command timeouts. ufshcd-qcom 1d84000.ufshc: invalid ref_clk setting = 300000000 This commit fixes the issue by properly reordering the UFS clocks to match their names. Fixes: ea172f61f4fd ("arm64: dts: qcom: qcs615: Fix up UFS clocks") Cc: stable@vger.kernel.org Signed-off-by: Pradeep P V K Link: https://lore.kernel.org/r/20251126131146.16146-1-pradeep.pragallapati@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/talos.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi index d1dbfa3bd81c..95d26e313622 100644 --- a/arch/arm64/boot/dts/qcom/talos.dtsi +++ b/arch/arm64/boot/dts/qcom/talos.dtsi @@ -1399,10 +1399,10 @@ <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, <&gcc GCC_UFS_PHY_AHB_CLK>, <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, - <&gcc GCC_UFS_PHY_ICE_CORE_CLK>, <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, - <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>; + <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; clock-names = "core_clk", "bus_aggr_clk", "iface_clk", From 08a797dbcea1bf923f9d3f87738375641eaf5769 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 28 Nov 2025 15:11:27 +0200 Subject: [PATCH 027/443] mailmap: Update email address for Abel Vesa My Linaro email is going to bounce soon, so add .mailmap entry to my kernel.org alias. Signed-off-by: Abel Vesa Link: https://lore.kernel.org/r/20251128-mailmap-update-abel-vesa-v1-1-2e45c25c0918@linaro.org Signed-off-by: Bjorn Andersson --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 84309a39d329..398e6752786e 100644 --- a/.mailmap +++ b/.mailmap @@ -12,6 +12,7 @@ # Aaron Durbin Abel Vesa +Abel Vesa Abel Vesa Abhijeet Dharmapurikar Abhinav Kumar From 8e6c237cd759b2297b38d978bd6e14bf0dc4a804 Mon Sep 17 00:00:00 2001 From: David Heidelberg Date: Thu, 4 Dec 2025 11:41:24 +0100 Subject: [PATCH 028/443] arm64: dts qcom: sdm845-oneplus-enchilada: Specify panel name within the compatible sofef00 is name of the DDIC, it doesn't contain name of the panel used. The DDIC is also paired with other panels, so make clear which panel is used. New device-tree will work with old driver as expected, due to secondary compatible. Cosmetic: sort the properties in the node. Reviewed-by: Neil Armstrong Signed-off-by: David Heidelberg Link: https://lore.kernel.org/r/20251204-sofef00-rebuild-v4-1-7f6e030ae5b7@ixit.cz Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm845-oneplus-enchilada.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-enchilada.dts b/arch/arm64/boot/dts/qcom/sdm845-oneplus-enchilada.dts index a259eb9d45ae..8aead6dc25e0 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-enchilada.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-enchilada.dts @@ -31,9 +31,9 @@ }; &display_panel { - status = "okay"; + compatible = "samsung,sofef00-ams628nw01", "samsung,sofef00"; - compatible = "samsung,sofef00"; + status = "okay"; }; &bq27441_fg { From 45e1be5ddec98db71e7481fa7a3005673200d85c Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 2 Dec 2025 18:36:20 +0100 Subject: [PATCH 029/443] dt-bindings: power: qcom,rpmpd: Add SC8280XP_MXC_AO Not sure how useful it's gonna be in practice, but the definition is missing (unlike the previously-unused SC8280XP_MXC-non-_AO), so add it to allow the driver to create the corresponding pmdomain. Fixes: dbfb5f94e084 ("dt-bindings: power: rpmpd: Add sc8280xp RPMh power-domains") Acked-by: Rob Herring (Arm) Signed-off-by: Konrad Dybcio Reviewed-by: Ulf Hansson Link: https://lore.kernel.org/r/20251202-topic-8280_mxc-v2-1-46cdf47a829e@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- include/dt-bindings/power/qcom,rpmhpd.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/power/qcom,rpmhpd.h b/include/dt-bindings/power/qcom,rpmhpd.h index 50e7c886709d..06851363ae0e 100644 --- a/include/dt-bindings/power/qcom,rpmhpd.h +++ b/include/dt-bindings/power/qcom,rpmhpd.h @@ -264,5 +264,6 @@ #define SC8280XP_NSP 13 #define SC8280XP_QPHY 14 #define SC8280XP_XO 15 +#define SC8280XP_MXC_AO 16 #endif From 5bc3e720e725cd5fa34875fa1e5434d565858067 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 2 Dec 2025 18:36:21 +0100 Subject: [PATCH 030/443] pmdomain: qcom: rpmhpd: Add MXC to SC8280XP This was apparently accounted for in dt-bindings, but never made its way into the driver. Fix it for SC8280XP and its VDD_GFX-less cousin, SA8540P. Fixes: f68f1cb3437d ("soc: qcom: rpmhpd: add sc8280xp & sa8540p rpmh power-domains") Reviewed-by: Dmitry Baryshkov Signed-off-by: Konrad Dybcio Reviewed-by: Ulf Hansson Link: https://lore.kernel.org/r/20251202-topic-8280_mxc-v2-2-46cdf47a829e@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/pmdomain/qcom/rpmhpd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pmdomain/qcom/rpmhpd.c b/drivers/pmdomain/qcom/rpmhpd.c index a8b37037c6fe..19849703be4a 100644 --- a/drivers/pmdomain/qcom/rpmhpd.c +++ b/drivers/pmdomain/qcom/rpmhpd.c @@ -246,6 +246,8 @@ static struct rpmhpd *sa8540p_rpmhpds[] = { [SC8280XP_MMCX_AO] = &mmcx_ao, [SC8280XP_MX] = &mx, [SC8280XP_MX_AO] = &mx_ao, + [SC8280XP_MXC] = &mxc, + [SC8280XP_MXC_AO] = &mxc_ao, [SC8280XP_NSP] = &nsp, }; @@ -700,6 +702,8 @@ static struct rpmhpd *sc8280xp_rpmhpds[] = { [SC8280XP_MMCX_AO] = &mmcx_ao, [SC8280XP_MX] = &mx, [SC8280XP_MX_AO] = &mx_ao, + [SC8280XP_MXC] = &mxc, + [SC8280XP_MXC_AO] = &mxc_ao, [SC8280XP_NSP] = &nsp, [SC8280XP_QPHY] = &qphy, }; From 868b979c5328b867c95a6d5a93ba13ad0d3cd2f1 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Tue, 2 Dec 2025 18:36:22 +0100 Subject: [PATCH 031/443] arm64: dts: qcom: sc8280xp: Add missing VDD_MXC links To make sure that power rail is voted for, wire it up to its consumers. Fixes: 152d1faf1e2f ("arm64: dts: qcom: add SC8280XP platform") Signed-off-by: Konrad Dybcio Reviewed-by: Ulf Hansson Link: https://lore.kernel.org/r/20251202-topic-8280_mxc-v2-3-46cdf47a829e@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sc8280xp.dtsi | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi index 5334adebf278..b9e0d9c7c065 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi @@ -5788,8 +5788,12 @@ clocks = <&rpmhcc RPMH_CXO_CLK>; clock-names = "xo"; - power-domains = <&rpmhpd SC8280XP_NSP>; - power-domain-names = "nsp"; + power-domains = <&rpmhpd SC8280XP_NSP>, + <&rpmhpd SC8280XP_CX>, + <&rpmhpd SC8280XP_MXC>; + power-domain-names = "nsp", + "cx", + "mxc"; memory-region = <&pil_nsp0_mem>; @@ -5919,8 +5923,12 @@ clocks = <&rpmhcc RPMH_CXO_CLK>; clock-names = "xo"; - power-domains = <&rpmhpd SC8280XP_NSP>; - power-domain-names = "nsp"; + power-domains = <&rpmhpd SC8280XP_NSP>, + <&rpmhpd SC8280XP_CX>, + <&rpmhpd SC8280XP_MXC>; + power-domain-names = "nsp", + "cx", + "mxc"; memory-region = <&pil_nsp1_mem>; From 9dbc9bed01837717b8ab755cf5067a6f8d35b00f Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Wed, 3 Dec 2025 20:18:55 +0530 Subject: [PATCH 032/443] arm64: dts: qcom: sm8550: Fix compile warnings in USB controller node With W=1, the following error comes up: Warning (avoid_unnecessary_addr_size): /soc@0/usb@a600000: unnecessary #address-cells/#size-cells without "ranges", "dma-ranges" or child "reg" or "ranges" property This is because the child node being removed during flattening and moving to latest bindings. Fixes: 33450878adfc ("arm64: dts: qcom: sm8550: Flatten the USB nodes") Signed-off-by: Krishna Kurapati Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20251203144856.2711440-2-krishna.kurapati@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8550.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi index 2ca9e50ef599..e3f93f4f412d 100644 --- a/arch/arm64/boot/dts/qcom/sm8550.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi @@ -4133,8 +4133,6 @@ usb_1: usb@a600000 { compatible = "qcom,sm8550-dwc3", "qcom,snps-dwc3"; reg = <0x0 0x0a600000 0x0 0xfc100>; - #address-cells = <1>; - #size-cells = <0>; clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>, From 1f6ca557088eb96c8c554f853eb7c60862f8a0a8 Mon Sep 17 00:00:00 2001 From: Krishna Kurapati Date: Wed, 3 Dec 2025 20:18:56 +0530 Subject: [PATCH 033/443] arm64: dts: qcom: sm8650: Fix compile warnings in USB controller node With W=1, the following error comes up: Warning (avoid_unnecessary_addr_size): /soc@0/usb@a600000: unnecessary #address-cells/#size-cells without "ranges", "dma-ranges" or child "reg" or "ranges" property This is because the child node being removed during flattening and moving to latest bindings. Fixes: 77e1f16b9302 ("arm64: dts: qcom: sm8650: Flatten the USB nodes") Signed-off-by: Krishna Kurapati Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20251203144856.2711440-3-krishna.kurapati@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sm8650.dtsi | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi index 07ae74851621..f8e1950a74ac 100644 --- a/arch/arm64/boot/dts/qcom/sm8650.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -5150,9 +5150,6 @@ dma-coherent; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; ports { From 7c6bbcb010b1b8e4e6452de109f0506bb05d6efb Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 17 Dec 2025 10:18:08 +0100 Subject: [PATCH 034/443] arm64: dts: rockchip: Fix wifi interrupts flag on Sakura Pi RK3308B GPIO_ACTIVE_x flags are not correct in the context of interrupt flags. These are simple defines so they could be used in DTS but they will not have the same meaning: GPIO_ACTIVE_HIGH = 0 = IRQ_TYPE_NONE. Correct the interrupt flags, assuming the author of the code wanted same logical behavior behind the name "ACTIVE_xxx", this is: ACTIVE_HIGH => IRQ_TYPE_LEVEL_HIGH Fixes: 79f2a1702441 ("arm64: dts: rockchip: add DTs for Sakura Pi RK3308B") Cc: stable+noautosel@kernel.org # Needs testing, because actual level is just a guess Signed-off-by: Krzysztof Kozlowski Acked-by: Chiyuki Akatsuki Link: https://patch.msgid.link/20251217091808.38253-2-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3308-sakurapi-rk3308b.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3308-sakurapi-rk3308b.dts b/arch/arm64/boot/dts/rockchip/rk3308-sakurapi-rk3308b.dts index e5e6b800c2d1..3473db08b9b2 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308-sakurapi-rk3308b.dts +++ b/arch/arm64/boot/dts/rockchip/rk3308-sakurapi-rk3308b.dts @@ -199,7 +199,7 @@ compatible = "brcm,bcm43455-fmac", "brcm,bcm4329-fmac"; reg = <1>; interrupt-parent = <&gpio0>; - interrupts = ; + interrupts = ; interrupt-names = "host-wake"; pinctrl-names = "default"; pinctrl-0 = <&wifi_host_wake>; From cd8967ea3105d30adb878a9fea0e34a9378df610 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 15 Dec 2025 17:45:56 +0100 Subject: [PATCH 035/443] arm64: dts: rockchip: fix unit-address for RK3588 NPU's core1 and core2's IOMMU The Device Tree specification specifies[1] that """ Each node in the devicetree is named according to the following convention: node-name@unit-address [...] The unit-address must match the first address specified in the reg property of the node. """ The first address in the reg property is fdaXa000 and not fdaX9000. This is likely a copy-paste error as the IOMMU for core0 has two entries in the reg property, the first one being fdab9000 and the second fdaba000. Let's fix this oversight to match what the spec is expecting. [1] https://github.com/devicetree-org/devicetree-specification/releases/download/v0.4/devicetree-specification-v0.4.pdf 2.2.1 Node Names Fixes: a31dfc060a74 ("arm64: dts: rockchip: Add nodes for NPU and its MMU to rk3588-base") Cc: stable@vger.kernel.org Signed-off-by: Quentin Schulz Link: https://patch.msgid.link/20251215-npu-dt-node-address-v1-1-840093e8a2bf@cherry.de Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3588-base.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi index 2a7921793020..7ab12d1054a7 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi @@ -1200,7 +1200,7 @@ status = "disabled"; }; - rknn_mmu_1: iommu@fdac9000 { + rknn_mmu_1: iommu@fdaca000 { compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu"; reg = <0x0 0xfdaca000 0x0 0x100>; interrupts = ; @@ -1230,7 +1230,7 @@ status = "disabled"; }; - rknn_mmu_2: iommu@fdad9000 { + rknn_mmu_2: iommu@fdada000 { compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu"; reg = <0x0 0xfdada000 0x0 0x100>; interrupts = ; From 0368e4afcf20f377c81fa77b1c7d0dee4a625a44 Mon Sep 17 00:00:00 2001 From: Geraldo Nascimento Date: Mon, 17 Nov 2025 18:47:43 -0300 Subject: [PATCH 036/443] arm64: dts: rockchip: remove dangerous max-link-speed from helios64 Shawn Lin from Rockchip strongly discourages attempts to use their RK3399 PCIe core at 5.0 GT/s speed, citing concerns about catastrophic failures that may happen. Even if the odds are low, drop from last user of this non-default property for the RK3399 platform, helios64 board dts. Fixes: 755fff528b1b ("arm64: dts: rockchip: add variables for pcie completion to helios64") Link: https://lore.kernel.org/all/e8524bf8-a90c-423f-8a58-9ef05a3db1dd@rock-chips.com/ Cc: stable@vger.kernel.org Reported-by: Shawn Lin Reviewed-by: Dragan Simic Signed-off-by: Geraldo Nascimento Acked-by: Shawn Lin Link: https://patch.msgid.link/43bb639c120f599106fca2deee6c6599b2692c5c.1763415706.git.geraldogabriel@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts b/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts index e7d4a2f9a95e..78a7775c3b22 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts @@ -424,7 +424,6 @@ &pcie0 { ep-gpios = <&gpio2 RK_PD4 GPIO_ACTIVE_HIGH>; - max-link-speed = <2>; num-lanes = <2>; pinctrl-names = "default"; status = "okay"; From ce652c98a7bfa0b7c675ef5cd85c44c186db96af Mon Sep 17 00:00:00 2001 From: Geraldo Nascimento Date: Mon, 17 Nov 2025 18:47:59 -0300 Subject: [PATCH 037/443] arm64: dts: rockchip: remove redundant max-link-speed from nanopi-r4s This is already the default in rk3399-base.dtsi, remove redundant declaration from rk3399-nanopi-r4s.dtsi. Fixes: db792e9adbf8 ("rockchip: rk3399: Add support for FriendlyARM NanoPi R4S") Cc: stable@vger.kernel.org Reported-by: Dragan Simic Reviewed-by: Dragan Simic Signed-off-by: Geraldo Nascimento Acked-by: Shawn Lin Link: https://patch.msgid.link/6694456a735844177c897581f785cc00c064c7d1.1763415706.git.geraldogabriel@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dtsi index 8d94d9f91a5c..3a9a10f531bd 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi-r4s.dtsi @@ -71,7 +71,6 @@ }; &pcie0 { - max-link-speed = <1>; num-lanes = <1>; vpcie3v3-supply = <&vcc3v3_sys>; }; From 49ccab4bedd4779899246107dc19fb01c5b6fea3 Mon Sep 17 00:00:00 2001 From: Franz Schnyder Date: Wed, 26 Nov 2025 15:01:33 +0100 Subject: [PATCH 038/443] phy: fsl-imx8mq-usb: fix typec orientation switch when built as module Currently, the PHY only registers the typec orientation switch when it is built in. If the typec driver is built as a module, the switch registration is skipped due to the preprocessor condition, causing orientation detection to fail. With commit 45fe729be9a6 ("usb: typec: Stub out typec_switch APIs when CONFIG_TYPEC=n") the preprocessor condition is not needed anymore and the orientation switch is correctly registered for both built-in and module builds. Fixes: b58f0f86fd61 ("phy: fsl-imx8mq-usb: add tca function driver for imx95") Cc: stable@vger.kernel.org Suggested-by: Xu Yang Signed-off-by: Franz Schnyder Reviewed-by: Frank Li Reviewed-by: Xu Yang Link: https://patch.msgid.link/20251126140136.1202241-1-fra.schnyder@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c index ad8a55012e42..99d2bdd4bfc8 100644 --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c @@ -126,8 +126,6 @@ struct imx8mq_usb_phy { static void tca_blk_orientation_set(struct tca_blk *tca, enum typec_orientation orientation); -#ifdef CONFIG_TYPEC - static int tca_blk_typec_switch_set(struct typec_switch_dev *sw, enum typec_orientation orientation) { @@ -175,18 +173,6 @@ static void tca_blk_put_typec_switch(struct typec_switch_dev *sw) typec_switch_unregister(sw); } -#else - -static struct typec_switch_dev *tca_blk_get_typec_switch(struct platform_device *pdev, - struct imx8mq_usb_phy *imx_phy) -{ - return NULL; -} - -static void tca_blk_put_typec_switch(struct typec_switch_dev *sw) {} - -#endif /* CONFIG_TYPEC */ - static void tca_blk_orientation_set(struct tca_blk *tca, enum typec_orientation orientation) { From 393e132efcc5e3fc4ef2bd9bbed2a096096c9359 Mon Sep 17 00:00:00 2001 From: Ziyue Zhang Date: Fri, 28 Nov 2025 18:49:23 +0800 Subject: [PATCH 039/443] dt-bindings: phy: qcom,sc8280xp-qmp-pcie-phy: Update pcie phy bindings for qcs8300 The gcc_aux_clk is not required by the PCIe PHY on qcs8300 and is not specified in the device tree node. Hence, move the qcs8300 phy compatibility entry into the list of PHYs that require six clocks. Removed the phy_aux clock from the PCIe PHY binding as it is no longer used by any instance. Fixes: e46e59b77a9e ("dt-bindings: phy: qcom,sc8280xp-qmp-pcie-phy: Document the QCS8300 QMP PCIe PHY Gen4 x2") Signed-off-by: Ziyue Zhang Acked-by: Manivannan Sadhasivam Acked-by: Rob Herring (Arm) Reviewed-by: Johan Hovold Link: https://patch.msgid.link/20251128104928.4070050-2-ziyue.zhang@oss.qualcomm.com Signed-off-by: Vinod Koul --- .../phy/qcom,sc8280xp-qmp-pcie-phy.yaml | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml index 48bd11410e8c..f5068df20cfe 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml @@ -56,7 +56,7 @@ properties: clocks: minItems: 5 - maxItems: 7 + maxItems: 6 clock-names: minItems: 5 @@ -67,7 +67,6 @@ properties: - enum: [rchng, refgen] - const: pipe - const: pipediv2 - - const: phy_aux power-domains: maxItems: 1 @@ -180,6 +179,7 @@ allOf: contains: enum: - qcom,glymur-qmp-gen5x4-pcie-phy + - qcom,qcs8300-qmp-gen4x2-pcie-phy - qcom,sa8775p-qmp-gen4x2-pcie-phy - qcom,sa8775p-qmp-gen4x4-pcie-phy - qcom,sc8280xp-qmp-gen3x1-pcie-phy @@ -197,19 +197,6 @@ allOf: clock-names: minItems: 6 - - if: - properties: - compatible: - contains: - enum: - - qcom,qcs8300-qmp-gen4x2-pcie-phy - then: - properties: - clocks: - minItems: 7 - clock-names: - minItems: 7 - - if: properties: compatible: From 8becf9179a4b45104a1701010ed666b55bf4b3a6 Mon Sep 17 00:00:00 2001 From: Stefano Radaelli Date: Fri, 19 Dec 2025 17:09:12 +0100 Subject: [PATCH 040/443] phy: fsl-imx8mq-usb: Clear the PCS_TX_SWING_FULL field before using it Clear the PCS_TX_SWING_FULL field mask before setting the new value in PHY_CTRL5 register. Without clearing the mask first, the OR operation could leave previously set bits, resulting in incorrect register configuration. Fixes: 63c85ad0cd81 ("phy: fsl-imx8mp-usb: add support for phy tuning") Suggested-by: Leonid Segal Acked-by: Pierluigi Passaro Signed-off-by: Stefano Radaelli Reviewed-by: Xu Yang Reviewed-by: Frank Li Reviewed-by: Fabio Estevam Reviewed-by: Ahmad Fatoum Link: https://patch.msgid.link/20251219160912.561431-1-stefano.r@variscite.com Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-imx8mq-usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c index 99d2bdd4bfc8..91b3e62743d3 100644 --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c @@ -490,6 +490,7 @@ static void imx8m_phy_tune(struct imx8mq_usb_phy *imx_phy) if (imx_phy->pcs_tx_swing_full != PHY_TUNE_DEFAULT) { value = readl(imx_phy->base + PHY_CTRL5); + value &= ~PHY_CTRL5_PCS_TX_SWING_FULL_MASK; value |= FIELD_PREP(PHY_CTRL5_PCS_TX_SWING_FULL_MASK, imx_phy->pcs_tx_swing_full); writel(value, imx_phy->base + PHY_CTRL5); From 1ca52c0983c34fca506921791202ed5bdafd5306 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 19 Dec 2025 09:56:40 +0100 Subject: [PATCH 041/443] phy: qcom-qusb2: Fix NULL pointer dereference on early suspend Enabling runtime PM before attaching the QPHY instance as driver data can lead to a NULL pointer dereference in runtime PM callbacks that expect valid driver data. There is a small window where the suspend callback may run after PM runtime enabling and before runtime forbid. This causes a sporadic crash during boot: ``` Unable to handle kernel NULL pointer dereference at virtual address 00000000000000a1 [...] CPU: 0 UID: 0 PID: 11 Comm: kworker/0:1 Not tainted 6.16.7+ #116 PREEMPT Workqueue: pm pm_runtime_work pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : qusb2_phy_runtime_suspend+0x14/0x1e0 [phy_qcom_qusb2] lr : pm_generic_runtime_suspend+0x2c/0x44 [...] ``` Attach the QPHY instance as driver data before enabling runtime PM to prevent NULL pointer dereference in runtime PM callbacks. Reorder pm_runtime_enable() and pm_runtime_forbid() to prevent a short window where an unnecessary runtime suspend can occur. Use the devres-managed version to ensure PM runtime is symmetrically disabled during driver removal for proper cleanup. Fixes: 891a96f65ac3 ("phy: qcom-qusb2: Add support for runtime PM") Signed-off-by: Loic Poulain Reviewed-by: Dmitry Baryshkov Reviewed-by: Abel Vesa Link: https://patch.msgid.link/20251219085640.114473-1-loic.poulain@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qusb2.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c index b5514a32ff8f..eb93015be841 100644 --- a/drivers/phy/qualcomm/phy-qcom-qusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c @@ -1093,29 +1093,29 @@ static int qusb2_phy_probe(struct platform_device *pdev) or->hsdisc_trim.override = true; } - pm_runtime_set_active(dev); - pm_runtime_enable(dev); + dev_set_drvdata(dev, qphy); + /* - * Prevent runtime pm from being ON by default. Users can enable - * it using power/control in sysfs. + * Enable runtime PM support, but forbid it by default. + * Users can allow it again via the power/control attribute in sysfs. */ + pm_runtime_set_active(dev); pm_runtime_forbid(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; generic_phy = devm_phy_create(dev, NULL, &qusb2_phy_gen_ops); if (IS_ERR(generic_phy)) { ret = PTR_ERR(generic_phy); dev_err(dev, "failed to create phy, %d\n", ret); - pm_runtime_disable(dev); return ret; } qphy->phy = generic_phy; - dev_set_drvdata(dev, qphy); phy_set_drvdata(generic_phy, qphy); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR(phy_provider)) - pm_runtime_disable(dev); return PTR_ERR_OR_ZERO(phy_provider); } From cabd25b57216ddc132efbcc31f972baa03aad15a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 9 Dec 2025 09:53:36 +0300 Subject: [PATCH 042/443] phy: stm32-usphyc: Fix off by one in probe() The "index" variable is used as an index into the usbphyc->phys[] array which has usbphyc->nphys elements. So if it is equal to usbphyc->nphys then it is one element out of bounds. The "index" comes from the device tree so it's data that we trust and it's unlikely to be wrong, however it's obviously still worth fixing the bug. Change the > to >=. Fixes: 94c358da3a05 ("phy: stm32: add support for STM32 USB PHY Controller (USBPHYC)") Signed-off-by: Dan Carpenter Reviewed-by: Amelie Delaunay Link: https://patch.msgid.link/aTfHcMJK1wFVnvEe@stanley.mountain Signed-off-by: Vinod Koul --- drivers/phy/st/phy-stm32-usbphyc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c index 27fe92f73f33..b44afbff8616 100644 --- a/drivers/phy/st/phy-stm32-usbphyc.c +++ b/drivers/phy/st/phy-stm32-usbphyc.c @@ -712,7 +712,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) } ret = of_property_read_u32(child, "reg", &index); - if (ret || index > usbphyc->nphys) { + if (ret || index >= usbphyc->nphys) { dev_err(&phy->dev, "invalid reg property: %d\n", ret); if (!ret) ret = -EINVAL; From 08aa19de72110df8ac10c9e67349dd884eeed41d Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 24 Nov 2025 18:57:34 +0800 Subject: [PATCH 043/443] phy: ti: da8xx-usb: Handle devm_pm_runtime_enable() errors devm_pm_runtime_enable() can fail due to memory allocation. The current code ignores its return value after calling pm_runtime_set_active(), leaving the device in an inconsistent state if runtime PM initialization fails. Check the return value of devm_pm_runtime_enable() and return on failure. Also move the declaration of 'ret' to the function scope to support this check. Fixes: ee8e41b5044f ("phy: ti: phy-da8xx-usb: Add runtime PM support") Suggested-by: Neil Armstrong Signed-off-by: Haotian Zhang Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20251124105734.1027-1-vulab@iscas.ac.cn Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-da8xx-usb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/phy/ti/phy-da8xx-usb.c b/drivers/phy/ti/phy-da8xx-usb.c index 1d81a1e6ec6b..62fa6f89c0e6 100644 --- a/drivers/phy/ti/phy-da8xx-usb.c +++ b/drivers/phy/ti/phy-da8xx-usb.c @@ -180,6 +180,7 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev) struct da8xx_usb_phy_platform_data *pdata = dev->platform_data; struct device_node *node = dev->of_node; struct da8xx_usb_phy *d_phy; + int ret; d_phy = devm_kzalloc(dev, sizeof(*d_phy), GFP_KERNEL); if (!d_phy) @@ -233,8 +234,6 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev) return PTR_ERR(d_phy->phy_provider); } } else { - int ret; - ret = phy_create_lookup(d_phy->usb11_phy, "usb-phy", "ohci-da8xx"); if (ret) @@ -249,7 +248,9 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev) PHY_INIT_BITS, PHY_INIT_BITS); pm_runtime_set_active(dev); - devm_pm_runtime_enable(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; /* * Prevent runtime pm from being ON by default. Users can enable * it using power/control in sysfs. From d543d3eb06873f0ab8edb0d1f8364e9af93544a0 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Fri, 31 Oct 2025 13:18:12 +0100 Subject: [PATCH 044/443] phy: sparx5-serdes: make it selectable for ARCH_LAN969X LAN969x uses the SparX-5 SERDES driver, so make it selectable for ARCH_LAN969X. Reviewed-by: Daniel Machon Signed-off-by: Robert Marko Tested-by: Gabor Juhos Tested-by: Vladimir Oltean Link: https://patch.msgid.link/20251031121834.665987-1-robert.marko@sartura.hr Signed-off-by: Vinod Koul --- drivers/phy/microchip/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/microchip/Kconfig b/drivers/phy/microchip/Kconfig index 2f0045e874ac..2e6d1224711e 100644 --- a/drivers/phy/microchip/Kconfig +++ b/drivers/phy/microchip/Kconfig @@ -6,7 +6,7 @@ config PHY_SPARX5_SERDES tristate "Microchip Sparx5 SerDes PHY driver" select GENERIC_PHY - depends on ARCH_SPARX5 || COMPILE_TEST + depends on ARCH_SPARX5 || ARCH_LAN969X || COMPILE_TEST depends on OF depends on HAS_IOMEM help From 4914d67da947031d6f645c81c74f7879e0844d5d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 27 Nov 2025 14:48:34 +0100 Subject: [PATCH 045/443] phy: ti: gmii-sel: fix regmap leak on probe failure The mmio regmap that may be allocated during probe is never freed. Switch to using the device managed allocator so that the regmap is released on probe failures (e.g. probe deferral) and on driver unbind. Fixes: 5ab90f40121a ("phy: ti: gmii-sel: Do not use syscon helper to build regmap") Cc: stable@vger.kernel.org # 6.14 Cc: Andrew Davis Signed-off-by: Johan Hovold Acked-by: Andrew Davis Link: https://patch.msgid.link/20251127134834.2030-1-johan@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-gmii-sel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c index 6cfe2538d15b..6213c2b6005a 100644 --- a/drivers/phy/ti/phy-gmii-sel.c +++ b/drivers/phy/ti/phy-gmii-sel.c @@ -512,7 +512,7 @@ static int phy_gmii_sel_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(base), "failed to get base memory resource\n"); - priv->regmap = regmap_init_mmio(dev, base, &phy_gmii_sel_regmap_cfg); + priv->regmap = devm_regmap_init_mmio(dev, base, &phy_gmii_sel_regmap_cfg); if (IS_ERR(priv->regmap)) return dev_err_probe(dev, PTR_ERR(priv->regmap), "Failed to get syscon\n"); From 028e8ca7b20fb7324f3e5db34ba8bd366d9d3acc Mon Sep 17 00:00:00 2001 From: Louis Chauvet Date: Thu, 27 Nov 2025 11:26:16 +0100 Subject: [PATCH 046/443] phy: rockchip: inno-usb2: fix disconnection in gadget mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the OTG USB port is used to power the SoC, configured as peripheral and used in gadget mode, there is a disconnection about 6 seconds after the gadget is configured and enumerated. The problem was observed on a Radxa Rock Pi S board, which can only be powered by the only USB-C connector. That connector is the only one usable in gadget mode. This implies the USB cable is connected from before boot and never disconnects while the kernel runs. The problem happens because of the PHY driver code flow, summarized as: * UDC start code (triggered via configfs at any time after boot) -> phy_init -> rockchip_usb2phy_init -> schedule_delayed_work(otg_sm_work [A], 6 sec) -> phy_power_on -> rockchip_usb2phy_power_on -> enable clock -> rockchip_usb2phy_reset * Now the gadget interface is up and running. * 6 seconds later otg_sm_work starts [A] -> rockchip_usb2phy_otg_sm_work(): if (B_IDLE state && VBUS present && ...): schedule_delayed_work(&rport->chg_work [B], 0); * immediately the chg_detect_work starts [B] -> rockchip_chg_detect_work(): if chg_state is UNDEFINED: if (!rport->suspended): rockchip_usb2phy_power_off() <--- [X] At [X], the PHY is powered off, causing a disconnection. This quickly triggers a new connection and following re-enumeration, but any connection that had been established during the 6 seconds is broken. The code already checks for !rport->suspended (which, somewhat counter-intuitively, means the PHY is powered on), so add a guard for VBUS as well to avoid a disconnection when a cable is connected. Fixes: 98898f3bc83c ("phy: rockchip-inno-usb2: support otg-port for rk3399") Cc: stable@vger.kernel.org Closes: https://lore.kernel.org/lkml/20250414185458.7767aabc@booty/ Signed-off-by: Louis Chauvet Co-developed-by: Luca Ceresoli Signed-off-by: Luca Ceresoli Reviewed-by: Théo Lebrun Link: https://patch.msgid.link/20251127-rk3308-fix-usb-gadget-phy-disconnect-v2-1-dac8a02cd2ca@bootlin.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index b0f23690ec30..0106d7b7ae24 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -821,14 +821,16 @@ static void rockchip_chg_detect_work(struct work_struct *work) container_of(work, struct rockchip_usb2phy_port, chg_work.work); struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); struct regmap *base = get_reg_base(rphy); - bool is_dcd, tmout, vout; + bool is_dcd, tmout, vout, vbus_attach; unsigned long delay; + vbus_attach = property_enabled(rphy->grf, &rport->port_cfg->utmi_bvalid); + dev_dbg(&rport->phy->dev, "chg detection work state = %d\n", rphy->chg_state); switch (rphy->chg_state) { case USB_CHG_STATE_UNDEFINED: - if (!rport->suspended) + if (!rport->suspended && !vbus_attach) rockchip_usb2phy_power_off(rport->phy); /* put the controller in non-driving mode */ property_enable(base, &rphy->phy_cfg->chg_det.opmode, false); From 7d8f725b79e35fa47e42c88716aad8711e1168d8 Mon Sep 17 00:00:00 2001 From: Luca Ceresoli Date: Thu, 27 Nov 2025 11:26:17 +0100 Subject: [PATCH 047/443] phy: rockchip: inno-usb2: fix communication disruption in gadget mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the OTG USB port is used to power to SoC, configured as peripheral and used in gadget mode, communication stops without notice about 6 seconds after the gadget is configured and enumerated. The problem was observed on a Radxa Rock Pi S board, which can only be powered by the only USB-C connector. That connector is the only one usable in gadget mode. This implies the USB cable is connected from before boot and never disconnects while the kernel runs. The related code flow in the PHY driver code can be summarized as: * the first time chg_detect_work starts (6 seconds after gadget is configured and enumerated) -> rockchip_chg_detect_work(): if chg_state is UNDEFINED: property_enable(base, &rphy->phy_cfg->chg_det.opmode, false); [Y] * rockchip_chg_detect_work() changes state and re-triggers itself a few times until it reaches the DETECTED state: -> rockchip_chg_detect_work(): if chg_state is DETECTED: property_enable(base, &rphy->phy_cfg->chg_det.opmode, true); [Z] At [Y] all existing communications stop. E.g. using a CDC serial gadget, the /dev/tty* devices are still present on both host and device, but no data is transferred anymore. The later call with a 'true' argument at [Z] does not restore it. Due to the lack of documentation, what chg_det.opmode does exactly is not clear, however by code inspection it seems reasonable that is disables something needed to keep the communication working, and testing proves that disabling these lines lets gadget mode keep working. So prevent changes to chg_det.opmode when there is a cable connected (VBUS present). Fixes: 98898f3bc83c ("phy: rockchip-inno-usb2: support otg-port for rk3399") Cc: stable@vger.kernel.org Closes: https://lore.kernel.org/lkml/20250414185458.7767aabc@booty/ Signed-off-by: Luca Ceresoli Reviewed-by: Théo Lebrun Link: https://patch.msgid.link/20251127-rk3308-fix-usb-gadget-phy-disconnect-v2-2-dac8a02cd2ca@bootlin.com Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 0106d7b7ae24..e5efae7b0135 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -833,7 +833,8 @@ static void rockchip_chg_detect_work(struct work_struct *work) if (!rport->suspended && !vbus_attach) rockchip_usb2phy_power_off(rport->phy); /* put the controller in non-driving mode */ - property_enable(base, &rphy->phy_cfg->chg_det.opmode, false); + if (!vbus_attach) + property_enable(base, &rphy->phy_cfg->chg_det.opmode, false); /* Start DCD processing stage 1 */ rockchip_chg_enable_dcd(rphy, true); rphy->chg_state = USB_CHG_STATE_WAIT_FOR_DCD; @@ -896,7 +897,8 @@ static void rockchip_chg_detect_work(struct work_struct *work) fallthrough; case USB_CHG_STATE_DETECTED: /* put the controller in normal mode */ - property_enable(base, &rphy->phy_cfg->chg_det.opmode, true); + if (!vbus_attach) + property_enable(base, &rphy->phy_cfg->chg_det.opmode, true); rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work); dev_dbg(&rport->phy->dev, "charger = %s\n", chg_to_string(rphy->chg_type)); From b246caa68037aa495390a60d080acaeb84f45fff Mon Sep 17 00:00:00 2001 From: Wayne Chang Date: Fri, 12 Dec 2025 11:21:16 +0800 Subject: [PATCH 048/443] phy: tegra: xusb: Explicitly configure HS_DISCON_LEVEL to 0x7 The USB2 Bias Pad Control register manages analog parameters for signal detection. Previously, the HS_DISCON_LEVEL relied on hardware reset values, which may lead to the detection failure. Explicitly configure HS_DISCON_LEVEL to 0x7. This ensures the disconnect threshold is sufficient to guarantee reliable detection. Fixes: bbf711682cd5 ("phy: tegra: xusb: Add Tegra186 support") Cc: stable@vger.kernel.org Signed-off-by: Wayne Chang Link: https://patch.msgid.link/20251212032116.768307-1-waynec@nvidia.com Signed-off-by: Vinod Koul --- drivers/phy/tegra/xusb-tegra186.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/xusb-tegra186.c index e818f6c3980e..bec9616c4a2e 100644 --- a/drivers/phy/tegra/xusb-tegra186.c +++ b/drivers/phy/tegra/xusb-tegra186.c @@ -84,6 +84,7 @@ #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x284 #define BIAS_PAD_PD BIT(11) #define HS_SQUELCH_LEVEL(x) (((x) & 0x7) << 0) +#define HS_DISCON_LEVEL(x) (((x) & 0x7) << 3) #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1 0x288 #define USB2_TRK_START_TIMER(x) (((x) & 0x7f) << 12) @@ -623,6 +624,8 @@ static void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl) value &= ~BIAS_PAD_PD; value &= ~HS_SQUELCH_LEVEL(~0); value |= HS_SQUELCH_LEVEL(priv->calib.hs_squelch); + value &= ~HS_DISCON_LEVEL(~0); + value |= HS_DISCON_LEVEL(0x7); padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); udelay(1); From 552dbf47a85c3b0eea1d7984ce3794b8d9b20e94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Fri, 19 Dec 2025 20:38:51 +0100 Subject: [PATCH 049/443] landlock: Fix formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Format with clang-format -i security/landlock/*.[ch] Cc: Christian Brauner Cc: Günther Noack Cc: Mateusz Guzik Fixes: b4dbfd8653b3 ("Coccinelle-based conversion to use ->i_state accessors") Link: https://lore.kernel.org/r/20251219193855.825889-5-mic@digikod.net Reviewed-by: Günther Noack Signed-off-by: Mickaël Salaün --- security/landlock/fs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/landlock/fs.c b/security/landlock/fs.c index fe794875ad46..e3c3a8a9ac27 100644 --- a/security/landlock/fs.c +++ b/security/landlock/fs.c @@ -1314,7 +1314,8 @@ static void hook_sb_delete(struct super_block *const sb) * second call to iput() for the same Landlock object. Also * checks I_NEW because such inode cannot be tied to an object. */ - if (inode_state_read(inode) & (I_FREEING | I_WILL_FREE | I_NEW)) { + if (inode_state_read(inode) & + (I_FREEING | I_WILL_FREE | I_NEW)) { spin_unlock(&inode->i_lock); continue; } From e4d82cbce2258f454634307fdabf33aa46b61ab0 Mon Sep 17 00:00:00 2001 From: Matthieu Buffet Date: Mon, 27 Oct 2025 20:07:26 +0100 Subject: [PATCH 050/443] landlock: Fix TCP handling of short AF_UNSPEC addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit current_check_access_socket() treats AF_UNSPEC addresses as AF_INET ones, and only later adds special case handling to allow connect(AF_UNSPEC), and on IPv4 sockets bind(AF_UNSPEC+INADDR_ANY). This would be fine except AF_UNSPEC addresses can be as short as a bare AF_UNSPEC sa_family_t field, and nothing more. The AF_INET code path incorrectly enforces a length of sizeof(struct sockaddr_in) instead. Move AF_UNSPEC edge case handling up inside the switch-case, before the address is (potentially incorrectly) treated as AF_INET. Fixes: fff69fb03dde ("landlock: Support network rules with TCP bind and connect") Signed-off-by: Matthieu Buffet Link: https://lore.kernel.org/r/20251027190726.626244-4-matthieu@buffet.re Signed-off-by: Mickaël Salaün --- security/landlock/net.c | 118 +++++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 51 deletions(-) diff --git a/security/landlock/net.c b/security/landlock/net.c index 1f3915a90a80..e6367e30e5b0 100644 --- a/security/landlock/net.c +++ b/security/landlock/net.c @@ -71,6 +71,61 @@ static int current_check_access_socket(struct socket *const sock, switch (address->sa_family) { case AF_UNSPEC: + if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) { + /* + * Connecting to an address with AF_UNSPEC dissolves + * the TCP association, which have the same effect as + * closing the connection while retaining the socket + * object (i.e., the file descriptor). As for dropping + * privileges, closing connections is always allowed. + * + * For a TCP access control system, this request is + * legitimate. Let the network stack handle potential + * inconsistencies and return -EINVAL if needed. + */ + return 0; + } else if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP) { + /* + * Binding to an AF_UNSPEC address is treated + * differently by IPv4 and IPv6 sockets. The socket's + * family may change under our feet due to + * setsockopt(IPV6_ADDRFORM), but that's ok: we either + * reject entirely or require + * %LANDLOCK_ACCESS_NET_BIND_TCP for the given port, so + * it cannot be used to bypass the policy. + * + * IPv4 sockets map AF_UNSPEC to AF_INET for + * retrocompatibility for bind accesses, only if the + * address is INADDR_ANY (cf. __inet_bind). IPv6 + * sockets always reject it. + * + * Checking the address is required to not wrongfully + * return -EACCES instead of -EAFNOSUPPORT or -EINVAL. + * We could return 0 and let the network stack handle + * these checks, but it is safer to return a proper + * error and test consistency thanks to kselftest. + */ + if (sock->sk->__sk_common.skc_family == AF_INET) { + const struct sockaddr_in *const sockaddr = + (struct sockaddr_in *)address; + + if (addrlen < sizeof(struct sockaddr_in)) + return -EINVAL; + + if (sockaddr->sin_addr.s_addr != + htonl(INADDR_ANY)) + return -EAFNOSUPPORT; + } else { + if (addrlen < SIN6_LEN_RFC2133) + return -EINVAL; + else + return -EAFNOSUPPORT; + } + } else { + WARN_ON_ONCE(1); + } + /* Only for bind(AF_UNSPEC+INADDR_ANY) on IPv4 socket. */ + fallthrough; case AF_INET: { const struct sockaddr_in *addr4; @@ -119,57 +174,18 @@ static int current_check_access_socket(struct socket *const sock, return 0; } - /* Specific AF_UNSPEC handling. */ - if (address->sa_family == AF_UNSPEC) { - /* - * Connecting to an address with AF_UNSPEC dissolves the TCP - * association, which have the same effect as closing the - * connection while retaining the socket object (i.e., the file - * descriptor). As for dropping privileges, closing - * connections is always allowed. - * - * For a TCP access control system, this request is legitimate. - * Let the network stack handle potential inconsistencies and - * return -EINVAL if needed. - */ - if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) - return 0; - - /* - * For compatibility reason, accept AF_UNSPEC for bind - * accesses (mapped to AF_INET) only if the address is - * INADDR_ANY (cf. __inet_bind). Checking the address is - * required to not wrongfully return -EACCES instead of - * -EAFNOSUPPORT. - * - * We could return 0 and let the network stack handle these - * checks, but it is safer to return a proper error and test - * consistency thanks to kselftest. - */ - if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP) { - /* addrlen has already been checked for AF_UNSPEC. */ - const struct sockaddr_in *const sockaddr = - (struct sockaddr_in *)address; - - if (sock->sk->__sk_common.skc_family != AF_INET) - return -EINVAL; - - if (sockaddr->sin_addr.s_addr != htonl(INADDR_ANY)) - return -EAFNOSUPPORT; - } - } else { - /* - * Checks sa_family consistency to not wrongfully return - * -EACCES instead of -EINVAL. Valid sa_family changes are - * only (from AF_INET or AF_INET6) to AF_UNSPEC. - * - * We could return 0 and let the network stack handle this - * check, but it is safer to return a proper error and test - * consistency thanks to kselftest. - */ - if (address->sa_family != sock->sk->__sk_common.skc_family) - return -EINVAL; - } + /* + * Checks sa_family consistency to not wrongfully return + * -EACCES instead of -EINVAL. Valid sa_family changes are + * only (from AF_INET or AF_INET6) to AF_UNSPEC. + * + * We could return 0 and let the network stack handle this + * check, but it is safer to return a proper error and test + * consistency thanks to kselftest. + */ + if (address->sa_family != sock->sk->__sk_common.skc_family && + address->sa_family != AF_UNSPEC) + return -EINVAL; id.key.data = (__force uintptr_t)port; BUILD_BUG_ON(sizeof(port) > sizeof(id.key.data)); From bd09d9a05cf04028f639e209b416bacaeffd4909 Mon Sep 17 00:00:00 2001 From: Matthieu Buffet Date: Mon, 27 Oct 2025 20:07:24 +0100 Subject: [PATCH 051/443] selftests/landlock: Fix TCP bind(AF_UNSPEC) test case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The nominal error code for bind(AF_UNSPEC) on an IPv6 socket is -EAFNOSUPPORT, not -EINVAL. -EINVAL is only returned when the supplied address struct is too short, which happens to be the case in current selftests because they treat AF_UNSPEC like IPv4 sockets do: as an alias for AF_INET (which is a 16-byte struct instead of the 24 bytes required by IPv6 sockets). Make the union large enough for any address (by adding struct sockaddr_storage to the union), and make AF_UNSPEC addresses large enough for any family. Test for -EAFNOSUPPORT instead, and add a dedicated test case for truncated inputs with -EINVAL. Fixes: a549d055a22e ("selftests/landlock: Add network tests") Signed-off-by: Matthieu Buffet Link: https://lore.kernel.org/r/20251027190726.626244-2-matthieu@buffet.re Signed-off-by: Mickaël Salaün --- tools/testing/selftests/landlock/common.h | 1 + tools/testing/selftests/landlock/net_test.c | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/landlock/common.h b/tools/testing/selftests/landlock/common.h index 230b75f6015b..90551650299c 100644 --- a/tools/testing/selftests/landlock/common.h +++ b/tools/testing/selftests/landlock/common.h @@ -237,6 +237,7 @@ struct service_fixture { struct sockaddr_un unix_addr; socklen_t unix_addr_len; }; + struct sockaddr_storage _largest; }; }; diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c index 2a45208551e6..3bbc0508420b 100644 --- a/tools/testing/selftests/landlock/net_test.c +++ b/tools/testing/selftests/landlock/net_test.c @@ -121,6 +121,10 @@ static socklen_t get_addrlen(const struct service_fixture *const srv, { switch (srv->protocol.domain) { case AF_UNSPEC: + if (minimal) + return sizeof(sa_family_t); + return sizeof(struct sockaddr_storage); + case AF_INET: return sizeof(srv->ipv4_addr); @@ -758,6 +762,11 @@ TEST_F(protocol, bind_unspec) bind_fd = socket_variant(&self->srv0); ASSERT_LE(0, bind_fd); + /* Tries to bind with too small addrlen. */ + EXPECT_EQ(-EINVAL, bind_variant_addrlen( + bind_fd, &self->unspec_any0, + get_addrlen(&self->unspec_any0, true) - 1)); + /* Allowed bind on AF_UNSPEC/INADDR_ANY. */ ret = bind_variant(bind_fd, &self->unspec_any0); if (variant->prot.domain == AF_INET) { @@ -766,6 +775,8 @@ TEST_F(protocol, bind_unspec) TH_LOG("Failed to bind to unspec/any socket: %s", strerror(errno)); } + } else if (variant->prot.domain == AF_INET6) { + EXPECT_EQ(-EAFNOSUPPORT, ret); } else { EXPECT_EQ(-EINVAL, ret); } @@ -792,6 +803,8 @@ TEST_F(protocol, bind_unspec) } else { EXPECT_EQ(0, ret); } + } else if (variant->prot.domain == AF_INET6) { + EXPECT_EQ(-EAFNOSUPPORT, ret); } else { EXPECT_EQ(-EINVAL, ret); } @@ -801,7 +814,8 @@ TEST_F(protocol, bind_unspec) bind_fd = socket_variant(&self->srv0); ASSERT_LE(0, bind_fd); ret = bind_variant(bind_fd, &self->unspec_srv0); - if (variant->prot.domain == AF_INET) { + if (variant->prot.domain == AF_INET || + variant->prot.domain == AF_INET6) { EXPECT_EQ(-EAFNOSUPPORT, ret); } else { EXPECT_EQ(-EINVAL, ret) From 6685201ebfacff0c889bcd569181fa6e8af5575e Mon Sep 17 00:00:00 2001 From: Matthieu Buffet Date: Mon, 27 Oct 2025 20:07:25 +0100 Subject: [PATCH 052/443] selftests/landlock: Add missing connect(minimal AF_UNSPEC) test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit connect_variant(unspec_any0) is called twice. Both calls end up in connect_variant_addrlen() with an address length of get_addrlen(minimal=false). However, the connect() syscall and its variants (e.g. iouring/compat) accept much shorter addresses of 4 bytes and that behaviour was not tested. Replace one of these calls with one using a minimal address length (just a bare sa_family=AF_UNSPEC field with no actual address). Also add a call using a truncated address for good measure. Signed-off-by: Matthieu Buffet Link: https://lore.kernel.org/r/20251027190726.626244-3-matthieu@buffet.re Signed-off-by: Mickaël Salaün --- tools/testing/selftests/landlock/net_test.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c index 3bbc0508420b..b34b139b3f89 100644 --- a/tools/testing/selftests/landlock/net_test.c +++ b/tools/testing/selftests/landlock/net_test.c @@ -906,7 +906,19 @@ TEST_F(protocol, connect_unspec) EXPECT_EQ(0, close(ruleset_fd)); } - ret = connect_variant(connect_fd, &self->unspec_any0); + /* Try to re-disconnect with a truncated address struct. */ + EXPECT_EQ(-EINVAL, + connect_variant_addrlen( + connect_fd, &self->unspec_any0, + get_addrlen(&self->unspec_any0, true) - 1)); + + /* + * Re-disconnect, with a minimal sockaddr struct (just a + * bare af_family=AF_UNSPEC field). + */ + ret = connect_variant_addrlen(connect_fd, &self->unspec_any0, + get_addrlen(&self->unspec_any0, + true)); if (self->srv0.protocol.domain == AF_UNIX && self->srv0.protocol.type == SOCK_STREAM) { EXPECT_EQ(-EINVAL, ret); From e1a57c33590a50a6639798e60a597af4a23b0340 Mon Sep 17 00:00:00 2001 From: Matthieu Buffet Date: Mon, 1 Dec 2025 01:36:31 +0100 Subject: [PATCH 053/443] selftests/landlock: Remove invalid unix socket bind() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove bind() call on a client socket that doesn't make sense. Since strlen(cli_un.sun_path) returns a random value depending on stack garbage, that many uninitialized bytes are read from the stack as an unix socket address. This creates random test failures due to the bind address being invalid or already in use if the same stack value comes up twice. Fixes: f83d51a5bdfe ("selftests/landlock: Check IOCTL restrictions for named UNIX domain sockets") Signed-off-by: Matthieu Buffet Reviewed-by: Günther Noack Link: https://lore.kernel.org/r/20251201003631.190817-1-matthieu@buffet.re Signed-off-by: Mickaël Salaün --- tools/testing/selftests/landlock/fs_test.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index eee814e09dd7..7d378bdf3bce 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -4391,9 +4391,6 @@ TEST_F_FORK(layout1, named_unix_domain_socket_ioctl) cli_fd = socket(AF_UNIX, SOCK_STREAM, 0); ASSERT_LE(0, cli_fd); - size = offsetof(struct sockaddr_un, sun_path) + strlen(cli_un.sun_path); - ASSERT_EQ(0, bind(cli_fd, (struct sockaddr *)&cli_un, size)); - bzero(&cli_un, sizeof(cli_un)); cli_un.sun_family = AF_UNIX; strncpy(cli_un.sun_path, path, sizeof(cli_un.sun_path)); From e4aa4461d4acb922ef45785581232f0588a6eea8 Mon Sep 17 00:00:00 2001 From: Matthieu Buffet Date: Tue, 2 Dec 2025 22:51:41 +0100 Subject: [PATCH 054/443] selftests/landlock: NULL-terminate unix pathname addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The size of Unix pathname addresses is computed in selftests using offsetof(struct sockaddr_un, sun_path) + strlen(xxx). It should have been that +1, which makes addresses passed to the libc and kernel non-NULL-terminated. unix_mkname_bsd() fixes that in Linux so there is no harm, but just using sizeof(the address struct) should improve readability. Signed-off-by: Matthieu Buffet Reviewed-by: Günther Noack Link: https://lore.kernel.org/r/20251202215141.689986-1-matthieu@buffet.re Signed-off-by: Mickaël Salaün --- tools/testing/selftests/landlock/fs_test.c | 24 +++++++++---------- .../landlock/scoped_abstract_unix_test.c | 21 +++++++--------- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 7d378bdf3bce..76491ba54dce 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -4362,22 +4362,24 @@ TEST_F_FORK(layout1, named_unix_domain_socket_ioctl) { const char *const path = file1_s1d1; int srv_fd, cli_fd, ruleset_fd; - socklen_t size; - struct sockaddr_un srv_un, cli_un; + struct sockaddr_un srv_un = { + .sun_family = AF_UNIX, + }; + struct sockaddr_un cli_un = { + .sun_family = AF_UNIX, + }; const struct landlock_ruleset_attr attr = { .handled_access_fs = LANDLOCK_ACCESS_FS_IOCTL_DEV, }; /* Sets up a server */ - srv_un.sun_family = AF_UNIX; - strncpy(srv_un.sun_path, path, sizeof(srv_un.sun_path)); - ASSERT_EQ(0, unlink(path)); srv_fd = socket(AF_UNIX, SOCK_STREAM, 0); ASSERT_LE(0, srv_fd); - size = offsetof(struct sockaddr_un, sun_path) + strlen(srv_un.sun_path); - ASSERT_EQ(0, bind(srv_fd, (struct sockaddr *)&srv_un, size)); + strncpy(srv_un.sun_path, path, sizeof(srv_un.sun_path)); + ASSERT_EQ(0, bind(srv_fd, (struct sockaddr *)&srv_un, sizeof(srv_un))); + ASSERT_EQ(0, listen(srv_fd, 10 /* qlen */)); /* Enables Landlock. */ @@ -4387,16 +4389,12 @@ TEST_F_FORK(layout1, named_unix_domain_socket_ioctl) ASSERT_EQ(0, close(ruleset_fd)); /* Sets up a client connection to it */ - cli_un.sun_family = AF_UNIX; cli_fd = socket(AF_UNIX, SOCK_STREAM, 0); ASSERT_LE(0, cli_fd); - bzero(&cli_un, sizeof(cli_un)); - cli_un.sun_family = AF_UNIX; strncpy(cli_un.sun_path, path, sizeof(cli_un.sun_path)); - size = offsetof(struct sockaddr_un, sun_path) + strlen(cli_un.sun_path); - - ASSERT_EQ(0, connect(cli_fd, (struct sockaddr *)&cli_un, size)); + ASSERT_EQ(0, + connect(cli_fd, (struct sockaddr *)&cli_un, sizeof(cli_un))); /* FIONREAD and other IOCTLs should not be forbidden. */ EXPECT_EQ(0, test_fionread_ioctl(cli_fd)); diff --git a/tools/testing/selftests/landlock/scoped_abstract_unix_test.c b/tools/testing/selftests/landlock/scoped_abstract_unix_test.c index 6825082c079c..2cdf1ba07016 100644 --- a/tools/testing/selftests/landlock/scoped_abstract_unix_test.c +++ b/tools/testing/selftests/landlock/scoped_abstract_unix_test.c @@ -779,7 +779,6 @@ FIXTURE_TEARDOWN(various_address_sockets) TEST_F(various_address_sockets, scoped_pathname_sockets) { - socklen_t size_stream, size_dgram; pid_t child; int status; char buf_child, buf_parent; @@ -798,12 +797,8 @@ TEST_F(various_address_sockets, scoped_pathname_sockets) /* Pathname address. */ snprintf(stream_pathname_addr.sun_path, sizeof(stream_pathname_addr.sun_path), "%s", stream_path); - size_stream = offsetof(struct sockaddr_un, sun_path) + - strlen(stream_pathname_addr.sun_path); snprintf(dgram_pathname_addr.sun_path, sizeof(dgram_pathname_addr.sun_path), "%s", dgram_path); - size_dgram = offsetof(struct sockaddr_un, sun_path) + - strlen(dgram_pathname_addr.sun_path); /* Abstract address. */ memset(&stream_abstract_addr, 0, sizeof(stream_abstract_addr)); @@ -841,8 +836,9 @@ TEST_F(various_address_sockets, scoped_pathname_sockets) /* Connects with pathname sockets. */ stream_pathname_socket = socket(AF_UNIX, SOCK_STREAM, 0); ASSERT_LE(0, stream_pathname_socket); - ASSERT_EQ(0, connect(stream_pathname_socket, - &stream_pathname_addr, size_stream)); + ASSERT_EQ(0, + connect(stream_pathname_socket, &stream_pathname_addr, + sizeof(stream_pathname_addr))); ASSERT_EQ(1, write(stream_pathname_socket, "b", 1)); EXPECT_EQ(0, close(stream_pathname_socket)); @@ -850,12 +846,13 @@ TEST_F(various_address_sockets, scoped_pathname_sockets) dgram_pathname_socket = socket(AF_UNIX, SOCK_DGRAM, 0); ASSERT_LE(0, dgram_pathname_socket); err = sendto(dgram_pathname_socket, "c", 1, 0, - &dgram_pathname_addr, size_dgram); + &dgram_pathname_addr, sizeof(dgram_pathname_addr)); EXPECT_EQ(1, err); /* Sends with connection. */ - ASSERT_EQ(0, connect(dgram_pathname_socket, - &dgram_pathname_addr, size_dgram)); + ASSERT_EQ(0, + connect(dgram_pathname_socket, &dgram_pathname_addr, + sizeof(dgram_pathname_addr))); ASSERT_EQ(1, write(dgram_pathname_socket, "d", 1)); EXPECT_EQ(0, close(dgram_pathname_socket)); @@ -910,13 +907,13 @@ TEST_F(various_address_sockets, scoped_pathname_sockets) stream_pathname_socket = socket(AF_UNIX, SOCK_STREAM, 0); ASSERT_LE(0, stream_pathname_socket); ASSERT_EQ(0, bind(stream_pathname_socket, &stream_pathname_addr, - size_stream)); + sizeof(stream_pathname_addr))); ASSERT_EQ(0, listen(stream_pathname_socket, backlog)); dgram_pathname_socket = socket(AF_UNIX, SOCK_DGRAM, 0); ASSERT_LE(0, dgram_pathname_socket); ASSERT_EQ(0, bind(dgram_pathname_socket, &dgram_pathname_addr, - size_dgram)); + sizeof(dgram_pathname_addr))); /* Sets up abstract servers. */ stream_abstract_socket = socket(AF_UNIX, SOCK_STREAM, 0); From 29fbfa46e4287c596bdc77e2c599e3a1bbf8bb67 Mon Sep 17 00:00:00 2001 From: Tingmao Wang Date: Sat, 6 Dec 2025 17:11:06 +0000 Subject: [PATCH 055/443] landlock: Fix wrong type usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I think, based on my best understanding, that this type is likely a typo (even though in the end both are u16) Signed-off-by: Tingmao Wang Fixes: 2fc80c69df82 ("landlock: Log file-related denials") Reviewed-by: Günther Noack Link: https://lore.kernel.org/r/7339ad7b47f998affd84ca629a334a71f913616d.1765040503.git.m@maowtm.org Signed-off-by: Mickaël Salaün --- security/landlock/audit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/landlock/audit.c b/security/landlock/audit.c index c52d079cdb77..e899995f1fd5 100644 --- a/security/landlock/audit.c +++ b/security/landlock/audit.c @@ -191,7 +191,7 @@ static size_t get_denied_layer(const struct landlock_ruleset *const domain, long youngest_layer = -1; for_each_set_bit(access_bit, &access_req, layer_masks_size) { - const access_mask_t mask = (*layer_masks)[access_bit]; + const layer_mask_t mask = (*layer_masks)[access_bit]; long layer; if (!mask) From 60207df2ebf3b740770aa605173d2d7d19ee66b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Fri, 19 Dec 2025 20:38:47 +0100 Subject: [PATCH 056/443] landlock: Remove useless include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove useless audit.h include. Cc: Günther Noack Fixes: 33e65b0d3add ("landlock: Add AUDIT_LANDLOCK_ACCESS and log ptrace denials") Link: https://lore.kernel.org/r/20251219193855.825889-1-mic@digikod.net Reviewed-by: Günther Noack Signed-off-by: Mickaël Salaün --- security/landlock/ruleset.c | 1 - 1 file changed, 1 deletion(-) diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c index dfcdc19ea268..0a5b0c76b3f7 100644 --- a/security/landlock/ruleset.c +++ b/security/landlock/ruleset.c @@ -23,7 +23,6 @@ #include #include "access.h" -#include "audit.h" #include "domain.h" #include "limits.h" #include "object.h" From 03a0ff99ef2e4958141f7b4c573722fc8f4b9539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Fri, 19 Dec 2025 20:38:48 +0100 Subject: [PATCH 057/443] landlock: Improve erratum documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve description about scoped signal handling. Reported-by: Günther Noack Link: https://lore.kernel.org/r/20251219193855.825889-2-mic@digikod.net Reviewed-by: Günther Noack Signed-off-by: Mickaël Salaün --- security/landlock/errata/abi-6.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/landlock/errata/abi-6.h b/security/landlock/errata/abi-6.h index df7bc0e1fdf4..5113a829f87e 100644 --- a/security/landlock/errata/abi-6.h +++ b/security/landlock/errata/abi-6.h @@ -9,7 +9,7 @@ * This fix addresses an issue where signal scoping was overly restrictive, * preventing sandboxed threads from signaling other threads within the same * process if they belonged to different domains. Because threads are not - * security boundaries, user space might assume that any thread within the same + * security boundaries, user space might assume that all threads within the same * process can send signals between themselves (see :manpage:`nptl(7)` and * :manpage:`libpsx(3)`). Consistent with :manpage:`ptrace(2)` behavior, direct * interaction between threads of the same process should always be allowed. From aa9877d74c07045f712a4ec82105505e69cd5efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Fri, 19 Dec 2025 20:38:49 +0100 Subject: [PATCH 058/443] landlock: Clean up hook_ptrace_access_check() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make variable's scope minimal in hook_ptrace_access_check(). Cc: Günther Noack Link: https://lore.kernel.org/r/20251219193855.825889-3-mic@digikod.net Reviewed-by: Günther Noack Signed-off-by: Mickaël Salaün --- security/landlock/task.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/landlock/task.c b/security/landlock/task.c index 2385017418ca..bf4ed15a7f01 100644 --- a/security/landlock/task.c +++ b/security/landlock/task.c @@ -86,7 +86,6 @@ static int hook_ptrace_access_check(struct task_struct *const child, const unsigned int mode) { const struct landlock_cred_security *parent_subject; - const struct landlock_ruleset *child_dom; int err; /* Quick return for non-landlocked tasks. */ @@ -96,7 +95,8 @@ static int hook_ptrace_access_check(struct task_struct *const child, scoped_guard(rcu) { - child_dom = landlock_get_task_domain(child); + const struct landlock_ruleset *const child_dom = + landlock_get_task_domain(child); err = domain_ptrace(parent_subject->domain, child_dom); } From 6548fb521822a5c0a688e423df28b2248a59543b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Fri, 19 Dec 2025 20:38:50 +0100 Subject: [PATCH 059/443] landlock: Fix spelling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Günther Noack Link: https://lore.kernel.org/r/20251219193855.825889-4-mic@digikod.net Reviewed-by: Günther Noack Signed-off-by: Mickaël Salaün --- security/landlock/domain.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/landlock/domain.h b/security/landlock/domain.h index 7fb70b25f85a..621f054c9a2b 100644 --- a/security/landlock/domain.h +++ b/security/landlock/domain.h @@ -97,7 +97,7 @@ struct landlock_hierarchy { */ atomic64_t num_denials; /** - * @id: Landlock domain ID, sets once at domain creation time. + * @id: Landlock domain ID, set once at domain creation time. */ u64 id; /** From 602acfb541195eb35584d7a3fc7d1db676f059bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Fri, 19 Dec 2025 15:22:59 +0100 Subject: [PATCH 060/443] landlock: Optimize stack usage when !CONFIG_AUDIT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Until now, each landlock_request struct were allocated on the stack, even if not really used, because is_access_to_paths_allowed() unconditionally modified the passed references. Even if the changed landlock_request variables are not used, the compiler is not smart enough to detect this case. To avoid this issue, explicitly disable the related code when CONFIG_AUDIT is not set, which enables elision of log_request_parent* and associated caller's stack variables thanks to dead code elimination. This makes it possible to reduce the stack frame by 32 bytes for the path_link and path_rename hooks, and by 20 bytes for most other filesystem hooks. Here is a summary of scripts/stackdelta before and after this change when CONFIG_AUDIT is disabled: current_check_refer_path 560 320 -240 current_check_access_path 328 184 -144 hook_file_open 328 184 -144 is_access_to_paths_allowed 376 360 -16 Also, add extra pointer checks to be more future-proof. Cc: Günther Noack Reported-by: Tingmao Wang Closes: https://lore.kernel.org/r/eb86863b-53b0-460b-b223-84dd31d765b9@maowtm.org Fixes: 2fc80c69df82 ("landlock: Log file-related denials") Link: https://lore.kernel.org/r/20251219142302.744917-2-mic@digikod.net Reviewed-by: Günther Noack [mic: Improve stack usage measurement accuracy with scripts/stackdelta] Signed-off-by: Mickaël Salaün --- security/landlock/fs.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/security/landlock/fs.c b/security/landlock/fs.c index e3c3a8a9ac27..8205673c8b1c 100644 --- a/security/landlock/fs.c +++ b/security/landlock/fs.c @@ -939,7 +939,12 @@ jump_up: } path_put(&walker_path); - if (!allowed_parent1) { + /* + * Check CONFIG_AUDIT to enable elision of log_request_parent* and + * associated caller's stack variables thanks to dead code elimination. + */ +#ifdef CONFIG_AUDIT + if (!allowed_parent1 && log_request_parent1) { log_request_parent1->type = LANDLOCK_REQUEST_FS_ACCESS; log_request_parent1->audit.type = LSM_AUDIT_DATA_PATH; log_request_parent1->audit.u.path = *path; @@ -949,7 +954,7 @@ jump_up: ARRAY_SIZE(*layer_masks_parent1); } - if (!allowed_parent2) { + if (!allowed_parent2 && log_request_parent2) { log_request_parent2->type = LANDLOCK_REQUEST_FS_ACCESS; log_request_parent2->audit.type = LSM_AUDIT_DATA_PATH; log_request_parent2->audit.u.path = *path; @@ -958,6 +963,8 @@ jump_up: log_request_parent2->layer_masks_size = ARRAY_SIZE(*layer_masks_parent2); } +#endif /* CONFIG_AUDIT */ + return allowed_parent1 && allowed_parent2; } From 14c00e30d3a29a7fb6053fcaa54aeb6c07fb1055 Mon Sep 17 00:00:00 2001 From: Tingmao Wang Date: Sun, 28 Dec 2025 01:27:31 +0000 Subject: [PATCH 061/443] selftests/landlock: Fix typo in fs_test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tingmao Wang Link: https://lore.kernel.org/r/62d18e06eeb26f62bc49d24c4467b3793c5ba32b.1766885035.git.m@maowtm.org Signed-off-by: Mickaël Salaün --- tools/testing/selftests/landlock/fs_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 76491ba54dce..37a5a3df712e 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -7069,8 +7069,8 @@ static int matches_log_fs_extra(struct __test_metadata *const _metadata, return -E2BIG; /* - * It is assume that absolute_path does not contain control characters nor - * spaces, see audit_string_contains_control(). + * It is assumed that absolute_path does not contain control + * characters nor spaces, see audit_string_contains_control(). */ absolute_path = realpath(path, NULL); if (!absolute_path) From 7aa593d8fb64b884bf00c13e01387b0733f3d786 Mon Sep 17 00:00:00 2001 From: Tingmao Wang Date: Sun, 28 Dec 2025 01:27:32 +0000 Subject: [PATCH 062/443] selftests/landlock: Fix missing semicolon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing semicolon after EXPECT_EQ(0, close(stream_server_child)) in the scoped_vs_unscoped test. I suspect currently it's just not executing the close statement after the line, but this causes no observable difference. Fixes: fefcf0f7cf47 ("selftests/landlock: Test abstract UNIX socket scoping") Cc: Tahera Fahimi Signed-off-by: Tingmao Wang Link: https://lore.kernel.org/r/d9e968e4cd4ecc9bf487593d7b7220bffbb3b5f5.1766885035.git.m@maowtm.org Signed-off-by: Mickaël Salaün --- tools/testing/selftests/landlock/scoped_abstract_unix_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/landlock/scoped_abstract_unix_test.c b/tools/testing/selftests/landlock/scoped_abstract_unix_test.c index 2cdf1ba07016..72f97648d4a7 100644 --- a/tools/testing/selftests/landlock/scoped_abstract_unix_test.c +++ b/tools/testing/selftests/landlock/scoped_abstract_unix_test.c @@ -543,7 +543,7 @@ TEST_F(scoped_vs_unscoped, unix_scoping) ASSERT_EQ(1, write(pipe_child[1], ".", 1)); ASSERT_EQ(grand_child, waitpid(grand_child, &status, 0)); - EXPECT_EQ(0, close(stream_server_child)) + EXPECT_EQ(0, close(stream_server_child)); EXPECT_EQ(0, close(dgram_server_child)); return; } From 55dc93a7c2717311d48ca0a47c5f8c1b0755a115 Mon Sep 17 00:00:00 2001 From: Tingmao Wang Date: Sun, 28 Dec 2025 01:27:34 +0000 Subject: [PATCH 063/443] selftests/landlock: Use scoped_base_variants.h for ptrace_test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ptrace_test.c currently contains a duplicated version of the scoped_domains fixture variants. This patch removes that and make it use the shared scoped_base_variants.h instead, like in scoped_abstract_unix_test and scoped_signal_test. This required renaming the hierarchy fixture to scoped_domains, but the test is otherwise the same. Cc: Tahera Fahimi Signed-off-by: Tingmao Wang Link: https://lore.kernel.org/r/48148f0134f95f819a25277486a875a6fd88ecf9.1766885035.git.m@maowtm.org Signed-off-by: Mickaël Salaün --- .../testing/selftests/landlock/ptrace_test.c | 154 +----------------- .../selftests/landlock/scoped_base_variants.h | 9 +- 2 files changed, 12 insertions(+), 151 deletions(-) diff --git a/tools/testing/selftests/landlock/ptrace_test.c b/tools/testing/selftests/landlock/ptrace_test.c index 4e356334ecb7..4f64c90583cd 100644 --- a/tools/testing/selftests/landlock/ptrace_test.c +++ b/tools/testing/selftests/landlock/ptrace_test.c @@ -86,16 +86,9 @@ static int get_yama_ptrace_scope(void) } /* clang-format off */ -FIXTURE(hierarchy) {}; +FIXTURE(scoped_domains) {}; /* clang-format on */ -FIXTURE_VARIANT(hierarchy) -{ - const bool domain_both; - const bool domain_parent; - const bool domain_child; -}; - /* * Test multiple tracing combinations between a parent process P1 and a child * process P2. @@ -104,155 +97,18 @@ FIXTURE_VARIANT(hierarchy) * restriction is enforced in addition to any Landlock check, which means that * all P2 requests to trace P1 would be denied. */ +#include "scoped_base_variants.h" -/* - * No domain - * - * P1-. P1 -> P2 : allow - * \ P2 -> P1 : allow - * 'P2 - */ -/* clang-format off */ -FIXTURE_VARIANT_ADD(hierarchy, allow_without_domain) { - /* clang-format on */ - .domain_both = false, - .domain_parent = false, - .domain_child = false, -}; - -/* - * Child domain - * - * P1--. P1 -> P2 : allow - * \ P2 -> P1 : deny - * .'-----. - * | P2 | - * '------' - */ -/* clang-format off */ -FIXTURE_VARIANT_ADD(hierarchy, allow_with_one_domain) { - /* clang-format on */ - .domain_both = false, - .domain_parent = false, - .domain_child = true, -}; - -/* - * Parent domain - * .------. - * | P1 --. P1 -> P2 : deny - * '------' \ P2 -> P1 : allow - * ' - * P2 - */ -/* clang-format off */ -FIXTURE_VARIANT_ADD(hierarchy, deny_with_parent_domain) { - /* clang-format on */ - .domain_both = false, - .domain_parent = true, - .domain_child = false, -}; - -/* - * Parent + child domain (siblings) - * .------. - * | P1 ---. P1 -> P2 : deny - * '------' \ P2 -> P1 : deny - * .---'--. - * | P2 | - * '------' - */ -/* clang-format off */ -FIXTURE_VARIANT_ADD(hierarchy, deny_with_sibling_domain) { - /* clang-format on */ - .domain_both = false, - .domain_parent = true, - .domain_child = true, -}; - -/* - * Same domain (inherited) - * .-------------. - * | P1----. | P1 -> P2 : allow - * | \ | P2 -> P1 : allow - * | ' | - * | P2 | - * '-------------' - */ -/* clang-format off */ -FIXTURE_VARIANT_ADD(hierarchy, allow_sibling_domain) { - /* clang-format on */ - .domain_both = true, - .domain_parent = false, - .domain_child = false, -}; - -/* - * Inherited + child domain - * .-----------------. - * | P1----. | P1 -> P2 : allow - * | \ | P2 -> P1 : deny - * | .-'----. | - * | | P2 | | - * | '------' | - * '-----------------' - */ -/* clang-format off */ -FIXTURE_VARIANT_ADD(hierarchy, allow_with_nested_domain) { - /* clang-format on */ - .domain_both = true, - .domain_parent = false, - .domain_child = true, -}; - -/* - * Inherited + parent domain - * .-----------------. - * |.------. | P1 -> P2 : deny - * || P1 ----. | P2 -> P1 : allow - * |'------' \ | - * | ' | - * | P2 | - * '-----------------' - */ -/* clang-format off */ -FIXTURE_VARIANT_ADD(hierarchy, deny_with_nested_and_parent_domain) { - /* clang-format on */ - .domain_both = true, - .domain_parent = true, - .domain_child = false, -}; - -/* - * Inherited + parent and child domain (siblings) - * .-----------------. - * | .------. | P1 -> P2 : deny - * | | P1 . | P2 -> P1 : deny - * | '------'\ | - * | \ | - * | .--'---. | - * | | P2 | | - * | '------' | - * '-----------------' - */ -/* clang-format off */ -FIXTURE_VARIANT_ADD(hierarchy, deny_with_forked_domain) { - /* clang-format on */ - .domain_both = true, - .domain_parent = true, - .domain_child = true, -}; - -FIXTURE_SETUP(hierarchy) +FIXTURE_SETUP(scoped_domains) { } -FIXTURE_TEARDOWN(hierarchy) +FIXTURE_TEARDOWN(scoped_domains) { } /* Test PTRACE_TRACEME and PTRACE_ATTACH for parent and child. */ -TEST_F(hierarchy, trace) +TEST_F(scoped_domains, trace) { pid_t child, parent; int status, err_proc_read; diff --git a/tools/testing/selftests/landlock/scoped_base_variants.h b/tools/testing/selftests/landlock/scoped_base_variants.h index d3b1fa8a584e..7116728ebc68 100644 --- a/tools/testing/selftests/landlock/scoped_base_variants.h +++ b/tools/testing/selftests/landlock/scoped_base_variants.h @@ -1,8 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Landlock scoped_domains variants + * Landlock scoped_domains test variant definition. * - * See the hierarchy variants from ptrace_test.c + * This file defines a fixture variant "scoped_domains" that has all + * permutations of parent/child process being in separate or shared + * Landlock domain, or not being in a Landlock domain at all. + * + * Scoped access tests can include this file to avoid repeating these + * combinations. * * Copyright © 2017-2020 Mickaël Salaün * Copyright © 2019-2020 ANSSI From ef4536f15224418b327a7b5d5cae07dab042760f Mon Sep 17 00:00:00 2001 From: Tingmao Wang Date: Sun, 28 Dec 2025 01:27:35 +0000 Subject: [PATCH 064/443] landlock: Improve the comment for domain_is_scoped MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently it is not obvious what "scoped" mean, and the fact that the function returns true when access should be denied is slightly surprising and in need of documentation. Cc: Tahera Fahimi Signed-off-by: Tingmao Wang Link: https://lore.kernel.org/r/06393bc18aee5bc278df5ef31c64a05b742ebc10.1766885035.git.m@maowtm.org [mic: Fix formatting and improve consistency] Signed-off-by: Mickaël Salaün --- security/landlock/task.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/security/landlock/task.c b/security/landlock/task.c index bf4ed15a7f01..833bc0cfe5c9 100644 --- a/security/landlock/task.c +++ b/security/landlock/task.c @@ -166,15 +166,15 @@ static int hook_ptrace_traceme(struct task_struct *const parent) } /** - * domain_is_scoped - Checks if the client domain is scoped in the same - * domain as the server. + * domain_is_scoped - Check if an interaction from a client/sender to a + * server/receiver should be restricted based on scope controls. * * @client: IPC sender domain. * @server: IPC receiver domain. * @scope: The scope restriction criteria. * - * Returns: True if the @client domain is scoped to access the @server, - * unless the @server is also scoped in the same domain as @client. + * Returns: True if @server is in a different domain from @client, and @client + * is scoped to access @server (i.e. access should be denied). */ static bool domain_is_scoped(const struct landlock_ruleset *const client, const struct landlock_ruleset *const server, From d1a6f1259b0bb415107e83f6403a2ecb945d042f Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Wed, 19 Nov 2025 14:47:50 +0100 Subject: [PATCH 065/443] ARM: dts: microchip: lan966x: Fix the access to the PHYs for pcb8290 The problem is that the MDIO controller can't detect any of the PHYs. The reason is that the lan966x is not pulling high the GPIO 53 that is connected to the PHYs reset GPIO. Without doing this the PHYs are kept in reset. The mdio controller framework has the possibility to control a GPIO to release the reset of the PHYs. So take advantage of this and set line to be high before accessing the PHYs. Signed-off-by: Horatiu Vultur Reviewed-by: Claudiu Beznea Reviewed-by: Andrew Lunn Link: https://lore.kernel.org/r/20251119134750.394655-1-horatiu.vultur@microchip.com [claudiu.beznea: add microchip in patch title, s/possiblity/possibility in patch description] Signed-off-by: Claudiu Beznea --- arch/arm/boot/dts/microchip/lan966x-pcb8290.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/microchip/lan966x-pcb8290.dts b/arch/arm/boot/dts/microchip/lan966x-pcb8290.dts index 3b7577e48b46..50bd29572f3e 100644 --- a/arch/arm/boot/dts/microchip/lan966x-pcb8290.dts +++ b/arch/arm/boot/dts/microchip/lan966x-pcb8290.dts @@ -54,6 +54,7 @@ &mdio0 { pinctrl-0 = <&miim_a_pins>; pinctrl-names = "default"; + reset-gpios = <&gpio 53 GPIO_ACTIVE_LOW>; status = "okay"; ext_phy0: ethernet-phy@7 { From fb21116099bbea1fc59efa9207e63c4be390ab72 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 24 Dec 2025 12:55:34 +0100 Subject: [PATCH 066/443] phy: broadcom: ns-usb3: Fix Wvoid-pointer-to-enum-cast warning (again) "family" is an enum, thus cast of pointer on 64-bit compile test with clang W=1 causes: phy-bcm-ns-usb3.c:206:17: error: cast to smaller integer type 'enum bcm_ns_family' from 'const void *' [-Werror,-Wvoid-pointer-to-enum-cast] This was already fixed in commit bd6e74a2f0a0 ("phy: broadcom: ns-usb3: fix Wvoid-pointer-to-enum-cast warning") but then got bad in commit 21bf6fc47a1e ("phy: Use device_get_match_data()"). Note that after various discussions the preferred cast is via "unsigned long", not "uintptr_t". Fixes: 21bf6fc47a1e ("phy: Use device_get_match_data()") Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251224115533.154162-2-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Vinod Koul --- drivers/phy/broadcom/phy-bcm-ns-usb3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/broadcom/phy-bcm-ns-usb3.c b/drivers/phy/broadcom/phy-bcm-ns-usb3.c index 9f995e156f75..6e56498d0644 100644 --- a/drivers/phy/broadcom/phy-bcm-ns-usb3.c +++ b/drivers/phy/broadcom/phy-bcm-ns-usb3.c @@ -203,7 +203,7 @@ static int bcm_ns_usb3_mdio_probe(struct mdio_device *mdiodev) usb3->dev = dev; usb3->mdiodev = mdiodev; - usb3->family = (enum bcm_ns_family)device_get_match_data(dev); + usb3->family = (unsigned long)device_get_match_data(dev); syscon_np = of_parse_phandle(dev->of_node, "usb3-dmp-syscon", 0); err = of_address_to_resource(syscon_np, 0, &res); From d42d5715dcb559342ff356327b241c53a67584d9 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Tue, 23 Dec 2025 20:32:02 +0800 Subject: [PATCH 067/443] EDAC/i3200: Fix a resource leak in i3200_probe1() If edac_mc_alloc() fails, also unmap the window. [ bp: Use separate labels, turning it into the classic unwind pattern. ] Fixes: dd8ef1db87a4 ("edac: i3200 memory controller driver") Signed-off-by: Haoxiang Li Signed-off-by: Borislav Petkov (AMD) Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251223123202.1492038-1-lihaoxiang@isrc.iscas.ac.cn --- drivers/edac/i3200_edac.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c index afccdebf5ac1..6cade6d7ceff 100644 --- a/drivers/edac/i3200_edac.c +++ b/drivers/edac/i3200_edac.c @@ -358,10 +358,11 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx) layers[1].type = EDAC_MC_LAYER_CHANNEL; layers[1].size = nr_channels; layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, - sizeof(struct i3200_priv)); + + rc = -ENOMEM; + mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(struct i3200_priv)); if (!mci) - return -ENOMEM; + goto unmap; edac_dbg(3, "MC: init mci\n"); @@ -421,9 +422,9 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx) return 0; fail: + edac_mc_free(mci); +unmap: iounmap(window); - if (mci) - edac_mc_free(mci); return rc; } From 0ff7c44106b4715fc27a2e455d9f57f1dfcfd54f Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Tue, 23 Dec 2025 20:43:50 +0800 Subject: [PATCH 068/443] EDAC/x38: Fix a resource leak in x38_probe1() If edac_mc_alloc() fails, also unmap the window. [ bp: Use separate labels, turning it into the classic unwind pattern. ] Fixes: df8bc08c192f ("edac x38: new MC driver module") Signed-off-by: Haoxiang Li Signed-off-by: Borislav Petkov (AMD) Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251223124350.1496325-1-lihaoxiang@isrc.iscas.ac.cn --- drivers/edac/x38_edac.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c index 49ab5721aab2..292dda754c23 100644 --- a/drivers/edac/x38_edac.c +++ b/drivers/edac/x38_edac.c @@ -341,9 +341,12 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx) layers[1].type = EDAC_MC_LAYER_CHANNEL; layers[1].size = x38_channel_num; layers[1].is_virt_csrow = false; + + + rc = -ENOMEM; mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0); if (!mci) - return -ENOMEM; + goto unmap; edac_dbg(3, "MC: init mci\n"); @@ -403,9 +406,9 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx) return 0; fail: + edac_mc_free(mci); +unmap: iounmap(window); - if (mci) - edac_mc_free(mci); return rc; } From 857bf9056291a16785ae3be1d291026b2437fc48 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 8 Dec 2025 14:45:00 -0500 Subject: [PATCH 069/443] pNFS: Fix a deadlock when returning a delegation during open() Ben Coddington reports seeing a hang in the following stack trace: 0 [ffffd0b50e1774e0] __schedule at ffffffff9ca05415 1 [ffffd0b50e177548] schedule at ffffffff9ca05717 2 [ffffd0b50e177558] bit_wait at ffffffff9ca061e1 3 [ffffd0b50e177568] __wait_on_bit at ffffffff9ca05cfb 4 [ffffd0b50e1775c8] out_of_line_wait_on_bit at ffffffff9ca05ea5 5 [ffffd0b50e177618] pnfs_roc at ffffffffc154207b [nfsv4] 6 [ffffd0b50e1776b8] _nfs4_proc_delegreturn at ffffffffc1506586 [nfsv4] 7 [ffffd0b50e177788] nfs4_proc_delegreturn at ffffffffc1507480 [nfsv4] 8 [ffffd0b50e1777f8] nfs_do_return_delegation at ffffffffc1523e41 [nfsv4] 9 [ffffd0b50e177838] nfs_inode_set_delegation at ffffffffc1524a75 [nfsv4] 10 [ffffd0b50e177888] nfs4_process_delegation at ffffffffc14f41dd [nfsv4] 11 [ffffd0b50e1778a0] _nfs4_opendata_to_nfs4_state at ffffffffc1503edf [nfsv4] 12 [ffffd0b50e1778c0] _nfs4_open_and_get_state at ffffffffc1504e56 [nfsv4] 13 [ffffd0b50e177978] _nfs4_do_open at ffffffffc15051b8 [nfsv4] 14 [ffffd0b50e1779f8] nfs4_do_open at ffffffffc150559c [nfsv4] 15 [ffffd0b50e177a80] nfs4_atomic_open at ffffffffc15057fb [nfsv4] 16 [ffffd0b50e177ad0] nfs4_file_open at ffffffffc15219be [nfsv4] 17 [ffffd0b50e177b78] do_dentry_open at ffffffff9c09e6ea 18 [ffffd0b50e177ba8] vfs_open at ffffffff9c0a082e 19 [ffffd0b50e177bd0] dentry_open at ffffffff9c0a0935 The issue is that the delegreturn is being asked to wait for a layout return that cannot complete because a state recovery was initiated. The state recovery cannot complete until the open() finishes processing the delegations it was given. The solution is to propagate the existing flags that indicate a non-blocking call to the function pnfs_roc(), so that it knows not to wait in this situation. Reported-by: Benjamin Coddington Fixes: 29ade5db1293 ("pNFS: Wait on outstanding layoutreturns to complete in pnfs_roc()") Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 6 ++--- fs/nfs/pnfs.c | 58 +++++++++++++++++++++++++++++++++-------------- fs/nfs/pnfs.h | 17 ++++++-------- 3 files changed, 51 insertions(+), 30 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ec1ce593dea2..51da62ba6559 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3894,8 +3894,8 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait) calldata->res.seqid = calldata->arg.seqid; calldata->res.server = server; calldata->res.lr_ret = -NFS4ERR_NOMATCHING_LAYOUT; - calldata->lr.roc = pnfs_roc(state->inode, - &calldata->lr.arg, &calldata->lr.res, msg.rpc_cred); + calldata->lr.roc = pnfs_roc(state->inode, &calldata->lr.arg, + &calldata->lr.res, msg.rpc_cred, wait); if (calldata->lr.roc) { calldata->arg.lr_args = &calldata->lr.arg; calldata->res.lr_res = &calldata->lr.res; @@ -7005,7 +7005,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred, data->inode = nfs_igrab_and_active(inode); if (data->inode || issync) { data->lr.roc = pnfs_roc(inode, &data->lr.arg, &data->lr.res, - cred); + cred, issync); if (data->lr.roc) { data->args.lr_args = &data->lr.arg; data->res.lr_res = &data->lr.res; diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index b72d7cc36766..cff225721d1c 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1533,10 +1533,9 @@ static int pnfs_layout_return_on_reboot(struct pnfs_layout_hdr *lo) PNFS_FL_LAYOUTRETURN_PRIVILEGED); } -bool pnfs_roc(struct inode *ino, - struct nfs4_layoutreturn_args *args, - struct nfs4_layoutreturn_res *res, - const struct cred *cred) +bool pnfs_roc(struct inode *ino, struct nfs4_layoutreturn_args *args, + struct nfs4_layoutreturn_res *res, const struct cred *cred, + bool sync) { struct nfs_inode *nfsi = NFS_I(ino); struct nfs_open_context *ctx; @@ -1547,7 +1546,7 @@ bool pnfs_roc(struct inode *ino, nfs4_stateid stateid; enum pnfs_iomode iomode = 0; bool layoutreturn = false, roc = false; - bool skip_read = false; + bool skip_read; if (!nfs_have_layout(ino)) return false; @@ -1560,20 +1559,14 @@ retry: lo = NULL; goto out_noroc; } - pnfs_get_layout_hdr(lo); - if (test_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) { - spin_unlock(&ino->i_lock); - rcu_read_unlock(); - wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN, - TASK_UNINTERRUPTIBLE); - pnfs_put_layout_hdr(lo); - goto retry; - } /* no roc if we hold a delegation */ + skip_read = false; if (nfs4_check_delegation(ino, FMODE_READ)) { - if (nfs4_check_delegation(ino, FMODE_WRITE)) + if (nfs4_check_delegation(ino, FMODE_WRITE)) { + lo = NULL; goto out_noroc; + } skip_read = true; } @@ -1582,12 +1575,43 @@ retry: if (state == NULL) continue; /* Don't return layout if there is open file state */ - if (state->state & FMODE_WRITE) + if (state->state & FMODE_WRITE) { + lo = NULL; goto out_noroc; + } if (state->state & FMODE_READ) skip_read = true; } + if (skip_read) { + bool writes = false; + + list_for_each_entry(lseg, &lo->plh_segs, pls_list) { + if (lseg->pls_range.iomode != IOMODE_READ) { + writes = true; + break; + } + } + if (!writes) { + lo = NULL; + goto out_noroc; + } + } + + pnfs_get_layout_hdr(lo); + if (test_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) { + if (!sync) { + pnfs_set_plh_return_info( + lo, skip_read ? IOMODE_RW : IOMODE_ANY, 0); + goto out_noroc; + } + spin_unlock(&ino->i_lock); + rcu_read_unlock(); + wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN, + TASK_UNINTERRUPTIBLE); + pnfs_put_layout_hdr(lo); + goto retry; + } list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) { if (skip_read && lseg->pls_range.iomode == IOMODE_READ) @@ -1627,7 +1651,7 @@ retry: out_noroc: spin_unlock(&ino->i_lock); rcu_read_unlock(); - pnfs_layoutcommit_inode(ino, true); + pnfs_layoutcommit_inode(ino, sync); if (roc) { struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld; if (ld->prepare_layoutreturn) diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 91ff877185c8..3db8f13d8fe4 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -303,10 +303,9 @@ int pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo, u32 seq); int pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, struct list_head *lseg_list); -bool pnfs_roc(struct inode *ino, - struct nfs4_layoutreturn_args *args, - struct nfs4_layoutreturn_res *res, - const struct cred *cred); +bool pnfs_roc(struct inode *ino, struct nfs4_layoutreturn_args *args, + struct nfs4_layoutreturn_res *res, const struct cred *cred, + bool sync); int pnfs_roc_done(struct rpc_task *task, struct nfs4_layoutreturn_args **argpp, struct nfs4_layoutreturn_res **respp, int *ret); void pnfs_roc_release(struct nfs4_layoutreturn_args *args, @@ -773,12 +772,10 @@ pnfs_layoutcommit_outstanding(struct inode *inode) return false; } - -static inline bool -pnfs_roc(struct inode *ino, - struct nfs4_layoutreturn_args *args, - struct nfs4_layoutreturn_res *res, - const struct cred *cred) +static inline bool pnfs_roc(struct inode *ino, + struct nfs4_layoutreturn_args *args, + struct nfs4_layoutreturn_res *res, + const struct cred *cred, bool sync) { return false; } From cce0be6eb4971456b703aaeafd571650d314bcca Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 31 Dec 2025 11:42:31 -0500 Subject: [PATCH 070/443] NFS: Fix a deadlock involving nfs_release_folio() Wang Zhaolong reports a deadlock involving NFSv4.1 state recovery waiting on kthreadd, which is attempting to reclaim memory by calling nfs_release_folio(). The latter cannot make progress due to state recovery being needed. It seems that the only safe thing to do here is to kick off a writeback of the folio, without waiting for completion, or else kicking off an asynchronous commit. Reported-by: Wang Zhaolong Fixes: 96780ca55e3c ("NFS: fix up nfs_release_folio() to try to release the page") Signed-off-by: Trond Myklebust --- fs/nfs/file.c | 3 ++- fs/nfs/nfstrace.h | 3 +++ fs/nfs/write.c | 33 +++++++++++++++++++++++++++++++++ include/linux/nfs_fs.h | 1 + 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/fs/nfs/file.c b/fs/nfs/file.c index d020aab40c64..d1c138a416cf 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -511,7 +511,8 @@ static bool nfs_release_folio(struct folio *folio, gfp_t gfp) if ((current_gfp_context(gfp) & GFP_KERNEL) != GFP_KERNEL || current_is_kswapd() || current_is_kcompactd()) return false; - if (nfs_wb_folio(folio->mapping->host, folio) < 0) + if (nfs_wb_folio_reclaim(folio->mapping->host, folio) < 0 || + folio_test_private(folio)) return false; } return nfs_fscache_release_folio(folio, gfp); diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h index 6ce55e8e6b67..9f9ce4a565ea 100644 --- a/fs/nfs/nfstrace.h +++ b/fs/nfs/nfstrace.h @@ -1062,6 +1062,9 @@ DECLARE_EVENT_CLASS(nfs_folio_event_done, DEFINE_NFS_FOLIO_EVENT(nfs_aop_readpage); DEFINE_NFS_FOLIO_EVENT_DONE(nfs_aop_readpage_done); +DEFINE_NFS_FOLIO_EVENT(nfs_writeback_folio_reclaim); +DEFINE_NFS_FOLIO_EVENT_DONE(nfs_writeback_folio_reclaim_done); + DEFINE_NFS_FOLIO_EVENT(nfs_writeback_folio); DEFINE_NFS_FOLIO_EVENT_DONE(nfs_writeback_folio_done); diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 336c510f3750..bf412455e8ed 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -2024,6 +2024,39 @@ int nfs_wb_folio_cancel(struct inode *inode, struct folio *folio) return ret; } +/** + * nfs_wb_folio_reclaim - Write back all requests on one page + * @inode: pointer to page + * @folio: pointer to folio + * + * Assumes that the folio has been locked by the caller + */ +int nfs_wb_folio_reclaim(struct inode *inode, struct folio *folio) +{ + loff_t range_start = folio_pos(folio); + size_t len = folio_size(folio); + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = 0, + .range_start = range_start, + .range_end = range_start + len - 1, + .for_sync = 1, + }; + int ret; + + if (folio_test_writeback(folio)) + return -EBUSY; + if (folio_clear_dirty_for_io(folio)) { + trace_nfs_writeback_folio_reclaim(inode, range_start, len); + ret = nfs_writepage_locked(folio, &wbc); + trace_nfs_writeback_folio_reclaim_done(inode, range_start, len, + ret); + return ret; + } + nfs_commit_inode(inode, 0); + return 0; +} + /** * nfs_wb_folio - Write back all requests on one page * @inode: pointer to page diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index a6624edb7226..8dd79a3f3d66 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -637,6 +637,7 @@ extern int nfs_update_folio(struct file *file, struct folio *folio, extern int nfs_sync_inode(struct inode *inode); extern int nfs_wb_all(struct inode *inode); extern int nfs_wb_folio(struct inode *inode, struct folio *folio); +extern int nfs_wb_folio_reclaim(struct inode *inode, struct folio *folio); int nfs_wb_folio_cancel(struct inode *inode, struct folio *folio); extern int nfs_commit_inode(struct inode *, int); extern struct nfs_commit_data *nfs_commitdata_alloc(void); From 0c728083654f0066f5e10a1d2b0bd0907af19a58 Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Thu, 25 Dec 2025 07:41:03 +0000 Subject: [PATCH 071/443] pnfs/flexfiles: Fix memory leak in nfs4_ff_alloc_deviceid_node() In nfs4_ff_alloc_deviceid_node(), if the allocation for ds_versions fails, the function jumps to the out_scratch label without freeing the already allocated dsaddrs list, leading to a memory leak. Fix this by jumping to the out_err_drain_dsaddrs label, which properly frees the dsaddrs list before cleaning up other resources. Fixes: d67ae825a59d6 ("pnfs/flexfiles: Add the FlexFile Layout Driver") Signed-off-by: Zilin Guan Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayoutdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c index c55ea8fa3bfa..c2d8a13a9dbd 100644 --- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c +++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c @@ -103,7 +103,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, sizeof(struct nfs4_ff_ds_version), gfp_flags); if (!ds_versions) - goto out_scratch; + goto out_err_drain_dsaddrs; for (i = 0; i < version_count; i++) { /* 20 = version(4) + minor_version(4) + rsize(4) + wsize(4) + From 5a74af51c3a6f4cd22c128b0c1c019f68fa90011 Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Thu, 25 Dec 2025 08:45:26 +0000 Subject: [PATCH 072/443] pnfs/blocklayout: Fix memory leak in bl_parse_scsi() In bl_parse_scsi(), if the block device length is zero, the function returns immediately without releasing the file reference obtained via bl_open_path(), leading to a memory leak. Fix this by jumping to the out_blkdev_put label to ensure the file reference is properly released. Fixes: d76c769c8db4c ("pnfs/blocklayout: Don't add zero-length pnfs_block_dev") Signed-off-by: Zilin Guan Signed-off-by: Trond Myklebust --- fs/nfs/blocklayout/dev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/nfs/blocklayout/dev.c b/fs/nfs/blocklayout/dev.c index ab76120705e2..134d7f760a33 100644 --- a/fs/nfs/blocklayout/dev.c +++ b/fs/nfs/blocklayout/dev.c @@ -417,8 +417,10 @@ bl_parse_scsi(struct nfs_server *server, struct pnfs_block_dev *d, d->map = bl_map_simple; d->pr_key = v->scsi.pr_key; - if (d->len == 0) - return -ENODEV; + if (d->len == 0) { + error = -ENODEV; + goto out_blkdev_put; + } ops = bdev->bd_disk->fops->pr_ops; if (!ops) { From 6f9bda2337f8b0a4c10ed5630e85eceb126a2c5c Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Fri, 19 Dec 2025 15:13:44 -0500 Subject: [PATCH 073/443] NFS: Fix directory delegation verifier checks Doing this check in nfs_check_verifier() resulted in many, many more lookups on the wire when running Christoph's delegation benchmarking script. After some experimentation, I found that we can treat directory delegations exactly the same as having a delegated verifier when we reach nfs4_lookup_revalidate() for the best performance. Reported-by: Christoph Hellwig Fixes: 156b09482933 ("NFS: Request a directory delegation on ACCESS, CREATE, and UNLINK") Signed-off-by: Anna Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 23a78a742b61..c0e9d5a45cd0 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1516,14 +1516,6 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry, if (!nfs_dentry_verify_change(dir, dentry)) return 0; - /* - * If we have a directory delegation then we don't need to revalidate - * the directory. The delegation will either get recalled or we will - * receive a notification when it changes. - */ - if (nfs_have_directory_delegation(dir)) - return 0; - /* Revalidate nfsi->cache_change_attribute before we declare a match */ if (nfs_mapping_need_revalidate_inode(dir)) { if (rcu_walk) @@ -2216,13 +2208,6 @@ no_open: } EXPORT_SYMBOL_GPL(nfs_atomic_open); -static int -nfs_lookup_revalidate_delegated_parent(struct inode *dir, struct dentry *dentry, - struct inode *inode) -{ - return nfs_lookup_revalidate_done(dir, dentry, inode, 1); -} - static int nfs4_lookup_revalidate(struct inode *dir, const struct qstr *name, struct dentry *dentry, unsigned int flags) @@ -2247,12 +2232,10 @@ nfs4_lookup_revalidate(struct inode *dir, const struct qstr *name, if (inode == NULL) goto full_reval; - if (nfs_verifier_is_delegated(dentry)) + if (nfs_verifier_is_delegated(dentry) || + nfs_have_directory_delegation(inode)) return nfs_lookup_revalidate_delegated(dir, dentry, inode); - if (nfs_have_directory_delegation(dir)) - return nfs_lookup_revalidate_delegated_parent(dir, dentry, inode); - /* NFS only supports OPEN on regular files */ if (!S_ISREG(inode->i_mode)) goto full_reval; From 105c2db2474f50f109082ab8d070efcc8c3d52bd Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 31 Dec 2025 16:41:15 -0500 Subject: [PATCH 074/443] NFSv4: Fix nfs_clear_verifier_delegated() for delegated directories If the client returns a directory delegation, then look up all the child dentries, and clear their 'verifier delegated' bit, unless subject to a file delegation. Similarly, if a file delegation is being returned, check if there is a directory delegation before clearing a 'verifier delegated' bit. Reported-by: Christoph Hellwig Fixes: 156b09482933 ("NFS: Request a directory delegation on ACCESS, CREATE, and UNLINK") Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 57 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index c0e9d5a45cd0..8f9ea79b7882 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1440,7 +1440,8 @@ static void nfs_set_verifier_locked(struct dentry *dentry, unsigned long verf) if (!dir || !nfs_verify_change_attribute(dir, verf)) return; - if (inode && NFS_PROTO(inode)->have_delegation(inode, FMODE_READ, 0)) + if (NFS_PROTO(dir)->have_delegation(dir, FMODE_READ, 0) || + (inode && NFS_PROTO(inode)->have_delegation(inode, FMODE_READ, 0))) nfs_set_verifier_delegated(&verf); dentry->d_time = verf; } @@ -1465,6 +1466,49 @@ void nfs_set_verifier(struct dentry *dentry, unsigned long verf) EXPORT_SYMBOL_GPL(nfs_set_verifier); #if IS_ENABLED(CONFIG_NFS_V4) +static void nfs_clear_verifier_file(struct inode *inode) +{ + struct dentry *alias; + struct inode *dir; + + hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { + spin_lock(&alias->d_lock); + dir = d_inode_rcu(alias->d_parent); + if (!dir || + !NFS_PROTO(dir)->have_delegation(dir, FMODE_READ, 0)) + nfs_unset_verifier_delegated(&alias->d_time); + spin_unlock(&alias->d_lock); + } +} + +static void nfs_clear_verifier_directory(struct inode *dir) +{ + struct dentry *this_parent; + struct dentry *dentry; + struct inode *inode; + + if (hlist_empty(&dir->i_dentry)) + return; + this_parent = + hlist_entry(dir->i_dentry.first, struct dentry, d_u.d_alias); + + spin_lock(&this_parent->d_lock); + nfs_unset_verifier_delegated(&this_parent->d_time); + dentry = d_first_child(this_parent); + hlist_for_each_entry_from(dentry, d_sib) { + if (unlikely(dentry->d_flags & DCACHE_DENTRY_CURSOR)) + continue; + inode = d_inode_rcu(dentry); + if (inode && + NFS_PROTO(inode)->have_delegation(inode, FMODE_READ, 0)) + continue; + spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); + nfs_unset_verifier_delegated(&dentry->d_time); + spin_unlock(&dentry->d_lock); + } + spin_unlock(&this_parent->d_lock); +} + /** * nfs_clear_verifier_delegated - clear the dir verifier delegation tag * @inode: pointer to inode @@ -1477,16 +1521,13 @@ EXPORT_SYMBOL_GPL(nfs_set_verifier); */ void nfs_clear_verifier_delegated(struct inode *inode) { - struct dentry *alias; - if (!inode) return; spin_lock(&inode->i_lock); - hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { - spin_lock(&alias->d_lock); - nfs_unset_verifier_delegated(&alias->d_time); - spin_unlock(&alias->d_lock); - } + if (S_ISREG(inode->i_mode)) + nfs_clear_verifier_file(inode); + else if (S_ISDIR(inode->i_mode)) + nfs_clear_verifier_directory(inode); spin_unlock(&inode->i_lock); } EXPORT_SYMBOL_GPL(nfs_clear_verifier_delegated); From 3f77eda548c82564ae4a23c76b51d36c6e39c865 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 1 Jan 2026 20:16:04 -0500 Subject: [PATCH 075/443] NFSv4: Don't free slots prematurely if requesting a directory delegation When requesting a directory delegation, it is imperative to hold the slot until the delegation state has been recorded. Otherwise, if a recall comes in, the call to referring_call_exists() will assume the processing is done, and when it doesn't find a delegation, it will assume it has been returned. Fixes: 156b09482933 ("NFS: Request a directory delegation on ACCESS, CREATE, and UNLINK") Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 51da62ba6559..a0885ae55abc 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -4494,6 +4494,25 @@ static bool should_request_dir_deleg(struct inode *inode) } #endif /* CONFIG_NFS_V4_1 */ +static void nfs4_call_getattr_prepare(struct rpc_task *task, void *calldata) +{ + struct nfs4_call_sync_data *data = calldata; + nfs4_setup_sequence(data->seq_server->nfs_client, data->seq_args, + data->seq_res, task); +} + +static void nfs4_call_getattr_done(struct rpc_task *task, void *calldata) +{ + struct nfs4_call_sync_data *data = calldata; + + nfs4_sequence_process(task, data->seq_res); +} + +static const struct rpc_call_ops nfs4_call_getattr_ops = { + .rpc_call_prepare = nfs4_call_getattr_prepare, + .rpc_call_done = nfs4_call_getattr_done, +}; + static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct inode *inode) { @@ -4511,16 +4530,26 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, .rpc_argp = &args, .rpc_resp = &res, }; + struct nfs4_call_sync_data data = { + .seq_server = server, + .seq_args = &args.seq_args, + .seq_res = &res.seq_res, + }; + struct rpc_task_setup task_setup = { + .rpc_client = server->client, + .rpc_message = &msg, + .callback_ops = &nfs4_call_getattr_ops, + .callback_data = &data, + }; struct nfs4_gdd_res gdd_res; - unsigned short task_flags = 0; int status; if (nfs4_has_session(server->nfs_client)) - task_flags = RPC_TASK_MOVEABLE; + task_setup.flags = RPC_TASK_MOVEABLE; /* Is this is an attribute revalidation, subject to softreval? */ if (inode && (server->flags & NFS_MOUNT_SOFTREVAL)) - task_flags |= RPC_TASK_TIMEOUT; + task_setup.flags |= RPC_TASK_TIMEOUT; args.get_dir_deleg = should_request_dir_deleg(inode); if (args.get_dir_deleg) @@ -4530,22 +4559,24 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, nfs_fattr_init(fattr); nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 0); - status = nfs4_do_call_sync(server->client, server, &msg, - &args.seq_args, &res.seq_res, task_flags); + status = nfs4_call_sync_custom(&task_setup); + if (args.get_dir_deleg) { switch (status) { case 0: if (gdd_res.status != GDD4_OK) break; - status = nfs_inode_set_delegation( - inode, current_cred(), FMODE_READ, - &gdd_res.deleg, 0, NFS4_OPEN_DELEGATE_READ); + nfs_inode_set_delegation(inode, current_cred(), + FMODE_READ, &gdd_res.deleg, 0, + NFS4_OPEN_DELEGATE_READ); break; case -ENOTSUPP: case -EOPNOTSUPP: server->caps &= ~NFS_CAP_DIR_DELEG; } } + + nfs4_sequence_free_slot(&res.seq_res); return status; } From 49aadf830eb048134d33ad7329d92ecff45d8dbb Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 2 Jan 2026 12:14:10 +0100 Subject: [PATCH 076/443] ASoC: codecs: wsa883x: fix unnecessary initialisation The soundwire update_status() callback may be called multiple times with the same ATTACHED status but initialisation should only be done when transitioning from UNATTACHED to ATTACHED. This avoids repeated initialisation of the codecs during boot of machines like the Lenovo ThinkPad X13s: [ 11.614523] wsa883x-codec sdw:1:0:0217:0202:00:1: WSA883X Version 1_1, Variant: WSA8835_V2 [ 11.618022] wsa883x-codec sdw:1:0:0217:0202:00:1: WSA883X Version 1_1, Variant: WSA8835_V2 [ 11.621377] wsa883x-codec sdw:1:0:0217:0202:00:1: WSA883X Version 1_1, Variant: WSA8835_V2 [ 11.624065] wsa883x-codec sdw:1:0:0217:0202:00:1: WSA883X Version 1_1, Variant: WSA8835_V2 [ 11.631382] wsa883x-codec sdw:1:0:0217:0202:00:2: WSA883X Version 1_1, Variant: WSA8835_V2 [ 11.634424] wsa883x-codec sdw:1:0:0217:0202:00:2: WSA883X Version 1_1, Variant: WSA8835_V2 Fixes: 43b8c7dc85a1 ("ASoC: codecs: add wsa883x amplifier support") Cc: stable@vger.kernel.org # 6.0 Cc: Srinivas Kandagatla Signed-off-by: Johan Hovold Reviewed-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260102111413.9605-2-johan@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wsa883x.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index c3046e260cb9..3ffea56aeb0f 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -475,6 +475,7 @@ struct wsa883x_priv { int active_ports; int dev_mode; int comp_offset; + bool hw_init; /* * Protects temperature reading code (related to speaker protection) and * fields: temperature and pa_on. @@ -1043,6 +1044,9 @@ static int wsa883x_init(struct wsa883x_priv *wsa883x) struct regmap *regmap = wsa883x->regmap; int variant, version, ret; + if (wsa883x->hw_init) + return 0; + ret = regmap_read(regmap, WSA883X_OTP_REG_0, &variant); if (ret) return ret; @@ -1085,6 +1089,8 @@ static int wsa883x_init(struct wsa883x_priv *wsa883x) wsa883x->comp_offset); } + wsa883x->hw_init = true; + return 0; } @@ -1093,6 +1099,9 @@ static int wsa883x_update_status(struct sdw_slave *slave, { struct wsa883x_priv *wsa883x = dev_get_drvdata(&slave->dev); + if (status == SDW_SLAVE_UNATTACHED) + wsa883x->hw_init = false; + if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0) return wsa883x_init(wsa883x); From 29d71b8a5a40708b3eed9ba4953bfc2312c9c776 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 2 Jan 2026 12:14:11 +0100 Subject: [PATCH 077/443] ASoC: codecs: wsa881x: fix unnecessary initialisation The soundwire update_status() callback may be called multiple times with the same ATTACHED status but initialisation should only be done when transitioning from UNATTACHED to ATTACHED. Fixes: a0aab9e1404a ("ASoC: codecs: add wsa881x amplifier support") Cc: stable@vger.kernel.org # 5.6 Cc: Srinivas Kandagatla Signed-off-by: Johan Hovold Reviewed-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260102111413.9605-3-johan@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wsa881x.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index d7aca6567c2d..2fc234adca5f 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -678,6 +678,7 @@ struct wsa881x_priv { */ unsigned int sd_n_val; int active_ports; + bool hw_init; bool port_prepared[WSA881X_MAX_SWR_PORTS]; bool port_enable[WSA881X_MAX_SWR_PORTS]; }; @@ -687,6 +688,9 @@ static void wsa881x_init(struct wsa881x_priv *wsa881x) struct regmap *rm = wsa881x->regmap; unsigned int val = 0; + if (wsa881x->hw_init) + return; + regmap_register_patch(wsa881x->regmap, wsa881x_rev_2_0, ARRAY_SIZE(wsa881x_rev_2_0)); @@ -724,6 +728,8 @@ static void wsa881x_init(struct wsa881x_priv *wsa881x) regmap_update_bits(rm, WSA881X_OTP_REG_28, 0x3F, 0x3A); regmap_update_bits(rm, WSA881X_BONGO_RESRV_REG1, 0xFF, 0xB2); regmap_update_bits(rm, WSA881X_BONGO_RESRV_REG2, 0xFF, 0x05); + + wsa881x->hw_init = true; } static int wsa881x_component_probe(struct snd_soc_component *comp) @@ -1067,6 +1073,9 @@ static int wsa881x_update_status(struct sdw_slave *slave, { struct wsa881x_priv *wsa881x = dev_get_drvdata(&slave->dev); + if (status == SDW_SLAVE_UNATTACHED) + wsa881x->hw_init = false; + if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0) wsa881x_init(wsa881x); From 120f3e6ff76209ee2f62a64e5e7e9d70274df42b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 2 Jan 2026 12:14:12 +0100 Subject: [PATCH 078/443] ASoC: codecs: wsa884x: fix codec initialisation The soundwire update_status() callback may be called multiple times with the same ATTACHED status but initialisation should only be done when transitioning from UNATTACHED to ATTACHED. Fix the inverted hw_init flag which was set to false instead of true after initialisation which defeats its purpose and may result in repeated unnecessary initialisation. Similarly, the initial state of the flag was also inverted so that the codec would only be initialised and brought out of regmap cache only mode if its status first transitions to UNATTACHED. Fixes: aa21a7d4f68a ("ASoC: codecs: wsa884x: Add WSA884x family of speakers") Cc: stable@vger.kernel.org # 6.5 Cc: Krzysztof Kozlowski Signed-off-by: Johan Hovold Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260102111413.9605-4-johan@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wsa884x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index 887edd2be705..6c6b497657d0 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -1534,7 +1534,7 @@ static void wsa884x_init(struct wsa884x_priv *wsa884x) wsa884x_set_gain_parameters(wsa884x); - wsa884x->hw_init = false; + wsa884x->hw_init = true; } static int wsa884x_update_status(struct sdw_slave *slave, @@ -2109,7 +2109,6 @@ static int wsa884x_probe(struct sdw_slave *pdev, /* Start in cache-only until device is enumerated */ regcache_cache_only(wsa884x->regmap, true); - wsa884x->hw_init = true; if (IS_REACHABLE(CONFIG_HWMON)) { struct device *hwmon; From 46a16d89d097ac2c93b63382a37d60aa7f21dc71 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 2 Jan 2026 12:14:13 +0100 Subject: [PATCH 079/443] ASoC: codecs: wsa883x: suppress variant printk Drivers should generally be silent on successful probe. Demote the codec variant printk to debug level and instead add a warning in case an unknown variant is ever encountered. Signed-off-by: Johan Hovold Reviewed-by: Krzysztof Kozlowski Reviewed-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260102111413.9605-5-johan@kernel.org Signed-off-by: Mark Brown --- sound/soc/codecs/wsa883x.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index 3ffea56aeb0f..468d2b38a22a 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -1058,22 +1058,23 @@ static int wsa883x_init(struct wsa883x_priv *wsa883x) switch (variant) { case WSA8830: - dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8830\n", - version); + dev_dbg(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8830\n", + version); break; case WSA8835: - dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835\n", - version); + dev_dbg(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835\n", + version); break; case WSA8832: - dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8832\n", - version); + dev_dbg(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8832\n", + version); break; case WSA8835_V2: - dev_info(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835_V2\n", - version); + dev_dbg(wsa883x->dev, "WSA883X Version 1_%d, Variant: WSA8835_V2\n", + version); break; default: + dev_warn(wsa883x->dev, "unknown variant: %d\n", variant); break; } From 12cacdfb023d1b2f6c4e5af471f2d5b6f0cbf909 Mon Sep 17 00:00:00 2001 From: Deep Harsora Date: Fri, 2 Jan 2026 15:21:24 +0000 Subject: [PATCH 080/443] ASoC: Intel: sof_sdw: Add new quirks for PTL on Dell with CS42L43 Add missing quirks for some new Dell laptops using cs42l43's speaker outputs. Signed-off-by: Deep Harsora Signed-off-by: Maciej Strozek Link: https://patch.msgid.link/20260102152132.3053106-1-mstrozek@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/sof_sdw.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 2c1001148d54..8721a098d53f 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -764,6 +764,14 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { .driver_data = (void *)(SOC_SDW_CODEC_SPKR), }, /* Pantherlake devices*/ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0DD6") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), + }, { .callback = sof_sdw_quirk_cb, .matches = { From 22a507d7680f2c3499c133f6384349f62f916176 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 29 Dec 2025 17:04:32 +0800 Subject: [PATCH 081/443] ASoC: simple-card-utils: Check device node before overwrite direction Even the device node don't exist, the graph_util_parse_link_direction() will overwrite the playback_only and capture_only to be zero. Which cause the playback_only and capture_only are not correct, so check device node exist or not before update the value. Signed-off-by: Shengjiu Wang Acked-by: Kuninori Morimoto Link: https://patch.msgid.link/20251229090432.3964848-1-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 355f7ec8943c..bdc02e85b089 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -1179,9 +1179,9 @@ void graph_util_parse_link_direction(struct device_node *np, bool is_playback_only = of_property_read_bool(np, "playback-only"); bool is_capture_only = of_property_read_bool(np, "capture-only"); - if (playback_only) + if (np && playback_only) *playback_only = is_playback_only; - if (capture_only) + if (np && capture_only) *capture_only = is_capture_only; } EXPORT_SYMBOL_GPL(graph_util_parse_link_direction); From 269031b15c1433ff39e30fa7ea3ab8f0be9d6ae2 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 6 Nov 2025 15:13:50 -0800 Subject: [PATCH 082/443] x86/kaslr: Recognize all ZONE_DEVICE users as physaddr consumers Commit 7ffb791423c7 ("x86/kaslr: Reduce KASLR entropy on most x86 systems") is too narrow. The effect being mitigated in that commit is caused by ZONE_DEVICE which PCI_P2PDMA has a dependency. ZONE_DEVICE, in general, lets any physical address be added to the direct-map. I.e. not only ACPI hotplug ranges, CXL Memory Windows, or EFI Specific Purpose Memory, but also any PCI MMIO range for the DEVICE_PRIVATE and PCI_P2PDMA cases. Update the mitigation, limit KASLR entropy, to apply in all ZONE_DEVICE=y cases. Distro kernels typically have PCI_P2PDMA=y, so the practical exposure of this problem is limited to the PCI_P2PDMA=n case. A potential path to recover entropy would be to walk ACPI and determine the limits for hotplug and PCI MMIO before kernel_randomize_memory(). On smaller systems that could yield some KASLR address bits. This needs additional investigation to determine if some limited ACPI table scanning can happen this early without an open coded solution like arch/x86/boot/compressed/acpi.c needs to deploy. Cc: Ingo Molnar Cc: Kees Cook Cc: Bjorn Helgaas Cc: Peter Zijlstra Cc: Andy Lutomirski Cc: Logan Gunthorpe Cc: Andrew Morton Cc: David Hildenbrand Cc: Lorenzo Stoakes Cc: "Liam R. Howlett" Cc: Vlastimil Babka Cc: Mike Rapoport Cc: Suren Baghdasaryan Cc: Michal Hocko Fixes: 7ffb791423c7 ("x86/kaslr: Reduce KASLR entropy on most x86 systems") Cc: Signed-off-by: Dan Williams Reviewed-by: Balbir Singh Tested-by: Yasunori Goto Acked-by: Dave Hansen Link: http://patch.msgid.link/692e08b2516d4_261c1100a3@dwillia2-mobl4.notmuch Signed-off-by: Dave Jiang --- arch/x86/mm/kaslr.c | 10 +++++----- drivers/pci/Kconfig | 6 ------ mm/Kconfig | 10 +++++++--- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c index 3c306de52fd4..834641c6049a 100644 --- a/arch/x86/mm/kaslr.c +++ b/arch/x86/mm/kaslr.c @@ -115,12 +115,12 @@ void __init kernel_randomize_memory(void) /* * Adapt physical memory region size based on available memory, - * except when CONFIG_PCI_P2PDMA is enabled. P2PDMA exposes the - * device BAR space assuming the direct map space is large enough - * for creating a ZONE_DEVICE mapping in the direct map corresponding - * to the physical BAR address. + * except when CONFIG_ZONE_DEVICE is enabled. ZONE_DEVICE wants to map + * any physical address into the direct-map. KASLR wants to reliably + * steal some physical address bits. Those design choices are in direct + * conflict. */ - if (!IS_ENABLED(CONFIG_PCI_P2PDMA) && (memory_tb < kaslr_regions[0].size_tb)) + if (!IS_ENABLED(CONFIG_ZONE_DEVICE) && (memory_tb < kaslr_regions[0].size_tb)) kaslr_regions[0].size_tb = memory_tb; /* diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 00b0210e1f1d..e3f848ffb52a 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -225,12 +225,6 @@ config PCI_P2PDMA P2P DMA transactions must be between devices behind the same root port. - Enabling this option will reduce the entropy of x86 KASLR memory - regions. For example - on a 46 bit system, the entropy goes down - from 16 bits to 15 bits. The actual reduction in entropy depends - on the physical address bits, on processor features, kernel config - (5 level page table) and physical memory present on the system. - If unsure, say N. config PCI_LABEL diff --git a/mm/Kconfig b/mm/Kconfig index bd0ea5454af8..a992f2203eb9 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -1220,10 +1220,14 @@ config ZONE_DEVICE Device memory hotplug support allows for establishing pmem, or other device driver discovered memory regions, in the memmap. This allows pfn_to_page() lookups of otherwise - "device-physical" addresses which is needed for using a DAX - mapping in an O_DIRECT operation, among other things. + "device-physical" addresses which is needed for DAX, PCI_P2PDMA, and + DEVICE_PRIVATE features among others. - If FS_DAX is enabled, then say Y. + Enabling this option will reduce the entropy of x86 KASLR memory + regions. For example - on a 46 bit system, the entropy goes down + from 16 bits to 15 bits. The actual reduction in entropy depends + on the physical address bits, on processor features, kernel config + (5 level page table) and physical memory present on the system. # # Helpers to mirror range of the CPU page tables of a process into device page From 88c72bab77aaf389beccf762e112828253ca0564 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 4 Dec 2025 10:52:26 +0100 Subject: [PATCH 083/443] cxl/region: fix format string for resource_size_t The size of this type is architecture specific, and the recommended way to print it portably is through the custom %pap format string. Fixes: d6602e25819d ("cxl/region: Add support to indicate region has extended linear cache") Signed-off-by: Arnd Bergmann Reviewed-by: Ira Weiny Reviewed-by: Dave Jiang > --- Reviewed-by: Alison Schofield Link: https://patch.msgid.link/20251204095237.1032528-1-arnd@kernel.org Signed-off-by: Dave Jiang --- drivers/cxl/core/region.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index ae899f68551f..fc36a5413d3f 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -759,7 +759,7 @@ static ssize_t extended_linear_cache_size_show(struct device *dev, ACQUIRE(rwsem_read_intr, rwsem)(&cxl_rwsem.region); if ((rc = ACQUIRE_ERR(rwsem_read_intr, &rwsem))) return rc; - return sysfs_emit(buf, "%#llx\n", p->cache_size); + return sysfs_emit(buf, "%pap\n", &p->cache_size); } static DEVICE_ATTR_RO(extended_linear_cache_size); From fd9a14d233fbf33488cfa0cb7f59051b3233b017 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Mon, 5 Jan 2026 13:32:03 -0600 Subject: [PATCH 084/443] ASoC: dt-bindings: everest,es8316: Add interrupt support The Everest ES8316 has interrupt capability on its GPIO3 pin for headphone detection. Several of the RockPi 4 variants are using it already. Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260105193203.3166320-1-robh@kernel.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/everest,es8316.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/everest,es8316.yaml b/Documentation/devicetree/bindings/sound/everest,es8316.yaml index 81a0215050e0..fe5d938ca310 100644 --- a/Documentation/devicetree/bindings/sound/everest,es8316.yaml +++ b/Documentation/devicetree/bindings/sound/everest,es8316.yaml @@ -49,6 +49,10 @@ properties: items: - const: mclk + interrupts: + maxItems: 1 + description: Headphone detect interrupt + port: $ref: audio-graph-port.yaml# unevaluatedProperties: false From 5ab3dd9d0a63af66377f58633fec9dad650e6827 Mon Sep 17 00:00:00 2001 From: Alexey Charkov Date: Mon, 29 Dec 2025 14:11:58 +0400 Subject: [PATCH 085/443] arm64: dts: rockchip: Fix headphones widget name on NanoPi M5 Fix the mismatch between the simple-audio-card routing table vs. widget names, which caused the following error at boot preventing the sound card from getting added: [ 6.625634] asoc-simple-card sound: ASoC: DAPM unknown pin Headphones [ 6.627247] asoc-simple-card sound: ASoC: Failed to add route HPOL -> Headphones(*) [ 6.627988] asoc-simple-card sound: ASoC: Failed to add route HPOR -> Headphones(*) Fixes: 96cbdfdd3ac2 ("arm64: dts: rockchip: Add FriendlyElec NanoPi M5 support") Cc: stable@vger.kernel.org Signed-off-by: Alexey Charkov Link: https://patch.msgid.link/20251229-rk3576-sound-v1-1-2f59ef0d19b1@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts index cce34c541f7c..37184913f918 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts +++ b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts @@ -211,7 +211,7 @@ "Headphones", "HPOR", "IN1P", "Microphone Jack"; simple-audio-card,widgets = - "Headphone", "Headphone Jack", + "Headphone", "Headphones", "Microphone", "Microphone Jack"; simple-audio-card,codec { From 3e4a81881c0929b21a0577bc6e69514c09da5c3f Mon Sep 17 00:00:00 2001 From: Alexey Charkov Date: Mon, 29 Dec 2025 14:11:59 +0400 Subject: [PATCH 086/443] arm64: dts: rockchip: Configure MCLK for analog sound on NanoPi M5 NanoPi M5 derives its analog sound signal from SAI2 in M0 pin mode, so the MCLK pin should be configured accordingly for the sound codec to get its I2S signal from the SoC. Request the required pin config. The clock itself should also be CLK_SAI2_MCLKOUT_TO_IO for the sound to work (otherwise there is only silence out of the audio out jack). Fixes: 96cbdfdd3ac2 ("arm64: dts: rockchip: Add FriendlyElec NanoPi M5 support") Cc: stable@vger.kernel.org Signed-off-by: Alexey Charkov Link: https://patch.msgid.link/20251229-rk3576-sound-v1-2-2f59ef0d19b1@gmail.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts index 37184913f918..bb2cc2814b83 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts +++ b/arch/arm64/boot/dts/rockchip/rk3576-nanopi-m5.dts @@ -201,6 +201,7 @@ pinctrl-names = "default"; pinctrl-0 = <&hp_det_l>; + simple-audio-card,bitclock-master = <&masterdai>; simple-audio-card,format = "i2s"; simple-audio-card,hp-det-gpios = <&gpio2 RK_PD6 GPIO_ACTIVE_LOW>; simple-audio-card,mclk-fs = <256>; @@ -218,8 +219,9 @@ sound-dai = <&rt5616>; }; - simple-audio-card,cpu { + masterdai: simple-audio-card,cpu { sound-dai = <&sai2>; + system-clock-frequency = <12288000>; }; }; }; @@ -727,10 +729,12 @@ rt5616: audio-codec@1b { compatible = "realtek,rt5616"; reg = <0x1b>; - assigned-clocks = <&cru CLK_SAI2_MCLKOUT>; + assigned-clocks = <&cru CLK_SAI2_MCLKOUT_TO_IO>; assigned-clock-rates = <12288000>; - clocks = <&cru CLK_SAI2_MCLKOUT>; + clocks = <&cru CLK_SAI2_MCLKOUT_TO_IO>; clock-names = "mclk"; + pinctrl-0 = <&sai2m0_mclk>; + pinctrl-names = "default"; #sound-dai-cells = <0>; }; }; From 955b263c421c6fe5075369c52199f278289ec8c4 Mon Sep 17 00:00:00 2001 From: Chaoyi Chen Date: Tue, 6 Jan 2026 15:15:13 +0800 Subject: [PATCH 087/443] arm64: dts: rockchip: Fix wrong register range of rk3576 gpu According to RK3576 TRM part1 Table 1-1 Address Mapping, the size of the GPU registers is 128 KB. The current mapping incorrectly includes the addresses of multiple following IP like the eInk interface at 0x27900000. This has not been detected by the DT tooling as none of the extra mapped IP is described in the upstream RK3576 DT so far. Fixes: 57b1ce903966 ("arm64: dts: rockchip: Add rk3576 SoC base DT") Signed-off-by: Chaoyi Chen Reviewed-by: Nicolas Frattaroli Reviewed-by: Sebastian Reichel Link: https://patch.msgid.link/20260106071513.209-1-kernel@airkyi.com Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3576.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi index a86fc6b4e8c4..c72343e7a045 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi @@ -1261,7 +1261,7 @@ gpu: gpu@27800000 { compatible = "rockchip,rk3576-mali", "arm,mali-bifrost"; - reg = <0x0 0x27800000 0x0 0x200000>; + reg = <0x0 0x27800000 0x0 0x20000>; assigned-clocks = <&scmi_clk SCMI_CLK_GPU>; assigned-clock-rates = <198000000>; clocks = <&cru CLK_GPU>; From 1eb217ab2e737609f8a861b517649e82e7236d05 Mon Sep 17 00:00:00 2001 From: Faisal Bukhari Date: Mon, 22 Sep 2025 23:38:34 +0530 Subject: [PATCH 088/443] perf parse-events: Fix evsel allocation failure If evsel__new_idx() returns NULL, the function currently jumps to label 'out_err'. Here, references to `cpus` and `pmu_cpus` are dropped. Also, resources held by evsel->name and evsel->metric_id are freed. But if evsel__new_idx() returns NULL, it can lead to NULL pointer dereference. Fixes: cd63c22168257a0b ("perf parse-events: Minor __add_event refactoring") Signed-off-by: Faisal Bukhari Reviewed-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim --- tools/perf/util/parse-events.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 17c1c36a7bf9..000c89a1e50d 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -251,8 +251,11 @@ __add_event(struct list_head *list, int *idx, event_attr_init(attr); evsel = evsel__new_idx(attr, *idx); - if (!evsel) - goto out_err; + if (!evsel) { + perf_cpu_map__put(cpus); + perf_cpu_map__put(pmu_cpus); + return NULL; + } if (name) { evsel->name = strdup(name); From 2fa0eaf78c4bb24c2b05a4db3e0d86a7dcd8fd9f Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Tue, 6 Jan 2026 22:58:46 +0000 Subject: [PATCH 089/443] ASoC: ops: fix pointer types to be big-endian If manipulating big-endian data, make the pointers be big-endian instead of host-endian. This should stop the following sparse warnigns about endian-conversion: sound/soc/soc-ops.c:547:33: warning: invalid assignment: &= sound/soc/soc-ops.c:547:33: left side has type unsigned short sound/soc/soc-ops.c:547:33: right side has type restricted __be16 sound/soc/soc-ops.c:551:33: warning: invalid assignment: &= sound/soc/soc-ops.c:551:33: left side has type unsigned int sound/soc/soc-ops.c:551:33: right side has type restricted __be32 Signed-off-by: Ben Dooks Link: https://patch.msgid.link/20260106225846.83580-1-ben.dooks@codethink.co.uk Signed-off-by: Mark Brown --- sound/soc/soc-ops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index 624e9269fc25..ba42939d5f01 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -543,11 +543,11 @@ int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, ucontrol->value.bytes.data[0] &= ~params->mask; break; case 2: - ((u16 *)(&ucontrol->value.bytes.data))[0] + ((__be16 *)(&ucontrol->value.bytes.data))[0] &= cpu_to_be16(~params->mask); break; case 4: - ((u32 *)(&ucontrol->value.bytes.data))[0] + ((__be32 *)(&ucontrol->value.bytes.data))[0] &= cpu_to_be32(~params->mask); break; default: From 14adddc65340f2034751c95616861c0e888e2bb1 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Tue, 14 Oct 2025 18:00:57 +0200 Subject: [PATCH 090/443] drm/bridge: dw-hdmi-qp: Fix spurious IRQ on resume After resume from suspend to RAM, the following splash is generated if the HDMI driver is probed (independent of a connected cable): [ 1194.484052] irq 80: nobody cared (try booting with the "irqpoll" option) [ 1194.484074] CPU: 0 UID: 0 PID: 627 Comm: rtcwake Not tainted 6.17.0-rc7-g96f1a11414b3 #1 PREEMPT [ 1194.484082] Hardware name: Rockchip RK3576 EVB V10 Board (DT) [ 1194.484085] Call trace: [ 1194.484087] ... (stripped) [ 1194.484283] handlers: [ 1194.484285] [<00000000bc363dcb>] dw_hdmi_qp_main_hardirq [dw_hdmi_qp] [ 1194.484302] Disabling IRQ #80 Apparently the HDMI IP is losing part of its state while the system is suspended and generates spurious interrupts during resume. The bug has not yet been noticed, as system suspend does not yet work properly on upstream kernel with either the Rockchip RK3588 or RK3576 platform. Fixes: 128a9bf8ace2 ("drm/rockchip: Add basic RK3588 HDMI output support") Signed-off-by: Sebastian Reichel Reviewed-by: Cristian Ciocaltea Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20251014-rockchip-hdmi-suspend-fix-v1-1-983fcbf44839@collabora.com --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 9 +++++++++ drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 12 +++++++++++- include/drm/bridge/dw_hdmi_qp.h | 1 + 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index fe4c026280f0..60166919c5b5 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -163,6 +163,7 @@ struct dw_hdmi_qp { unsigned long ref_clk_rate; struct regmap *regm; + int main_irq; unsigned long tmds_char_rate; }; @@ -1271,6 +1272,7 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, dw_hdmi_qp_init_hw(hdmi); + hdmi->main_irq = plat_data->main_irq; ret = devm_request_threaded_irq(dev, plat_data->main_irq, dw_hdmi_qp_main_hardirq, NULL, IRQF_SHARED, dev_name(dev), hdmi); @@ -1331,9 +1333,16 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind); +void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi) +{ + disable_irq(hdmi->main_irq); +} +EXPORT_SYMBOL_GPL(dw_hdmi_qp_suspend); + void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi) { dw_hdmi_qp_init_hw(hdmi); + enable_irq(hdmi->main_irq); } EXPORT_SYMBOL_GPL(dw_hdmi_qp_resume); diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c index c9fe6aa3e3e3..6e39e8a00774 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c @@ -640,6 +640,15 @@ static void dw_hdmi_qp_rockchip_remove(struct platform_device *pdev) component_del(&pdev->dev, &dw_hdmi_qp_rockchip_ops); } +static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev) +{ + struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); + + dw_hdmi_qp_suspend(dev, hdmi->hdmi); + + return 0; +} + static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev) { struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); @@ -655,7 +664,8 @@ static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev) } static const struct dev_pm_ops dw_hdmi_qp_rockchip_pm = { - SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_qp_rockchip_resume) + SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_qp_rockchip_suspend, + dw_hdmi_qp_rockchip_resume) }; struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver = { diff --git a/include/drm/bridge/dw_hdmi_qp.h b/include/drm/bridge/dw_hdmi_qp.h index 3f461f6b9bbf..3af12f82da2c 100644 --- a/include/drm/bridge/dw_hdmi_qp.h +++ b/include/drm/bridge/dw_hdmi_qp.h @@ -34,5 +34,6 @@ struct dw_hdmi_qp_plat_data { struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, struct drm_encoder *encoder, const struct dw_hdmi_qp_plat_data *plat_data); +void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi); void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi); #endif /* __DW_HDMI_QP__ */ From 0ed91d47959cb7573c17e06487f0fb891d59dfb3 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Fri, 2 Jan 2026 21:53:46 +0000 Subject: [PATCH 091/443] usb: dwc3: Check for USB4 IP_NAME Synopsys renamed DWC_usb32 IP to DWC_usb4 as of IP version 1.30. No functional change except checking for the IP_NAME here. The driver will treat the new IP_NAME as if it's DWC_usb32. Additional features for USB4 will be introduced and checked separately. Cc: stable@vger.kernel.org Signed-off-by: Thinh Nguyen Link: https://patch.msgid.link/e6f1827754c7a7ddc5eb7382add20bfe3a9b312f.1767390747.git.Thinh.Nguyen@synopsys.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 2 ++ drivers/usb/dwc3/core.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ec8407972b9d..93fd5fdf95cb 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -993,6 +993,8 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); dwc->ip = DWC3_GSNPS_ID(reg); + if (dwc->ip == DWC4_IP) + dwc->ip = DWC32_IP; /* This should read as U3 followed by revision number */ if (DWC3_IP_IS(DWC3)) { diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index a5fc92c4ffa3..45757169b672 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1265,6 +1265,7 @@ struct dwc3 { #define DWC3_IP 0x5533 #define DWC31_IP 0x3331 #define DWC32_IP 0x3332 +#define DWC4_IP 0x3430 u32 revision; From 1366cd228b0c67b60a2c0c26ef37fe9f7cfedb7f Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Mon, 5 Jan 2026 09:43:23 +0100 Subject: [PATCH 092/443] tcpm: allow looking for role_sw device in the main node If ports are defined in the tcpc main node, fwnode_usb_role_switch_get() returns an error, meaning usb_role_switch_get() (which would succeed) never gets a chance to run as port->role_sw isn't NULL, causing a regression on devices where this is the case. Fix this by turning the NULL check into IS_ERR_OR_NULL(), so usb_role_switch_get() can actually run and the device get properly probed. Fixes: 2d8713f807a4 ("tcpm: switch check for role_sw device with fw_node") Cc: stable Reviewed-by: Heikki Krogerus Reviewed-by: Dragan Simic Signed-off-by: Arnaud Ferraris Link: https://patch.msgid.link/20260105-fix-ppp-power-v2-1-6924f5a41224@collabora.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 4ca2746ce16b..be49a976428f 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -7890,7 +7890,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) port->partner_desc.identity = &port->partner_ident; port->role_sw = fwnode_usb_role_switch_get(tcpc->fwnode); - if (!port->role_sw) + if (IS_ERR_OR_NULL(port->role_sw)) port->role_sw = usb_role_switch_get(port->dev); if (IS_ERR(port->role_sw)) { err = PTR_ERR(port->role_sw); From db0635a30462f6dbdc7284a712f65ec5345a0caa Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 6 Jan 2026 19:50:13 +0100 Subject: [PATCH 093/443] dt-bindings: usb: qcom,dwc3: Correct IPQ5018 interrupts According to reference manual, IPQ5018 does not have QUSB2 PHY and its interrupts should rather match ones used in IPQ5332 (so power_event, eud_dmse_int_mx, eud_dpse_int_mx). Fixes: 53c6d854be4e ("dt-bindings: usb: dwc3: Clean up hs_phy_irq in binding") Fixes: 6e762f7b8edc ("dt-bindings: usb: Introduce qcom,snps-dwc3") Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260106185012.19551-3-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/qcom,dwc3.yaml | 2 +- Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml index a792434c59db..809280b09143 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml @@ -406,7 +406,6 @@ allOf: compatible: contains: enum: - - qcom,ipq5018-dwc3 - qcom,ipq6018-dwc3 - qcom,ipq8074-dwc3 - qcom,msm8953-dwc3 @@ -451,6 +450,7 @@ allOf: compatible: contains: enum: + - qcom,ipq5018-dwc3 - qcom,ipq5332-dwc3 then: properties: diff --git a/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml index 8cee7c5582f2..3073943c5964 100644 --- a/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml @@ -420,7 +420,6 @@ allOf: compatible: contains: enum: - - qcom,ipq5018-dwc3 - qcom,ipq6018-dwc3 - qcom,ipq8074-dwc3 - qcom,msm8953-dwc3 @@ -467,6 +466,7 @@ allOf: compatible: contains: enum: + - qcom,ipq5018-dwc3 - qcom,ipq5332-dwc3 then: properties: From 1d32389dc52f6e0305228988243b61cbe687414d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 6 Jan 2026 19:50:14 +0100 Subject: [PATCH 094/443] dt-bindings: usb: qcom,dwc3: Correct MSM8994 interrupts According to the reference manual, MSM8994 does have QUSB2 PHY and does not have DP/DM IRQs interrupts. It is also logical it has the same constraints as similar device: MSM8996. This fixes dtbs_check warnings like: msm8994-sony-xperia-kitakami-karin.dtb: usb@f92f8800 (qcom,msm8994-dwc3): interrupt-names:1: 'hs_phy_irq' was expected msm8994-sony-xperia-kitakami-karin.dtb: usb@f92f8800 (qcom,msm8994-dwc3): interrupt-names:2: 'dp_hs_phy_irq' was expected msm8994-sony-xperia-kitakami-karin.dtb: usb@f92f8800 (qcom,msm8994-dwc3): interrupt-names:3: 'dm_hs_phy_irq' was expected Fixes: 53c6d854be4e ("dt-bindings: usb: dwc3: Clean up hs_phy_irq in binding") Fixes: 6e762f7b8edc ("dt-bindings: usb: Introduce qcom,snps-dwc3") Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260106185012.19551-4-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/qcom,dwc3.yaml | 2 +- Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml index 809280b09143..a7f58114c02e 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml @@ -427,6 +427,7 @@ allOf: compatible: contains: enum: + - qcom,msm8994-dwc3 - qcom,msm8996-dwc3 - qcom,qcs404-dwc3 - qcom,sdm660-dwc3 @@ -488,7 +489,6 @@ allOf: enum: - qcom,ipq4019-dwc3 - qcom,ipq8064-dwc3 - - qcom,msm8994-dwc3 - qcom,qcs615-dwc3 - qcom,qcs8300-dwc3 - qcom,qdu1000-dwc3 diff --git a/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml index 3073943c5964..7d784a648b7d 100644 --- a/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,snps-dwc3.yaml @@ -442,6 +442,7 @@ allOf: compatible: contains: enum: + - qcom,msm8994-dwc3 - qcom,msm8996-dwc3 - qcom,qcs404-dwc3 - qcom,sdm660-dwc3 @@ -509,7 +510,6 @@ allOf: - qcom,ipq4019-dwc3 - qcom,ipq8064-dwc3 - qcom,kaanapali-dwc3 - - qcom,msm8994-dwc3 - qcom,qcs615-dwc3 - qcom,qcs8300-dwc3 - qcom,qdu1000-dwc3 From 2740ac33c87b3d0dfa022efd6ba04c6261b1abbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Br=C3=BCderl?= Date: Sun, 7 Dec 2025 10:02:20 +0100 Subject: [PATCH 095/443] usb: core: add USB_QUIRK_NO_BOS for devices that hang on BOS descriptor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add USB_QUIRK_NO_BOS quirk flag to skip requesting the BOS descriptor for devices that cannot handle it. Add Elgato 4K X (0fd9:009b) to the quirk table. This device hangs when the BOS descriptor is requested at SuperSpeed Plus (10Gbps). Link: https://bugzilla.kernel.org/show_bug.cgi?id=220027 Cc: stable Signed-off-by: Johannes Brüderl Link: https://patch.msgid.link/20251207090220.14807-1-johannes.bruederl@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 5 +++++ drivers/usb/core/quirks.c | 3 +++ include/linux/usb/quirks.h | 3 +++ 3 files changed, 11 insertions(+) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index baf5bc844b6f..2bb1ceb9d621 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -1040,6 +1040,11 @@ int usb_get_bos_descriptor(struct usb_device *dev) __u8 cap_type; int ret; + if (dev->quirks & USB_QUIRK_NO_BOS) { + dev_dbg(ddev, "skipping BOS descriptor\n"); + return -ENOMSG; + } + bos = kzalloc(sizeof(*bos), GFP_KERNEL); if (!bos) return -ENOMEM; diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 47f589c4104a..c4d85089d19b 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -450,6 +450,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0c45, 0x7056), .driver_info = USB_QUIRK_IGNORE_REMOTE_WAKEUP }, + /* Elgato 4K X - BOS descriptor fetch hangs at SuperSpeed Plus */ + { USB_DEVICE(0x0fd9, 0x009b), .driver_info = USB_QUIRK_NO_BOS }, + /* Sony Xperia XZ1 Compact (lilac) smartphone in fastboot mode */ { USB_DEVICE(0x0fce, 0x0dde), .driver_info = USB_QUIRK_NO_LPM }, diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index 59409c1fc3de..2f7bd2fdc616 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -75,4 +75,7 @@ /* short SET_ADDRESS request timeout */ #define USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT BIT(16) +/* skip BOS descriptor request */ +#define USB_QUIRK_NO_BOS BIT(17) + #endif /* __LINUX_USB_QUIRKS_H */ From d9186faeae6efb7d0841a5e8eb213ff4c7966614 Mon Sep 17 00:00:00 2001 From: Ian Forbes Date: Fri, 14 Nov 2025 14:37:03 -0600 Subject: [PATCH 096/443] drm/vmwgfx: Fix KMS with 3D on HW version 10 HW version 10 does not have GB Surfaces so there is no backing buffer for surface backed FBs. This would result in a nullptr dereference and crash the driver causing a black screen. Fixes: 965544150d1c ("drm/vmwgfx: Refactor cursor handling") Signed-off-by: Ian Forbes Reviewed-by: Zack Rusin Signed-off-by: Zack Rusin Link: https://patch.msgid.link/20251114203703.1946616-1-ian.forbes@broadcom.com --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index d32ce1cb579e..bc51b5d55e38 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -766,13 +766,15 @@ err_out: return ERR_PTR(ret); } - ttm_bo_reserve(&bo->tbo, false, false, NULL); - ret = vmw_bo_dirty_add(bo); - if (!ret && surface && surface->res.func->dirty_alloc) { - surface->res.coherent = true; - ret = surface->res.func->dirty_alloc(&surface->res); + if (bo) { + ttm_bo_reserve(&bo->tbo, false, false, NULL); + ret = vmw_bo_dirty_add(bo); + if (!ret && surface && surface->res.func->dirty_alloc) { + surface->res.coherent = true; + ret = surface->res.func->dirty_alloc(&surface->res); + } + ttm_bo_unreserve(&bo->tbo); } - ttm_bo_unreserve(&bo->tbo); return &vfb->base; } From 37a0cff4551c14aca4cfa6ef3f2f0e0f61d66825 Mon Sep 17 00:00:00 2001 From: Ian Forbes Date: Wed, 7 Jan 2026 09:20:59 -0600 Subject: [PATCH 097/443] drm/vmwgfx: Merge vmw_bo_release and vmw_bo_free functions Some of the warnings need to be reordered between these two functions in order to be correct. This has happened multiple times. Merging them solves this problem once and for all. Fixes: d6667f0ddf46 ("drm/vmwgfx: Fix handling of dumb buffers") Signed-off-by: Ian Forbes Signed-off-by: Zack Rusin Link: https://patch.msgid.link/20260107152059.3048329-1-ian.forbes@broadcom.com --- drivers/gpu/drm/vmwgfx/vmwgfx_bo.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c index f031a312c783..b22887e8c881 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_bo.c @@ -32,9 +32,15 @@ #include -static void vmw_bo_release(struct vmw_bo *vbo) +/** + * vmw_bo_free - vmw_bo destructor + * + * @bo: Pointer to the embedded struct ttm_buffer_object + */ +static void vmw_bo_free(struct ttm_buffer_object *bo) { struct vmw_resource *res; + struct vmw_bo *vbo = to_vmw_bo(&bo->base); WARN_ON(kref_read(&vbo->tbo.base.refcount) != 0); vmw_bo_unmap(vbo); @@ -62,20 +68,8 @@ static void vmw_bo_release(struct vmw_bo *vbo) } vmw_surface_unreference(&vbo->dumb_surface); } - drm_gem_object_release(&vbo->tbo.base); -} - -/** - * vmw_bo_free - vmw_bo destructor - * - * @bo: Pointer to the embedded struct ttm_buffer_object - */ -static void vmw_bo_free(struct ttm_buffer_object *bo) -{ - struct vmw_bo *vbo = to_vmw_bo(&bo->base); - WARN_ON(!RB_EMPTY_ROOT(&vbo->res_tree)); - vmw_bo_release(vbo); + drm_gem_object_release(&vbo->tbo.base); WARN_ON(vbo->dirty); kfree(vbo); } From bf72b4b7bb7dbb643d204fa41e7463894a95999f Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Wed, 24 Dec 2025 17:11:05 +0800 Subject: [PATCH 098/443] drm/vmwgfx: Fix an error return check in vmw_compat_shader_add() In vmw_compat_shader_add(), the return value check of vmw_shader_alloc() is not proper. Modify the check for the return pointer 'res'. Found by code review and compiled on ubuntu 20.04. Fixes: 18e4a4669c50 ("drm/vmwgfx: Fix compat shader namespace") Cc: stable@vger.kernel.org Signed-off-by: Haoxiang Li Signed-off-by: Zack Rusin Link: https://patch.msgid.link/20251224091105.1569464-1-lihaoxiang@isrc.iscas.ac.cn --- drivers/gpu/drm/vmwgfx/vmwgfx_shader.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c index 69dfe69ce0f8..a8c8c9375d29 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c @@ -923,8 +923,10 @@ int vmw_compat_shader_add(struct vmw_private *dev_priv, ttm_bo_unreserve(&buf->tbo); res = vmw_shader_alloc(dev_priv, buf, size, 0, shader_type); - if (unlikely(ret != 0)) + if (IS_ERR(res)) { + ret = PTR_ERR(res); goto no_reserve; + } ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_shader, vmw_shader_key(user_key, shader_type), From df56ddd057424d21483bd0bee4da3632706d6606 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 6 Jan 2026 11:54:32 -0500 Subject: [PATCH 099/443] NFSv4.x: Directory delegations don't require any state recovery The state recovery code in nfs_end_delegation_return() is intended to allow regular files to recover cached open and lock state. It has no function for directory delegations, and may cause corruption. Fixes: 156b09482933 ("NFS: Request a directory delegation on ACCESS, CREATE, and UNLINK") Signed-off-by: Trond Myklebust --- fs/nfs/delegation.c | 5 +++++ fs/nfs/nfs4state.c | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 2248e3ad089a..c9fa4c1f68fc 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -581,6 +581,10 @@ static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation if (delegation == NULL) return 0; + /* Directory delegations don't require any state recovery */ + if (!S_ISREG(inode->i_mode)) + goto out_return; + if (!issync) mode |= O_NONBLOCK; /* Recall of any remaining application leases */ @@ -604,6 +608,7 @@ static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation goto out; } +out_return: err = nfs_do_return_delegation(inode, delegation, issync); out: /* Refcount matched in nfs_start_delegation_return_locked() */ diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 01179f7de322..dba51c622cf3 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1445,6 +1445,8 @@ void nfs_inode_find_state_and_recover(struct inode *inode, struct nfs4_state *state; bool found = false; + if (!S_ISREG(inode->i_mode)) + goto out; rcu_read_lock(); list_for_each_entry_rcu(ctx, &nfsi->open_files, list) { state = ctx->state; @@ -1466,7 +1468,7 @@ void nfs_inode_find_state_and_recover(struct inode *inode, found = true; } rcu_read_unlock(); - +out: nfs_inode_find_delegation_state_and_recover(inode, stateid); if (found) nfs4_schedule_state_manager(clp); @@ -1478,6 +1480,8 @@ static void nfs4_state_mark_open_context_bad(struct nfs4_state *state, int err) struct nfs_inode *nfsi = NFS_I(inode); struct nfs_open_context *ctx; + if (!S_ISREG(inode->i_mode)) + return; rcu_read_lock(); list_for_each_entry_rcu(ctx, &nfsi->open_files, list) { if (ctx->state != state) From 001945a777ec4de8610f646397a054c62d272c2d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 2 Jan 2026 16:01:06 -0500 Subject: [PATCH 100/443] NFS/localio: Stop further I/O upon hitting an error If the call into the filesystem results in an I/O error, then the next chunk of data won't be contiguous with the end of the last successful chunk. So break out of the I/O loop and report the results. Currently the localio code will do this for a short read/write, but not for an error. Fixes: 6a218b9c3183 ("nfs/localio: do not issue misaligned DIO out-of-order") Signed-off-by: Trond Myklebust Reviewed-by: Mike Snitzer --- fs/nfs/localio.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c index a113bfdacfd6..c884245e8fb8 100644 --- a/fs/nfs/localio.c +++ b/fs/nfs/localio.c @@ -618,7 +618,6 @@ static void nfs_local_call_read(struct work_struct *work) struct nfs_local_kiocb *iocb = container_of(work, struct nfs_local_kiocb, work); struct file *filp = iocb->kiocb.ki_filp; - bool force_done = false; ssize_t status; int n_iters; @@ -637,13 +636,13 @@ static void nfs_local_call_read(struct work_struct *work) scoped_with_creds(filp->f_cred) status = filp->f_op->read_iter(&iocb->kiocb, &iocb->iters[i]); - if (status != -EIOCBQUEUED) { - if (unlikely(status >= 0 && status < iocb->iters[i].count)) - force_done = true; /* Partial read */ - if (nfs_local_pgio_done(iocb, status, force_done)) { - nfs_local_read_iocb_done(iocb); - break; - } + if (status == -EIOCBQUEUED) + continue; + /* Break on completion, errors, or short reads */ + if (nfs_local_pgio_done(iocb, status, false) || status < 0 || + (size_t)status < iov_iter_count(&iocb->iters[i])) { + nfs_local_read_iocb_done(iocb); + break; } } } @@ -821,7 +820,6 @@ static void nfs_local_call_write(struct work_struct *work) container_of(work, struct nfs_local_kiocb, work); struct file *filp = iocb->kiocb.ki_filp; unsigned long old_flags = current->flags; - bool force_done = false; ssize_t status; int n_iters; @@ -843,13 +841,13 @@ static void nfs_local_call_write(struct work_struct *work) scoped_with_creds(filp->f_cred) status = filp->f_op->write_iter(&iocb->kiocb, &iocb->iters[i]); - if (status != -EIOCBQUEUED) { - if (unlikely(status >= 0 && status < iocb->iters[i].count)) - force_done = true; /* Partial write */ - if (nfs_local_pgio_done(iocb, status, force_done)) { - nfs_local_write_iocb_done(iocb); - break; - } + if (status == -EIOCBQUEUED) + continue; + /* Break on completion, errors, or short writes */ + if (nfs_local_pgio_done(iocb, status, false) || status < 0 || + (size_t)status < iov_iter_count(&iocb->iters[i])) { + nfs_local_write_iocb_done(iocb); + break; } } file_end_write(filp); From 60699ab7cbf0a4eb19929cce243002b39c67917d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 2 Jan 2026 18:55:08 -0500 Subject: [PATCH 101/443] NFS/localio: Deal with page bases that are > PAGE_SIZE When resending requests, etc, the page base can quickly grow larger than the page size. Fixes: 091bdcfcece0 ("nfs/localio: refactor iocb and iov_iter_bvec initialization") Signed-off-by: Trond Myklebust Reviewed-by: Mike Snitzer --- fs/nfs/localio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c index c884245e8fb8..41fbcb3f9167 100644 --- a/fs/nfs/localio.c +++ b/fs/nfs/localio.c @@ -461,6 +461,8 @@ nfs_local_iters_init(struct nfs_local_kiocb *iocb, int rw) v = 0; total = hdr->args.count; base = hdr->args.pgbase; + pagevec += base >> PAGE_SHIFT; + base &= ~PAGE_MASK; while (total && v < hdr->page_array.npages) { len = min_t(size_t, total, PAGE_SIZE - base); bvec_set_page(&iocb->bvec[v], *pagevec, len, base); From 3ea3b7891b21ce079cfc60dfd476ba59ee625a2b Mon Sep 17 00:00:00 2001 From: Bartlomiej Kubik Date: Thu, 11 Dec 2025 19:10:44 +0100 Subject: [PATCH 102/443] drm/vmwgfx: Fix kernel-doc warnings for vmwgfx_fence Add missing descriptions for vmw_event_fence_action_seq_passed. This fixes the following warnings: drivers/gpu/drm/vmwgfx/vmwgfx_fence.c:526 function parameter 'f' not described in 'vmw_event_fence_action_seq_passed' drivers/gpu/drm/vmwgfx/vmwgfx_fence.c:526 function parameter 'cb' not described in 'vmw_event_fence_action_seq_passed' Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202507040807.jKTxWGVQ-lkp@intel.com/ Signed-off-by: Bartlomiej Kubik Signed-off-by: Zack Rusin Link: https://lore.kernel.org/all/20251211181044.4098689-1-kubik.bartlomiej@gmail.com/ --- drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c index 00be92da5509..85795082fef9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c @@ -515,12 +515,12 @@ int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data, /** * vmw_event_fence_action_seq_passed * - * @action: The struct vmw_fence_action embedded in a struct - * vmw_event_fence_action. + * @f: The struct dma_fence which provides timestamp for the action event + * @cb: The struct dma_fence_cb callback for the action event. * - * This function is called when the seqno of the fence where @action is - * attached has passed. It queues the event on the submitter's event list. - * This function is always called from atomic context. + * This function is called when the seqno of the fence has passed + * and it is always called from atomic context. + * It queues the event on the submitter's event list. */ static void vmw_event_fence_action_seq_passed(struct dma_fence *f, struct dma_fence_cb *cb) From 70b8c45d8621c4d77b5659270e9a26ce7b1123cf Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 3 Jan 2026 17:00:44 -0800 Subject: [PATCH 103/443] arm: npcm: drop unused Kconfig ERRATA symbol The code for this errata was not merged. See https://lore.kernel.org/linux-arm-kernel/CAL_JsqK--G_7nO_UQ6jyomA1Sq6GUKtXVZpBF0dXjYA2iE047w@mail.gmail.com/ Fixes: 7bffa14c9aed ("arm: npcm: add basic support for Nuvoton BMCs") Signed-off-by: Randy Dunlap Signed-off-by: Andrew Jeffery --- arch/arm/mach-npcm/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-npcm/Kconfig b/arch/arm/mach-npcm/Kconfig index 63b42a19d1b8..d933e8abb50f 100644 --- a/arch/arm/mach-npcm/Kconfig +++ b/arch/arm/mach-npcm/Kconfig @@ -30,7 +30,6 @@ config ARCH_NPCM7XX select ARM_ERRATA_764369 if SMP select ARM_ERRATA_720789 select ARM_ERRATA_754322 - select ARM_ERRATA_794072 select PL310_ERRATA_588369 select PL310_ERRATA_727915 select MFD_SYSCON From 47c27c9c9c720bc93fdc69605d0ecd9382e99047 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 7 Jan 2026 22:36:42 +0100 Subject: [PATCH 104/443] ALSA: pcm: Improve the fix for race of buffer access at PCM OSS layer Handle the error code from snd_pcm_buffer_access_lock() in snd_pcm_runtime_buffer_set_silence() function. Found by Alexandros Panagiotou Fixes: 93a81ca06577 ("ALSA: pcm: Fix race of buffer access at PCM OSS layer") Cc: stable@vger.kernel.org # 6.15 Signed-off-by: Jaroslav Kysela Link: https://patch.msgid.link/20260107213642.332954-1-perex@perex.cz Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 2 +- sound/core/oss/pcm_oss.c | 4 +++- sound/core/pcm_native.c | 9 +++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 58fd6e84f961..a7860c047503 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1402,7 +1402,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s #define snd_pcm_lib_mmap_iomem NULL #endif -void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime); +int snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime); /** * snd_pcm_limit_isa_dma_size - Get the max size fitting with ISA DMA transfer diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index a82dd155e1d3..b12df5b5ddfc 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1074,7 +1074,9 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) runtime->oss.params = 0; runtime->oss.prepare = 1; runtime->oss.buffer_used = 0; - snd_pcm_runtime_buffer_set_silence(runtime); + err = snd_pcm_runtime_buffer_set_silence(runtime); + if (err < 0) + goto failure; runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 68bee40c9ada..932a9bf98cbc 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -730,13 +730,18 @@ static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime) } /* fill the PCM buffer with the current silence format; called from pcm_oss.c */ -void snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime) +int snd_pcm_runtime_buffer_set_silence(struct snd_pcm_runtime *runtime) { - snd_pcm_buffer_access_lock(runtime); + int err; + + err = snd_pcm_buffer_access_lock(runtime); + if (err < 0) + return err; if (runtime->dma_area) snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes)); snd_pcm_buffer_access_unlock(runtime); + return 0; } EXPORT_SYMBOL_GPL(snd_pcm_runtime_buffer_set_silence); From aabc977aa472ccf756372ae594d890022c19c9c8 Mon Sep 17 00:00:00 2001 From: Hari Prasath Gujulan Elango Date: Fri, 2 Jan 2026 18:01:30 +0100 Subject: [PATCH 105/443] ARM: dts: microchip: sama7d65: fix the ranges property for flx9 Update the ranges property for the flexcom9 as per the datasheet and align with the reg property. Fixes: b51e4aea3ecf ("ARM: dts: microchip: sama7d65: Add FLEXCOMs to sama7d65 SoC") Cc: stable@vger.kernel.org # 6.16+ Signed-off-by: Hari Prasath Gujulan Elango Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20260102170135.70717-2-nicolas.ferre@microchip.com Signed-off-by: Claudiu Beznea --- arch/arm/boot/dts/microchip/sama7d65.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/microchip/sama7d65.dtsi b/arch/arm/boot/dts/microchip/sama7d65.dtsi index cd2cf9a6f40b..5f3a7b178aa7 100644 --- a/arch/arm/boot/dts/microchip/sama7d65.dtsi +++ b/arch/arm/boot/dts/microchip/sama7d65.dtsi @@ -676,7 +676,7 @@ flx9: flexcom@e2820000 { compatible = "microchip,sama7d65-flexcom", "atmel,sama5d2-flexcom"; reg = <0xe2820000 0x200>; - ranges = <0x0 0xe281c000 0x800>; + ranges = <0x0 0xe2820000 0x800>; clocks = <&pmc PMC_TYPE_PERIPHERAL 43>; #address-cells = <1>; #size-cells = <1>; From 94ad504e67cd3be94fa1b2fed0cb87da0d8f9396 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 2 Jan 2026 18:01:31 +0100 Subject: [PATCH 106/443] ARM: dts: microchip: sama7d65: fix size-cells property for i2c3 Fix the #size-cells property for i2c3 node and remove the dtbs_check error telling that "#size-cells: 0 was expected" from schema atmel,at91sam-i2c.yaml and i2c-controller.yaml. Fixes: b51e4aea3ecf ("ARM: dts: microchip: sama7d65: Add FLEXCOMs to sama7d65 SoC") Cc: stable@vger.kernel.org # 6.16+ Signed-off-by: Nicolas Ferre Link: https://lore.kernel.org/r/20260102170135.70717-3-nicolas.ferre@microchip.com Signed-off-by: Claudiu Beznea --- arch/arm/boot/dts/microchip/sama7d65.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/microchip/sama7d65.dtsi b/arch/arm/boot/dts/microchip/sama7d65.dtsi index 5f3a7b178aa7..868045c650a7 100644 --- a/arch/arm/boot/dts/microchip/sama7d65.dtsi +++ b/arch/arm/boot/dts/microchip/sama7d65.dtsi @@ -527,7 +527,7 @@ interrupts = ; clocks = <&pmc PMC_TYPE_PERIPHERAL 37>; #address-cells = <1>; - #size-cells = <1>; + #size-cells = <0>; dmas = <&dma0 AT91_XDMAC_DT_PERID(12)>, <&dma0 AT91_XDMAC_DT_PERID(11)>; dma-names = "tx", "rx"; From 6e62d1c6f2c7dba31db976e60ca0d6edf96cf8d5 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 5 Dec 2025 10:32:16 +0100 Subject: [PATCH 107/443] efi: Wipe INITRD config table from memory after consumption When the EFI stub itself loads the initrd and puts it in memory (rather than simply passing on a struct boot_params or device tree that already carries initrd information), it exposes this information to the core kernel via a INITRD configuration table. Given that config tables are preserved across kexec, this means that subsequent kexec boots will observe the same information, even though it most likely has become stale by that point. On x86, this information is usually superseded by the initrd info passed via bootparams, in which case this stale information is simply ignored. However, when performing a kexec boot without passing an initrd, the loader falls back to this stale information and explodes. So wipe the base and size from the INITRD config table as soon as it has been consumed. This fixes the issue for kexec on all EFI architectures. Reported-by: James Le Cuirot Tested-by: James Le Cuirot Acked-by: H. Peter Anvin (Intel) Link: https://lore.kernel.org/all/20251126173209.374755-2-chewi@gentoo.org Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/efi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 55452e61af31..f5ff6e84a9b7 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -819,6 +819,7 @@ int __init efi_config_parse_tables(const efi_config_table_t *config_tables, if (tbl) { phys_initrd_start = tbl->base; phys_initrd_size = tbl->size; + tbl->base = tbl->size = 0; early_memunmap(tbl, sizeof(*tbl)); } } From 85829b80ca29d3ac6c1770dbe12306a1d960a8ac Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 6 Jan 2026 11:24:26 +0100 Subject: [PATCH 108/443] MAINTAINERS: add cper to APEI files The CPER records are defined as part of UEFI specs, but its primary way to report it is via APEI/GHES. As such, let's place it under the same umbrella to make easier for patch review. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Ard Biesheuvel --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5b11839cba9d..2f8bdcfe31d8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -314,6 +314,7 @@ R: Mauro Carvalho Chehab R: Shuai Xue L: linux-acpi@vger.kernel.org F: drivers/acpi/apei/ +F: drivers/firmware/efi/cper* ACPI COMPONENT ARCHITECTURE (ACPICA) M: "Rafael J. Wysocki" @@ -9511,6 +9512,7 @@ F: arch/arm/boot/compressed/efi-header.S F: arch/x86/platform/efi/ F: drivers/firmware/efi/ F: include/linux/efi*.h +X: drivers/firmware/efi/cper* EXTERNAL CONNECTOR SUBSYSTEM (EXTCON) M: MyungJoo Ham From b7e26c8bdae70832d7c4b31ec2995b1812a60169 Mon Sep 17 00:00:00 2001 From: Matthew Schwartz Date: Thu, 8 Jan 2026 01:36:50 -0800 Subject: [PATCH 109/443] ALSA: hda/tas2781: Skip UEFI calibration on ASUS ROG Xbox Ally X There is currently an issue with UEFI calibration data parsing for some TAS devices, like the ASUS ROG Xbox Ally X (RC73XA), that causes audio quality issues such as gaps in playback. Until the issue is root caused and fixed, add a quirk to skip using the UEFI calibration data and fall back to using the calibration data provided by the DSP firmware, which restores full speaker functionality on affected devices. Cc: stable@vger.kernel.org # 6.18 Link: https://lore.kernel.org/all/160aef32646c4d5498cbfd624fd683cc@ti.com/ Closes: https://lore.kernel.org/all/0ba100d0-9b6f-4a3b-bffa-61abe1b46cd5@linux.dev/ Suggested-by: Baojun Xu Signed-off-by: Matthew Schwartz Reviewed-by: Antheas Kapenekakis Link: https://patch.msgid.link/20260108093650.1142176-1-matthew.schwartz@linux.dev Signed-off-by: Takashi Iwai --- sound/hda/codecs/side-codecs/tas2781_hda_i2c.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index f7a7f216d586..0e4bda3a544e 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -60,6 +60,7 @@ struct tas2781_hda_i2c_priv { int (*save_calibration)(struct tas2781_hda *h); int hda_chip_id; + bool skip_calibration; }; static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data) @@ -491,7 +492,8 @@ static void tasdevice_dspfw_init(void *context) /* If calibrated data occurs error, dsp will still works with default * calibrated data inside algo. */ - hda_priv->save_calibration(tas_hda); + if (!hda_priv->skip_calibration) + hda_priv->save_calibration(tas_hda); } static void tasdev_fw_ready(const struct firmware *fmw, void *context) @@ -548,6 +550,7 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, void *master_data) { struct tas2781_hda *tas_hda = dev_get_drvdata(dev); + struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv; struct hda_component_parent *parent = master_data; struct hda_component *comp; struct hda_codec *codec; @@ -573,6 +576,14 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, break; } + /* + * Using ASUS ROG Xbox Ally X (RC73XA) UEFI calibration data + * causes audio dropouts during playback, use fallback data + * from DSP firmware as a workaround. + */ + if (codec->core.subsystem_id == 0x10431384) + hda_priv->skip_calibration = true; + pm_runtime_get_sync(dev); comp->dev = dev; From 9fae82450d8a5f9c8fa016cd15186e975609b2ac Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Fri, 18 Jul 2025 14:41:13 +0800 Subject: [PATCH 110/443] drm/rockchip: vop2: Add delay between poll registers According to the implementation of read_poll_timeout_atomic, if the delay time is 0, it will only use a simple loop based on timeout_us to decrement the count. Therefore, the final timeout time will differ significantly from the set timeout time. So, here we set a specific delay time to ensure that the calculation of the timeout duration is accurate. Fixes: 3e89a8c68354 ("drm/rockchip: vop2: Fix the update of LAYER/PORT select registers when there are multi display output on rk3588/rk3568") Signed-off-by: Andy Yan Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20250718064120.8811-1-andyshrk@163.com --- drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index cd8380f0eddc..855386a6a9f5 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -2104,7 +2104,7 @@ static void rk3568_vop2_wait_for_port_mux_done(struct vop2 *vop2) * Spin until the previous port_mux figuration is done. */ ret = readx_poll_timeout_atomic(rk3568_vop2_read_port_mux, vop2, port_mux_sel, - port_mux_sel == vop2->old_port_sel, 0, 50 * 1000); + port_mux_sel == vop2->old_port_sel, 10, 50 * 1000); if (ret) DRM_DEV_ERROR(vop2->dev, "wait port_mux done timeout: 0x%x--0x%x\n", port_mux_sel, vop2->old_port_sel); @@ -2124,7 +2124,7 @@ static void rk3568_vop2_wait_for_layer_cfg_done(struct vop2 *vop2, u32 cfg) * Spin until the previous layer configuration is done. */ ret = readx_poll_timeout_atomic(rk3568_vop2_read_layer_cfg, vop2, atv_layer_cfg, - atv_layer_cfg == cfg, 0, 50 * 1000); + atv_layer_cfg == cfg, 10, 50 * 1000); if (ret) DRM_DEV_ERROR(vop2->dev, "wait layer cfg done timeout: 0x%x--0x%x\n", atv_layer_cfg, cfg); From 7f6721b767e219343cfe9a894f5bd869ff5b9d3a Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Fri, 18 Jul 2025 14:41:14 +0800 Subject: [PATCH 111/443] drm/rockchip: vop2: Only wait for changed layer cfg done when there is pending cfgdone bits The write of cfgdone bits always done at .atomic_flush. When userspace makes plane zpos changes of two crtc within one commit, at the .atomic_begin stage, crtcN will never receive the "layer change cfg done" event of crtcM because crtcM has not yet written "cfgdone". So only wait when there is pending cfgdone bits to avoid long timeout. Fixes: 3e89a8c68354 ("drm/rockchip: vop2: Fix the update of LAYER/PORT select registers when there are multi display output on rk3588/rk3568") Signed-off-by: Andy Yan Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20250718064120.8811-2-andyshrk@163.com --- drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 855386a6a9f5..f3950e8476a7 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -2144,6 +2144,7 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp) u8 layer_sel_id; unsigned int ofs; u32 ovl_ctrl; + u32 cfg_done; int i; struct vop2_video_port *vp0 = &vop2->vps[0]; struct vop2_video_port *vp1 = &vop2->vps[1]; @@ -2298,8 +2299,16 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp) rk3568_vop2_wait_for_port_mux_done(vop2); } - if (layer_sel != old_layer_sel && atv_layer_sel != old_layer_sel) - rk3568_vop2_wait_for_layer_cfg_done(vop2, vop2->old_layer_sel); + if (layer_sel != old_layer_sel && atv_layer_sel != old_layer_sel) { + cfg_done = vop2_readl(vop2, RK3568_REG_CFG_DONE); + cfg_done &= (BIT(vop2->data->nr_vps) - 1); + cfg_done &= ~BIT(vp->id); + /* + * Changes of other VPs' overlays have not taken effect + */ + if (cfg_done) + rk3568_vop2_wait_for_layer_cfg_done(vop2, vop2->old_layer_sel); + } vop2_writel(vop2, RK3568_OVL_LAYER_SEL, layer_sel); mutex_unlock(&vop2->ovl_lock); From 54b603f2db6b95495bc33a8f2bde80f044baff9a Mon Sep 17 00:00:00 2001 From: Yaxiong Tian Date: Tue, 30 Dec 2025 14:15:34 +0800 Subject: [PATCH 112/443] PM: EM: Fix incorrect description of the cost field in struct em_perf_state Due to commit 1b600da51073 ("PM: EM: Optimize em_cpu_energy() and remove division"), the logic for energy consumption calculation has been modified. The actual calculation of cost is 10 * power * max_frequency / frequency instead of power * max_frequency / frequency. Therefore, the comment for cost has been updated to reflect the correct content. Fixes: 1b600da51073 ("PM: EM: Optimize em_cpu_energy() and remove division") Signed-off-by: Yaxiong Tian Reviewed-by: Lukasz Luba [ rjw: Added Fixes: tag ] Link: https://patch.msgid.link/20251230061534.816894-1-tianyaxiong@kylinos.cn Signed-off-by: Rafael J. Wysocki --- include/linux/energy_model.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/energy_model.h b/include/linux/energy_model.h index 43aa6153dc57..e7497f804644 100644 --- a/include/linux/energy_model.h +++ b/include/linux/energy_model.h @@ -18,7 +18,7 @@ * @power: The power consumed at this level (by 1 CPU or by a registered * device). It can be a total power: static and dynamic. * @cost: The cost coefficient associated with this level, used during - * energy calculation. Equal to: power * max_frequency / frequency + * energy calculation. Equal to: 10 * power * max_frequency / frequency * @flags: see "em_perf_state flags" description below. */ struct em_perf_state { From e25348c5405c38c7b5e7b833898f2d205289186a Mon Sep 17 00:00:00 2001 From: Malaya Kumar Rout Date: Mon, 5 Jan 2026 16:07:29 +0530 Subject: [PATCH 113/443] PM: EM: Fix memory leak in em_create_pd() error path When ida_alloc() fails in em_create_pd(), the function returns without freeing the previously allocated 'pd' structure, leading to a memory leak. The 'pd' pointer is allocated either at line 436 (for CPU devices with cpumask) or line 442 (for other devices) using kzalloc(). Additionally, the function incorrectly returns -ENOMEM when ida_alloc() fails, ignoring the actual error code returned by ida_alloc(), which can fail for reasons other than memory exhaustion. Fix both issues by: 1. Freeing the 'pd' structure with kfree() when ida_alloc() fails 2. Returning the actual error code from ida_alloc() instead of -ENOMEM This ensures proper cleanup on the error path and accurate error reporting. Fixes: cbe5aeedecc7 ("PM: EM: Assign a unique ID when creating a performance domain") Signed-off-by: Malaya Kumar Rout Reviewed-by: Changwoo Min Link: https://patch.msgid.link/20260105103730.65626-1-mrout@redhat.com Signed-off-by: Rafael J. Wysocki --- kernel/power/energy_model.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c index 11af9f64aa82..5b055cbe5341 100644 --- a/kernel/power/energy_model.c +++ b/kernel/power/energy_model.c @@ -449,8 +449,10 @@ static int em_create_pd(struct device *dev, int nr_states, INIT_LIST_HEAD(&pd->node); id = ida_alloc(&em_pd_ida, GFP_KERNEL); - if (id < 0) - return -ENOMEM; + if (id < 0) { + kfree(pd); + return id; + } pd->id = id; em_table = em_table_alloc(pd); From 9ce4aef9a5b1b76207152ba019f838f62dff97b8 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Thu, 8 Jan 2026 16:07:31 +0000 Subject: [PATCH 114/443] drm/gpuvm: take GEM lock inside drm_gpuvm_bo_obtain_prealloc() When calling drm_gpuvm_bo_obtain_prealloc() and using immediate mode, this may result in a call to ops->vm_bo_free(vm_bo) while holding the GEMs gpuva mutex. This is a problem if ops->vm_bo_free(vm_bo) performs any operations that are not safe in the fence signalling critical path, and it turns out that Panthor (the only current user of the method) calls drm_gem_shmem_unpin() which takes a resv lock internally. This constitutes both a violation of signalling safety and lock inversion. To fix this, we modify the method to internally take the GEMs gpuva mutex so that the mutex can be unlocked before freeing the preallocated vm_bo. Note that this modification introduces a requirement that the driver uses immediate mode to call drm_gpuvm_bo_obtain_prealloc() as it would otherwise take the wrong lock. Fixes: 63e919a31625 ("panthor: use drm_gpuva_unlink_defer()") Reviewed-by: Boris Brezillon Signed-off-by: Alice Ryhl Link: https://patch.msgid.link/20260108-gpuvm-rust-v2-1-dbd014005a0b@google.com Signed-off-by: Danilo Krummrich --- drivers/gpu/drm/drm_gpuvm.c | 75 ++++++++++++++++++--------- drivers/gpu/drm/panthor/panthor_mmu.c | 10 ---- 2 files changed, 51 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index 8a06d296561d..0de47e83d84d 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -1602,24 +1602,23 @@ drm_gpuvm_bo_create(struct drm_gpuvm *gpuvm, } EXPORT_SYMBOL_GPL(drm_gpuvm_bo_create); +/* + * drm_gpuvm_bo_destroy_not_in_lists() - final part of drm_gpuvm_bo cleanup + * @vm_bo: the &drm_gpuvm_bo to destroy + * + * It is illegal to call this method if the @vm_bo is present in the GEMs gpuva + * list, the extobj list, or the evicted list. + * + * Note that this puts a refcount on the GEM object, which may destroy the GEM + * object if the refcount reaches zero. It's illegal for this to happen if the + * caller holds the GEMs gpuva mutex because it would free the mutex. + */ static void -drm_gpuvm_bo_destroy(struct kref *kref) +drm_gpuvm_bo_destroy_not_in_lists(struct drm_gpuvm_bo *vm_bo) { - struct drm_gpuvm_bo *vm_bo = container_of(kref, struct drm_gpuvm_bo, - kref); struct drm_gpuvm *gpuvm = vm_bo->vm; const struct drm_gpuvm_ops *ops = gpuvm->ops; struct drm_gem_object *obj = vm_bo->obj; - bool lock = !drm_gpuvm_resv_protected(gpuvm); - - if (!lock) - drm_gpuvm_resv_assert_held(gpuvm); - - drm_gpuvm_bo_list_del(vm_bo, extobj, lock); - drm_gpuvm_bo_list_del(vm_bo, evict, lock); - - drm_gem_gpuva_assert_lock_held(gpuvm, obj); - list_del(&vm_bo->list.entry.gem); if (ops && ops->vm_bo_free) ops->vm_bo_free(vm_bo); @@ -1630,6 +1629,35 @@ drm_gpuvm_bo_destroy(struct kref *kref) drm_gem_object_put(obj); } +static void +drm_gpuvm_bo_destroy_not_in_lists_kref(struct kref *kref) +{ + struct drm_gpuvm_bo *vm_bo = container_of(kref, struct drm_gpuvm_bo, + kref); + + drm_gpuvm_bo_destroy_not_in_lists(vm_bo); +} + +static void +drm_gpuvm_bo_destroy(struct kref *kref) +{ + struct drm_gpuvm_bo *vm_bo = container_of(kref, struct drm_gpuvm_bo, + kref); + struct drm_gpuvm *gpuvm = vm_bo->vm; + bool lock = !drm_gpuvm_resv_protected(gpuvm); + + if (!lock) + drm_gpuvm_resv_assert_held(gpuvm); + + drm_gpuvm_bo_list_del(vm_bo, extobj, lock); + drm_gpuvm_bo_list_del(vm_bo, evict, lock); + + drm_gem_gpuva_assert_lock_held(gpuvm, vm_bo->obj); + list_del(&vm_bo->list.entry.gem); + + drm_gpuvm_bo_destroy_not_in_lists(vm_bo); +} + /** * drm_gpuvm_bo_put() - drop a struct drm_gpuvm_bo reference * @vm_bo: the &drm_gpuvm_bo to release the reference of @@ -1745,9 +1773,7 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_bo_put_deferred); void drm_gpuvm_bo_deferred_cleanup(struct drm_gpuvm *gpuvm) { - const struct drm_gpuvm_ops *ops = gpuvm->ops; struct drm_gpuvm_bo *vm_bo; - struct drm_gem_object *obj; struct llist_node *bo_defer; bo_defer = llist_del_all(&gpuvm->bo_defer); @@ -1766,14 +1792,7 @@ drm_gpuvm_bo_deferred_cleanup(struct drm_gpuvm *gpuvm) while (bo_defer) { vm_bo = llist_entry(bo_defer, struct drm_gpuvm_bo, list.entry.bo_defer); bo_defer = bo_defer->next; - obj = vm_bo->obj; - if (ops && ops->vm_bo_free) - ops->vm_bo_free(vm_bo); - else - kfree(vm_bo); - - drm_gpuvm_put(gpuvm); - drm_gem_object_put(obj); + drm_gpuvm_bo_destroy_not_in_lists(vm_bo); } } EXPORT_SYMBOL_GPL(drm_gpuvm_bo_deferred_cleanup); @@ -1861,6 +1880,9 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_bo_obtain); * count is decreased. If not found @__vm_bo is returned without further * increase of the reference count. * + * The provided @__vm_bo must not already be in the gpuva, evict, or extobj + * lists prior to calling this method. + * * A new &drm_gpuvm_bo is added to the GEMs gpuva list. * * Returns: a pointer to the found &drm_gpuvm_bo or @__vm_bo if no existing @@ -1873,14 +1895,19 @@ drm_gpuvm_bo_obtain_prealloc(struct drm_gpuvm_bo *__vm_bo) struct drm_gem_object *obj = __vm_bo->obj; struct drm_gpuvm_bo *vm_bo; + drm_WARN_ON(gpuvm->drm, !drm_gpuvm_immediate_mode(gpuvm)); + + mutex_lock(&obj->gpuva.lock); vm_bo = drm_gpuvm_bo_find(gpuvm, obj); if (vm_bo) { - drm_gpuvm_bo_put(__vm_bo); + mutex_unlock(&obj->gpuva.lock); + kref_put(&__vm_bo->kref, drm_gpuvm_bo_destroy_not_in_lists_kref); return vm_bo; } drm_gem_gpuva_assert_lock_held(gpuvm, obj); list_add_tail(&__vm_bo->list.entry.gem, &obj->gpuva.list); + mutex_unlock(&obj->gpuva.lock); return __vm_bo; } diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index d4839d282689..f6339963e496 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -1252,17 +1252,7 @@ static int panthor_vm_prepare_map_op_ctx(struct panthor_vm_op_ctx *op_ctx, goto err_cleanup; } - /* drm_gpuvm_bo_obtain_prealloc() will call drm_gpuvm_bo_put() on our - * pre-allocated BO if the association exists. Given we - * only have one ref on preallocated_vm_bo, drm_gpuvm_bo_destroy() will - * be called immediately, and we have to hold the VM resv lock when - * calling this function. - */ - dma_resv_lock(panthor_vm_resv(vm), NULL); - mutex_lock(&bo->base.base.gpuva.lock); op_ctx->map.vm_bo = drm_gpuvm_bo_obtain_prealloc(preallocated_vm_bo); - mutex_unlock(&bo->base.base.gpuva.lock); - dma_resv_unlock(panthor_vm_resv(vm)); op_ctx->map.bo_offset = offset; From 5b577d214fcc109707bcb77b4ae72a31cfd86798 Mon Sep 17 00:00:00 2001 From: Kery Qi Date: Wed, 7 Jan 2026 23:48:37 +0800 Subject: [PATCH 115/443] ASoC: davinci-evm: Fix reference leak in davinci_evm_probe The davinci_evm_probe() function calls of_parse_phandle() to acquire device nodes for "ti,audio-codec" and "ti,mcasp-controller". These functions return device nodes with incremented reference counts. However, in several error paths (e.g., when the second of_parse_phandle(), snd_soc_of_parse_card_name(), or devm_snd_soc_register_card() fails), the function returns directly without releasing the acquired nodes, leading to reference leaks. This patch adds an error handling path 'err_put' to properly release the device nodes using of_node_put() and clean up the pointers when an error occurs. Signed-off-by: Kery Qi Link: https://patch.msgid.link/20260107154836.1521-2-qikeyu2017@gmail.com Signed-off-by: Mark Brown --- sound/soc/ti/davinci-evm.c | 39 ++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c index 3848766d96c3..ad514c2e5a25 100644 --- a/sound/soc/ti/davinci-evm.c +++ b/sound/soc/ti/davinci-evm.c @@ -194,27 +194,32 @@ static int davinci_evm_probe(struct platform_device *pdev) return -EINVAL; dai->cpus->of_node = of_parse_phandle(np, "ti,mcasp-controller", 0); - if (!dai->cpus->of_node) - return -EINVAL; + if (!dai->cpus->of_node) { + ret = -EINVAL; + goto err_put; + } dai->platforms->of_node = dai->cpus->of_node; evm_soc_card.dev = &pdev->dev; ret = snd_soc_of_parse_card_name(&evm_soc_card, "ti,model"); if (ret) - return ret; + goto err_put; mclk = devm_clk_get(&pdev->dev, "mclk"); if (PTR_ERR(mclk) == -EPROBE_DEFER) { - return -EPROBE_DEFER; + ret = -EPROBE_DEFER; + goto err_put; } else if (IS_ERR(mclk)) { dev_dbg(&pdev->dev, "mclk not found.\n"); mclk = NULL; } drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; + if (!drvdata) { + ret = -ENOMEM; + goto err_put; + } drvdata->mclk = mclk; @@ -224,7 +229,8 @@ static int davinci_evm_probe(struct platform_device *pdev) if (!drvdata->mclk) { dev_err(&pdev->dev, "No clock or clock rate defined.\n"); - return -EINVAL; + ret = -EINVAL; + goto err_put; } drvdata->sysclk = clk_get_rate(drvdata->mclk); } else if (drvdata->mclk) { @@ -240,8 +246,25 @@ static int davinci_evm_probe(struct platform_device *pdev) snd_soc_card_set_drvdata(&evm_soc_card, drvdata); ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card); - if (ret) + if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + goto err_put; + } + + return ret; + +err_put: + dai->platforms->of_node = NULL; + + if (dai->cpus->of_node) { + of_node_put(dai->cpus->of_node); + dai->cpus->of_node = NULL; + } + + if (dai->codecs->of_node) { + of_node_put(dai->codecs->of_node); + dai->codecs->of_node = NULL; + } return ret; } From 15e8d739fda1084d81f7d3813e9600eba6e0f134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Noack?= Date: Thu, 1 Jan 2026 14:40:58 +0100 Subject: [PATCH 116/443] selftests/landlock: Properly close a file descriptor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a missing close(srv_fd) call, and use EXPECT_EQ() to check the result. Signed-off-by: Günther Noack Fixes: f83d51a5bdfe ("selftests/landlock: Check IOCTL restrictions for named UNIX domain sockets") Link: https://lore.kernel.org/r/20260101134102.25938-2-gnoack3000@gmail.com [mic: Use EXPECT_EQ() and update commit message] Signed-off-by: Mickaël Salaün --- tools/testing/selftests/landlock/fs_test.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 37a5a3df712e..968a91c927a4 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -4399,7 +4399,8 @@ TEST_F_FORK(layout1, named_unix_domain_socket_ioctl) /* FIONREAD and other IOCTLs should not be forbidden. */ EXPECT_EQ(0, test_fionread_ioctl(cli_fd)); - ASSERT_EQ(0, close(cli_fd)); + EXPECT_EQ(0, close(cli_fd)); + EXPECT_EQ(0, close(srv_fd)); } /* clang-format off */ From 8dad31f85c7b91fd8bdbc6d0f27abc53bd8b1ffe Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 19 Dec 2025 13:33:50 +0300 Subject: [PATCH 117/443] xfs: fix memory leak in xfs_growfs_check_rtgeom() Free the "nmp" allocation before returning -EINVAL. Fixes: dc68c0f60169 ("xfs: fix the zoned RT growfs check for zone alignment") Signed-off-by: Dan Carpenter Reviewed-by: Christoph Hellwig Signed-off-by: Carlos Maiolino --- fs/xfs/xfs_rtalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index e063f4f2f2e6..167298ad88dd 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -1265,7 +1265,7 @@ xfs_growfs_check_rtgeom( uint32_t rem; if (rextsize != 1) - return -EINVAL; + goto out_inval; div_u64_rem(nmp->m_sb.sb_rblocks, gblocks, &rem); if (rem) { xfs_warn(mp, From 66b47b9c069fa548db64bde6a32d3b33aa05f740 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 8 Jan 2026 14:31:56 +0000 Subject: [PATCH 118/443] ASoC: dt-bindings: realtek,rt5640: Document mclk Commit eba5a0bac211 ("ASoC: dt-bindings: realtek,rt5640: Convert to dtschema") converted the rt5640 dt-binding to yaml format but in the process dropped 'clock' and 'clock-names' properties that are used to specify the codec 'mclk'. This is causing DTB build warnings for boards that use this codec and define an 'mclk' in device-tree. Update the rt5640 binding document to add the optional mclk. Fixes: eba5a0bac211 ("ASoC: dt-bindings: realtek,rt5640: Convert to dtschema") Signed-off-by: Jon Hunter Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260108143158.351223-2-jonathanh@nvidia.com Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/realtek,rt5640.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml index 3f4f59287c1c..6bb6e12bdf8b 100644 --- a/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml +++ b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml @@ -44,6 +44,14 @@ properties: - realtek,rt5640 - realtek,rt5639 + clocks: + items: + - description: phandle and clock specifier for codec MCLK. + + clock-names: + items: + - const: mclk + reg: maxItems: 1 From 25b858474497b5f7e2198f6fc9381488d9bdb55d Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 8 Jan 2026 14:31:57 +0000 Subject: [PATCH 119/443] ASoC: dt-bindings: realtek,rt5640: Update jack-detect The device-tree property 'realtek,jack-detect-source' currently only permits values from 0-6. However, commit 2b9c8d2b3c89 ("ASoC: rt5640: Add the HDA header support") updated the Realtek rt5640 to support setting the 'realtek,jack-detect-source' to 7 to support the HDA header. The Tegra234 platforms currently set 'realtek,jack-detect-source' to 7 for the HDA header and this is causing a warning when building device-tree. audio-codec@1c (realtek,rt5640): realtek,jack-detect-source: 7 is not one of [0, 1, 2, 3, 4, 5, 6] Given that the driver already supports this settings, update the binding document for the rt5640 device to add the HDA header as a valid configuration for the 'realtek,jack-detect-source' property. Fixes: 2b9c8d2b3c89 ("ASoC: rt5640: Add the HDA header support") Signed-off-by: Jon Hunter Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260108143158.351223-3-jonathanh@nvidia.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/realtek,rt5640.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml index 6bb6e12bdf8b..e7d4ec29b0ec 100644 --- a/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml +++ b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml @@ -106,6 +106,7 @@ properties: - 4 # Use GPIO2 for jack-detect - 5 # Use GPIO3 for jack-detect - 6 # Use GPIO4 for jack-detect + - 7 # Use HDA header for jack-detect realtek,jack-detect-not-inverted: description: From b540b4e157c4b24d0501e5e50ffba598d066de42 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 8 Jan 2026 14:31:58 +0000 Subject: [PATCH 120/443] ASoC: dt-bindings: realtek,rt5640: Document port node Various boards that use the rt5640 audio codec define a 'port' child node under the codec node to describe the interface between it and the SoC that it is connected to. The binding document for the rt5640 codec does not define the 'port' child node and so this is generating warnings when running the DTB checks for these boards. Add the 'port' node to the binding document for the rt5640 codec to fix this. Signed-off-by: Jon Hunter Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260108143158.351223-4-jonathanh@nvidia.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/realtek,rt5640.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml index e7d4ec29b0ec..2f6a4a6cc0e6 100644 --- a/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml +++ b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml @@ -130,6 +130,10 @@ properties: - 2 # Scale current by 1.0 - 3 # Scale current by 1.5 + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + required: - compatible - reg From 32b63acd78f577b332d976aa06b56e70d054cbba Mon Sep 17 00:00:00 2001 From: Shivam Kumar Date: Sat, 13 Dec 2025 13:57:48 -0500 Subject: [PATCH 121/443] nvme-tcp: fix NULL pointer dereferences in nvmet_tcp_build_pdu_iovec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit efa56305908b ("nvmet-tcp: Fix a kernel panic when host sends an invalid H2C PDU length") added ttag bounds checking and data_offset validation in nvmet_tcp_handle_h2c_data_pdu(), but it did not validate whether the command's data structures (cmd->req.sg and cmd->iov) have been properly initialized before processing H2C_DATA PDUs. The nvmet_tcp_build_pdu_iovec() function dereferences these pointers without NULL checks. This can be triggered by sending H2C_DATA PDU immediately after the ICREQ/ICRESP handshake, before sending a CONNECT command or NVMe write command. Attack vectors that trigger NULL pointer dereferences: 1. H2C_DATA PDU sent before CONNECT → both pointers NULL 2. H2C_DATA PDU for READ command → cmd->req.sg allocated, cmd->iov NULL 3. H2C_DATA PDU for uninitialized command slot → both pointers NULL The fix validates both cmd->req.sg and cmd->iov before calling nvmet_tcp_build_pdu_iovec(). Both checks are required because: - Uninitialized commands: both NULL - READ commands: cmd->req.sg allocated, cmd->iov NULL - WRITE commands: both allocated Fixes: efa56305908b ("nvmet-tcp: Fix a kernel panic when host sends an invalid H2C PDU length") Reviewed-by: Sagi Grimberg Signed-off-by: Shivam Kumar Signed-off-by: Keith Busch --- drivers/nvme/target/tcp.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index 15416ff0eac4..d5966d007ba3 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -982,6 +982,18 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) pr_err("H2CData PDU len %u is invalid\n", cmd->pdu_len); goto err_proto; } + /* + * Ensure command data structures are initialized. We must check both + * cmd->req.sg and cmd->iov because they can have different NULL states: + * - Uninitialized commands: both NULL + * - READ commands: cmd->req.sg allocated, cmd->iov NULL + * - WRITE commands: both allocated + */ + if (unlikely(!cmd->req.sg || !cmd->iov)) { + pr_err("queue %d: H2CData PDU received for invalid command state (ttag %u)\n", + queue->idx, data->ttag); + goto err_proto; + } cmd->pdu_recv = 0; nvmet_tcp_build_pdu_iovec(cmd); queue->cmd = cmd; From 7d3fa7e954934fbda0a017ac1c305b7b10ecceef Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 31 Dec 2025 11:10:57 +0100 Subject: [PATCH 122/443] nvme-apple: add "apple,t8103-nvme-ans2" as compatible After discussion with the devicetree maintainers we agreed to not extend lists with the generic compatible "apple,nvme-ans2" anymore [1]. Add "apple,t8103-nvme-ans2" as fallback compatible as it is the SoC the driver and bindings were written for. [1]: https://lore.kernel.org/asahi/12ab93b7-1fc2-4ce0-926e-c8141cfe81bf@kernel.org/ Cc: stable@vger.kernel.org # v6.18+ Fixes: 5bd2927aceba ("nvme-apple: Add initial Apple SoC NVMe driver") Reviewed-by: Neal Gompa Reviewed-by: Christoph Hellwig Signed-off-by: Janne Grunau Signed-off-by: Keith Busch --- drivers/nvme/host/apple.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c index 15b3d07f8ccd..ed61b97fde59 100644 --- a/drivers/nvme/host/apple.c +++ b/drivers/nvme/host/apple.c @@ -1704,6 +1704,7 @@ static const struct apple_nvme_hw apple_nvme_t8103_hw = { static const struct of_device_id apple_nvme_of_match[] = { { .compatible = "apple,t8015-nvme-ans2", .data = &apple_nvme_t8015_hw }, + { .compatible = "apple,t8103-nvme-ans2", .data = &apple_nvme_t8103_hw }, { .compatible = "apple,nvme-ans2", .data = &apple_nvme_t8103_hw }, {}, }; From d1877cc7270302081a315a81a0ee8331f19f95c8 Mon Sep 17 00:00:00 2001 From: Chaitanya Kulkarni Date: Fri, 19 Dec 2025 16:18:42 -0800 Subject: [PATCH 123/443] nvme-fc: release admin tagset if init fails nvme_fabrics creates an NVMe/FC controller in following path: nvmf_dev_write() -> nvmf_create_ctrl() -> nvme_fc_create_ctrl() -> nvme_fc_init_ctrl() nvme_fc_init_ctrl() allocates the admin blk-mq resources right after nvme_add_ctrl() succeeds. If any of the subsequent steps fail (changing the controller state, scheduling connect work, etc.), we jump to the fail_ctrl path, which tears down the controller references but never frees the admin queue/tag set. The leaked blk-mq allocations match the kmemleak report seen during blktests nvme/fc. Check ctrl->ctrl.admin_tagset in the fail_ctrl path and call nvme_remove_admin_tag_set() when it is set so that all admin queue allocations are reclaimed whenever controller setup aborts. Reported-by: Yi Zhang Reviewed-by: Justin Tee Signed-off-by: Chaitanya Kulkarni Signed-off-by: Keith Busch --- drivers/nvme/host/fc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index bc455fa98246..6948de3f438a 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -3587,6 +3587,8 @@ fail_ctrl: ctrl->ctrl.opts = NULL; + if (ctrl->ctrl.admin_tagset) + nvme_remove_admin_tag_set(&ctrl->ctrl); /* initiate nvme ctrl ref counting teardown */ nvme_uninit_ctrl(&ctrl->ctrl); From 9282a1e171ad8d2205067e8ec3bbe4e3cef4f29f Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Mon, 5 Jan 2026 22:04:38 +0100 Subject: [PATCH 124/443] wifi: ath10k: fix dma_free_coherent() pointer dma_alloc_coherent() allocates a DMA mapped buffer and stores the addresses in XXX_unaligned fields. Those should be reused when freeing the buffer rather than the aligned addresses. Fixes: 2a1e1ad3fd37 ("ath10k: Add support for 64 bit ce descriptor") Cc: stable@vger.kernel.org Signed-off-by: Thomas Fourier Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20260105210439.20131-2-fourier.thomas@gmail.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath10k/ce.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 7bbda46cfd93..82f120ee1c66 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1727,8 +1727,8 @@ static void _ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) (ce_state->src_ring->nentries * sizeof(struct ce_desc) + CE_DESC_RING_ALIGN), - ce_state->src_ring->base_addr_owner_space, - ce_state->src_ring->base_addr_ce_space); + ce_state->src_ring->base_addr_owner_space_unaligned, + ce_state->src_ring->base_addr_ce_space_unaligned); kfree(ce_state->src_ring); } @@ -1737,8 +1737,8 @@ static void _ath10k_ce_free_pipe(struct ath10k *ar, int ce_id) (ce_state->dest_ring->nentries * sizeof(struct ce_desc) + CE_DESC_RING_ALIGN), - ce_state->dest_ring->base_addr_owner_space, - ce_state->dest_ring->base_addr_ce_space); + ce_state->dest_ring->base_addr_owner_space_unaligned, + ce_state->dest_ring->base_addr_ce_space_unaligned); kfree(ce_state->dest_ring); } @@ -1758,8 +1758,8 @@ static void _ath10k_ce_free_pipe_64(struct ath10k *ar, int ce_id) (ce_state->src_ring->nentries * sizeof(struct ce_desc_64) + CE_DESC_RING_ALIGN), - ce_state->src_ring->base_addr_owner_space, - ce_state->src_ring->base_addr_ce_space); + ce_state->src_ring->base_addr_owner_space_unaligned, + ce_state->src_ring->base_addr_ce_space_unaligned); kfree(ce_state->src_ring); } @@ -1768,8 +1768,8 @@ static void _ath10k_ce_free_pipe_64(struct ath10k *ar, int ce_id) (ce_state->dest_ring->nentries * sizeof(struct ce_desc_64) + CE_DESC_RING_ALIGN), - ce_state->dest_ring->base_addr_owner_space, - ce_state->dest_ring->base_addr_ce_space); + ce_state->dest_ring->base_addr_owner_space_unaligned, + ce_state->dest_ring->base_addr_ce_space_unaligned); kfree(ce_state->dest_ring); } From bb97131fbf9b708dd9616ac2bdc793ad102b5c48 Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Tue, 6 Jan 2026 09:49:04 +0100 Subject: [PATCH 125/443] wifi: ath12k: fix dma_free_coherent() pointer dma_alloc_coherent() allocates a DMA mapped buffer and stores the addresses in XXX_unaligned fields. Those should be reused when freeing the buffer rather than the aligned addresses. Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices") Cc: stable@vger.kernel.org Signed-off-by: Thomas Fourier Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20260106084905.18622-2-fourier.thomas@gmail.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/ce.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/ce.c b/drivers/net/wireless/ath/ath12k/ce.c index 9a63608838ac..4aea58446838 100644 --- a/drivers/net/wireless/ath/ath12k/ce.c +++ b/drivers/net/wireless/ath/ath12k/ce.c @@ -984,8 +984,8 @@ void ath12k_ce_free_pipes(struct ath12k_base *ab) dma_free_coherent(ab->dev, pipe->src_ring->nentries * desc_sz + CE_DESC_RING_ALIGN, - pipe->src_ring->base_addr_owner_space, - pipe->src_ring->base_addr_ce_space); + pipe->src_ring->base_addr_owner_space_unaligned, + pipe->src_ring->base_addr_ce_space_unaligned); kfree(pipe->src_ring); pipe->src_ring = NULL; } @@ -995,8 +995,8 @@ void ath12k_ce_free_pipes(struct ath12k_base *ab) dma_free_coherent(ab->dev, pipe->dest_ring->nentries * desc_sz + CE_DESC_RING_ALIGN, - pipe->dest_ring->base_addr_owner_space, - pipe->dest_ring->base_addr_ce_space); + pipe->dest_ring->base_addr_owner_space_unaligned, + pipe->dest_ring->base_addr_ce_space_unaligned); kfree(pipe->dest_ring); pipe->dest_ring = NULL; } @@ -1007,8 +1007,8 @@ void ath12k_ce_free_pipes(struct ath12k_base *ab) dma_free_coherent(ab->dev, pipe->status_ring->nentries * desc_sz + CE_DESC_RING_ALIGN, - pipe->status_ring->base_addr_owner_space, - pipe->status_ring->base_addr_ce_space); + pipe->status_ring->base_addr_owner_space_unaligned, + pipe->status_ring->base_addr_ce_space_unaligned); kfree(pipe->status_ring); pipe->status_ring = NULL; } From 1fed08c5519d2f929457f354d3c06c6a8c33829c Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Thu, 8 Jan 2026 11:21:46 +0800 Subject: [PATCH 126/443] wifi: ath12k: don't force radio frequency check in freq_to_idx() freq_to_idx() is used to map a channel to a survey index. Commit acc152f9be20 ("wifi: ath12k: combine channel list for split-phy devices in single-wiphy") adds radio specific frequency range check in this helper to make sure an invalid index is returned if the channel falls outside that range. However, this check introduces a race, resulting in below warnings as reported in [1]. ath12k_pci 0000:08:00.0: chan info: invalid frequency 6455 (idx 101 out of bounds) ath12k_pci 0000:08:00.0: chan info: invalid frequency 6535 (idx 101 out of bounds) ath12k_pci 0000:08:00.0: chan info: invalid frequency 6615 (idx 101 out of bounds) ath12k_pci 0000:08:00.0: chan info: invalid frequency 6695 (idx 101 out of bounds) ath12k_pci 0000:08:00.0: chan info: invalid frequency 6775 (idx 101 out of bounds) ath12k_pci 0000:08:00.0: chan info: invalid frequency 6855 (idx 101 out of bounds) ath12k_pci 0000:08:00.0: chan info: invalid frequency 6935 (idx 101 out of bounds) ath12k_pci 0000:08:00.0: chan info: invalid frequency 7015 (idx 101 out of bounds) ath12k_pci 0000:08:00.0: chan info: invalid frequency 7095 (idx 101 out of bounds) ath12k_pci 0000:08:00.0: chan info: invalid frequency 6435 (idx 101 out of bounds) Race scenario: 1) A regdomain covering below frequency range is uploaded to host via WMI_REG_CHAN_LIST_CC_EXT_EVENTID event: Country 00, CFG Regdomain UNSET FW Regdomain 0, num_reg_rules 6 1. (2402 - 2472 @ 40) (0, 20) (0 ms) (FLAGS 360448) (0, 0) 2. (2457 - 2477 @ 20) (0, 20) (0 ms) (FLAGS 360576) (0, 0) 3. (5170 - 5330 @ 160) (0, 20) (0 ms) (FLAGS 264320) (0, 0) 4. (5490 - 5730 @ 160) (0, 20) (0 ms) (FLAGS 264320) (0, 0) 5. (5735 - 5895 @ 160) (0, 20) (0 ms) (FLAGS 264320) (0, 0) 6. (5925 - 7125 @ 320) (0, 24) (0 ms) (FLAGS 2056) (0, 255) As a result, radio frequency range is updated as [2402, 7125] ath12k_pci 0000:08:00.0: mac pdev 0 freq limit updated. New range 2402->7125 MHz If no scan in progress or after scan finished, command WMI_SCAN_CHAN_LIST_CMDID is sent to firmware notifying that firmware is allowed to do scan on all channels within that range. The running path is: /* redomain uploaded */ 1. WMI_REG_CHAN_LIST_CC_EXT_EVENTID 2. ath12k_reg_chan_list_event() 3. ath12k_reg_handle_chan_list() 4. queue_work(..., &ar->regd_update_work) 5. ath12k_regd_update_work() 6. ath12k_regd_update() /* update radio frequency range */ 7. ath12k_mac_update_freq_range() 8. regulatory_set_wiphy_regd() 9. ath12k_reg_notifier() 10. ath12k_reg_update_chan_list() 11. queue_work(..., &ar->regd_channel_update_work) 12. ath12k_regd_update_chan_list_work() /* wait scan finishes */ 13. wait_for_completion_timeout(&ar->scan.completed, ...) /* command notifying list of valid channels */ 14. ath12k_wmi_send_scan_chan_list_cmd() 2) Hardware scan is triggered on all allowed channels. 3) Before scan completed, 11D mechanism detects a new country code ath12k_pci 0000:08:00.0: wmi 11d new cc GB With this code sent to firmware, firmware uploads a new regdomain Country GB, CFG Regdomain ETSI FW Regdomain 2, num_reg_rules 9 1. (2402 - 2482 @ 40) (0, 20) (0 ms) (FLAGS 360448) (0, 0) 2. (5170 - 5250 @ 80) (0, 23) (0 ms) (FLAGS 264192) (0, 0) 3. (5250 - 5330 @ 80) (0, 23) (0 ms) (FLAGS 264216) (0, 0) 4. (5490 - 5590 @ 80) (0, 30) (0 ms) (FLAGS 264208) 5. (5590 - 5650 @ 40) (0, 30) (600000 ms) (FLAGS 264208) 6. (5650 - 5730 @ 80) (0, 30) (0 ms) (FLAGS 264208) 7. (5735 - 5875 @ 80) (0, 14) (0 ms) (FLAGS 264192) (0, 0) 8. (5855 - 5875 @ 20) (0, 14) (0 ms) (FLAGS 264192) (0, 0) 9. (5945 - 6425 @ 320) (0, 24) (0 ms) (FLAGS 2056) (0, 11) Then radio frequency range is updated as [2402, 6425] ath12k_pci 0000:08:00.0: mac pdev 0 freq limit updated. New range 2402->6425 MHz Please note this is a smaller range than the previous one. Later host runs the same path for the purpose of notifying the new channel list. However since scan not completed, host just waits there. Meanwhile, firmware is possibly scanning channels outside the new range. As a result, WMI_CHAN_INFO_EVENTID events for those channels fail freq_to_idx() check and triggers warnings above. Fix this issue by removing radio frequency check in freq_to_idx(). This is valid because channels being scanned do not synchronize with frequency range update. Besides, this won't cause any problem, since freq_to_idx() is only used for survey data. Even out-of-range channels filled in the survey, they won't get delivered to userspace due to the range check already there in ath12k_mac_op_get_survey(). Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Fixes: acc152f9be20 ("wifi: ath12k: combine channel list for split-phy devices in single-wiphy") Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220871 # 1 Signed-off-by: Baochen Qiang Link: https://patch.msgid.link/20260108-ath12k-fix-freq-to-idx-v1-1-b2458cf7aa0d@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/wmi.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index be8b2943094f..3ce5fcb0e460 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -6575,16 +6575,9 @@ static int freq_to_idx(struct ath12k *ar, int freq) if (!sband) continue; - for (ch = 0; ch < sband->n_channels; ch++, idx++) { - if (sband->channels[ch].center_freq < - KHZ_TO_MHZ(ar->freq_range.start_freq) || - sband->channels[ch].center_freq > - KHZ_TO_MHZ(ar->freq_range.end_freq)) - continue; - + for (ch = 0; ch < sband->n_channels; ch++, idx++) if (sband->channels[ch].center_freq == freq) goto exit; - } } exit: From 3e8aaacdad4f66641f87ab441fe644b45f8ebdff Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 8 Jan 2026 11:13:23 +0100 Subject: [PATCH 127/443] cxl/port: Fix target list setup for multiple decoders sharing the same dport If a switch port has more than one decoder that is using the same downstream port, the enumeration of the target lists may fail with: # dmesg | grep target.list update_decoder_targets: cxl decoder1.0: dport3 found in target list, index 3 update_decoder_targets: cxl decoder1.0: dport2 found in target list, index 2 update_decoder_targets: cxl decoder1.0: dport0 found in target list, index 0 update_decoder_targets: cxl decoder2.0: dport3 found in target list, index 1 update_decoder_targets: cxl decoder4.0: dport3 found in target list, index 1 cxl_mem mem6: failed to find endpoint12:0000:00:01.4 in target list of decoder2.1 cxl_mem mem8: failed to find endpoint13:0000:20:01.4 in target list of decoder4.1 The case, that the same downstream port can be used in multiple target lists, is allowed and possible. Fix the update of the target list. Enumerate all children of the switch port and do not stop the iteration after the first matching target was found. With the fix applied: # dmesg | grep target.list update_decoder_targets: cxl decoder1.0: dport2 found in target list, index 2 update_decoder_targets: cxl decoder1.0: dport0 found in target list, index 0 update_decoder_targets: cxl decoder1.0: dport3 found in target list, index 3 update_decoder_targets: cxl decoder2.0: dport3 found in target list, index 1 update_decoder_targets: cxl decoder2.1: dport3 found in target list, index 1 update_decoder_targets: cxl decoder4.0: dport3 found in target list, index 1 update_decoder_targets: cxl decoder4.1: dport3 found in target list, index 1 Analyzing the conditions when this happens: 1) A dport is shared by multiple decoders. 2) The decoders have interleaving configured (ways > 1). The configuration above has the following hierarchy details (fixed version): root0 |_ | | | decoder0.1 | ways: 2 | target_list: 0,1 |_______________________________________ | | | dport0 | dport1 | | port2 port4 | | |___________________ |_____________________ | | | | | | | decoder2.0 decoder2.1 | decoder4.0 decoder4.1 | ways: 2 ways: 2 | ways: 2 ways: 2 | target_list: 2,3 target_list: 2,3 | target_list: 2,3 target_list: 2,3 |___________________ |___________________ | | | | | dport2 | dport3 | dport2 | dport3 | | | | endpoint7 endpoint12 endpoint9 endpoint13 |_ |_ |_ |_ | | | | | | | | | decoder7.0 | decoder12.0 | decoder9.0 | decoder13.0 | decoder7.2 | decoder12.2 | decoder9.2 | decoder13.2 | | | | mem3 mem5 mem6 mem8 Note: Device numbers vary for every boot. Current kernel fails to enumerate endpoint12 and endpoint13 as the target list is not updated for the second decoder. Fixes: 4f06d81e7c6a ("cxl: Defer dport allocation for switch ports") Reviewed-by: Dave Jiang Reviewed-by: Alison Schofield Reviewed-by: Jonathan Cameron Signed-off-by: Robert Richter Link: https://patch.msgid.link/20260108101324.509667-1-rrichter@amd.com Signed-off-by: Dave Jiang --- drivers/cxl/core/port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index fef3aa0c6680..3310dbfae9d6 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -1590,7 +1590,7 @@ static int update_decoder_targets(struct device *dev, void *data) cxlsd->target[i] = dport; dev_dbg(dev, "dport%d found in target list, index %d\n", dport->port_id, i); - return 1; + return 0; } } From 1e1f2055ad5a7a5d548789b334a4473a7665c418 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Fri, 19 Dec 2025 11:26:02 +0000 Subject: [PATCH 128/443] btrfs: release path before iget_failed() in btrfs_read_locked_inode() In btrfs_read_locked_inode() if we fail to lookup the inode, we jump to the 'out' label with a path that has a read locked leaf and then we call iget_failed(). This can result in a ABBA deadlock, since iget_failed() triggers inode eviction and that causes the release of the delayed inode, which must lock the delayed inode's mutex, and a task updating a delayed inode starts by taking the node's mutex and then modifying the inode's subvolume btree. Syzbot reported the following lockdep splat for this: ====================================================== WARNING: possible circular locking dependency detected syzkaller #0 Not tainted ------------------------------------------------------ btrfs-cleaner/8725 is trying to acquire lock: ffff0000d6826a48 (&delayed_node->mutex){+.+.}-{4:4}, at: __btrfs_release_delayed_node+0xa0/0x9b0 fs/btrfs/delayed-inode.c:290 but task is already holding lock: ffff0000dbeba878 (btrfs-tree-00){++++}-{4:4}, at: btrfs_tree_read_lock_nested+0x44/0x2ec fs/btrfs/locking.c:145 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (btrfs-tree-00){++++}-{4:4}: __lock_release kernel/locking/lockdep.c:5574 [inline] lock_release+0x198/0x39c kernel/locking/lockdep.c:5889 up_read+0x24/0x3c kernel/locking/rwsem.c:1632 btrfs_tree_read_unlock+0xdc/0x298 fs/btrfs/locking.c:169 btrfs_tree_unlock_rw fs/btrfs/locking.h:218 [inline] btrfs_search_slot+0xa6c/0x223c fs/btrfs/ctree.c:2133 btrfs_lookup_inode+0xd8/0x38c fs/btrfs/inode-item.c:395 __btrfs_update_delayed_inode+0x124/0xed0 fs/btrfs/delayed-inode.c:1032 btrfs_update_delayed_inode fs/btrfs/delayed-inode.c:1118 [inline] __btrfs_commit_inode_delayed_items+0x15f8/0x1748 fs/btrfs/delayed-inode.c:1141 __btrfs_run_delayed_items+0x1ac/0x514 fs/btrfs/delayed-inode.c:1176 btrfs_run_delayed_items_nr+0x28/0x38 fs/btrfs/delayed-inode.c:1219 flush_space+0x26c/0xb68 fs/btrfs/space-info.c:828 do_async_reclaim_metadata_space+0x110/0x364 fs/btrfs/space-info.c:1158 btrfs_async_reclaim_metadata_space+0x90/0xd8 fs/btrfs/space-info.c:1226 process_one_work+0x7e8/0x155c kernel/workqueue.c:3263 process_scheduled_works kernel/workqueue.c:3346 [inline] worker_thread+0x958/0xed8 kernel/workqueue.c:3427 kthread+0x5fc/0x75c kernel/kthread.c:463 ret_from_fork+0x10/0x20 arch/arm64/kernel/entry.S:844 -> #0 (&delayed_node->mutex){+.+.}-{4:4}: check_prev_add kernel/locking/lockdep.c:3165 [inline] check_prevs_add kernel/locking/lockdep.c:3284 [inline] validate_chain kernel/locking/lockdep.c:3908 [inline] __lock_acquire+0x1774/0x30a4 kernel/locking/lockdep.c:5237 lock_acquire+0x14c/0x2e0 kernel/locking/lockdep.c:5868 __mutex_lock_common+0x1d0/0x2678 kernel/locking/mutex.c:598 __mutex_lock kernel/locking/mutex.c:760 [inline] mutex_lock_nested+0x2c/0x38 kernel/locking/mutex.c:812 __btrfs_release_delayed_node+0xa0/0x9b0 fs/btrfs/delayed-inode.c:290 btrfs_release_delayed_node fs/btrfs/delayed-inode.c:315 [inline] btrfs_remove_delayed_node+0x68/0x84 fs/btrfs/delayed-inode.c:1326 btrfs_evict_inode+0x578/0xe28 fs/btrfs/inode.c:5587 evict+0x414/0x928 fs/inode.c:810 iput_final fs/inode.c:1914 [inline] iput+0x95c/0xad4 fs/inode.c:1966 iget_failed+0xec/0x134 fs/bad_inode.c:248 btrfs_read_locked_inode+0xe1c/0x1234 fs/btrfs/inode.c:4101 btrfs_iget+0x1b0/0x264 fs/btrfs/inode.c:5837 btrfs_run_defrag_inode fs/btrfs/defrag.c:237 [inline] btrfs_run_defrag_inodes+0x520/0xdc4 fs/btrfs/defrag.c:309 cleaner_kthread+0x21c/0x418 fs/btrfs/disk-io.c:1516 kthread+0x5fc/0x75c kernel/kthread.c:463 ret_from_fork+0x10/0x20 arch/arm64/kernel/entry.S:844 other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- rlock(btrfs-tree-00); lock(&delayed_node->mutex); lock(btrfs-tree-00); lock(&delayed_node->mutex); *** DEADLOCK *** 1 lock held by btrfs-cleaner/8725: #0: ffff0000dbeba878 (btrfs-tree-00){++++}-{4:4}, at: btrfs_tree_read_lock_nested+0x44/0x2ec fs/btrfs/locking.c:145 stack backtrace: CPU: 0 UID: 0 PID: 8725 Comm: btrfs-cleaner Not tainted syzkaller #0 PREEMPT Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/03/2025 Call trace: show_stack+0x2c/0x3c arch/arm64/kernel/stacktrace.c:499 (C) __dump_stack+0x30/0x40 lib/dump_stack.c:94 dump_stack_lvl+0xd8/0x12c lib/dump_stack.c:120 dump_stack+0x1c/0x28 lib/dump_stack.c:129 print_circular_bug+0x324/0x32c kernel/locking/lockdep.c:2043 check_noncircular+0x154/0x174 kernel/locking/lockdep.c:2175 check_prev_add kernel/locking/lockdep.c:3165 [inline] check_prevs_add kernel/locking/lockdep.c:3284 [inline] validate_chain kernel/locking/lockdep.c:3908 [inline] __lock_acquire+0x1774/0x30a4 kernel/locking/lockdep.c:5237 lock_acquire+0x14c/0x2e0 kernel/locking/lockdep.c:5868 __mutex_lock_common+0x1d0/0x2678 kernel/locking/mutex.c:598 __mutex_lock kernel/locking/mutex.c:760 [inline] mutex_lock_nested+0x2c/0x38 kernel/locking/mutex.c:812 __btrfs_release_delayed_node+0xa0/0x9b0 fs/btrfs/delayed-inode.c:290 btrfs_release_delayed_node fs/btrfs/delayed-inode.c:315 [inline] btrfs_remove_delayed_node+0x68/0x84 fs/btrfs/delayed-inode.c:1326 btrfs_evict_inode+0x578/0xe28 fs/btrfs/inode.c:5587 evict+0x414/0x928 fs/inode.c:810 iput_final fs/inode.c:1914 [inline] iput+0x95c/0xad4 fs/inode.c:1966 iget_failed+0xec/0x134 fs/bad_inode.c:248 btrfs_read_locked_inode+0xe1c/0x1234 fs/btrfs/inode.c:4101 btrfs_iget+0x1b0/0x264 fs/btrfs/inode.c:5837 btrfs_run_defrag_inode fs/btrfs/defrag.c:237 [inline] btrfs_run_defrag_inodes+0x520/0xdc4 fs/btrfs/defrag.c:309 cleaner_kthread+0x21c/0x418 fs/btrfs/disk-io.c:1516 kthread+0x5fc/0x75c kernel/kthread.c:463 ret_from_fork+0x10/0x20 arch/arm64/kernel/entry.S:844 Fix this by releasing the path before calling iget_failed(). Reported-by: syzbot+c1c6edb02bea1da754d8@syzkaller.appspotmail.com Link: https://lore.kernel.org/linux-btrfs/694530c2.a70a0220.207337.010d.GAE@google.com/ Fixes: 69673992b1ae ("btrfs: push cleanup into btrfs_read_locked_inode()") Reviewed-by: Boris Burkov Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/inode.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5ea1c392bbc7..731cd5df232c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4178,6 +4178,15 @@ cache_acl: return 0; out: + /* + * We may have a read locked leaf and iget_failed() triggers inode + * eviction which needs to release the delayed inode and that needs + * to lock the delayed inode's mutex. This can cause a ABBA deadlock + * with a task running delayed items, as that require first locking + * the delayed inode's mutex and then modifying its subvolume btree. + * So release the path before iget_failed(). + */ + btrfs_release_path(path); iget_failed(vfs_inode); return ret; } From be1c2e8afe3ac4a4f15a13f6844619c2cf47b1d1 Mon Sep 17 00:00:00 2001 From: Zilin Guan Date: Fri, 26 Dec 2025 11:30:22 +0000 Subject: [PATCH 129/443] btrfs: tests: fix root tree leak in btrfs_test_qgroups() If btrfs_insert_fs_root() fails, the tmp_root allocated by btrfs_alloc_dummy_root() is leaked because its initial reference count is not decremented. Fix this by calling btrfs_put_root() unconditionally after btrfs_insert_fs_root(). This ensures the local reference is always dropped. Also fix a copy-paste error in the error message where the subvolume root insertion failure was incorrectly logged as "fs root". Co-developed-by: Jianhao Xu Signed-off-by: Jianhao Xu Signed-off-by: Zilin Guan Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/tests/qgroup-tests.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/tests/qgroup-tests.c b/fs/btrfs/tests/qgroup-tests.c index e9124605974b..0fcc31beeffe 100644 --- a/fs/btrfs/tests/qgroup-tests.c +++ b/fs/btrfs/tests/qgroup-tests.c @@ -517,11 +517,11 @@ int btrfs_test_qgroups(u32 sectorsize, u32 nodesize) tmp_root->root_key.objectid = BTRFS_FS_TREE_OBJECTID; root->fs_info->fs_root = tmp_root; ret = btrfs_insert_fs_root(root->fs_info, tmp_root); + btrfs_put_root(tmp_root); if (ret) { test_err("couldn't insert fs root %d", ret); goto out; } - btrfs_put_root(tmp_root); tmp_root = btrfs_alloc_dummy_root(fs_info); if (IS_ERR(tmp_root)) { @@ -532,11 +532,11 @@ int btrfs_test_qgroups(u32 sectorsize, u32 nodesize) tmp_root->root_key.objectid = BTRFS_FIRST_FREE_OBJECTID; ret = btrfs_insert_fs_root(root->fs_info, tmp_root); + btrfs_put_root(tmp_root); if (ret) { - test_err("couldn't insert fs root %d", ret); + test_err("couldn't insert subvolume root %d", ret); goto out; } - btrfs_put_root(tmp_root); test_msg("running qgroup tests"); ret = test_no_shared_qgroup(root, sectorsize, nodesize); From d5fac7ddb38cd627a8fc2b87e5b588b48a803956 Mon Sep 17 00:00:00 2001 From: Naohiro Aota Date: Mon, 5 Jan 2026 17:19:05 +0900 Subject: [PATCH 130/443] btrfs: tests: fix return 0 on rmap test failure In test_rmap_blocks(), we have ret = 0 before checking the results. We need to set it to -EINVAL, so that a mismatching result will return -EINVAL not 0. Reviewed-by: Qu Wenruo Signed-off-by: Naohiro Aota Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/tests/extent-map-tests.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/btrfs/tests/extent-map-tests.c b/fs/btrfs/tests/extent-map-tests.c index 0b9f25dd1a68..aabf825e8d7b 100644 --- a/fs/btrfs/tests/extent-map-tests.c +++ b/fs/btrfs/tests/extent-map-tests.c @@ -1059,6 +1059,7 @@ static int test_rmap_block(struct btrfs_fs_info *fs_info, if (out_stripe_len != BTRFS_STRIPE_LEN) { test_err("calculated stripe length doesn't match"); + ret = -EINVAL; goto out; } @@ -1066,12 +1067,14 @@ static int test_rmap_block(struct btrfs_fs_info *fs_info, for (i = 0; i < out_ndaddrs; i++) test_msg("mapped %llu", logical[i]); test_err("unexpected number of mapped addresses: %d", out_ndaddrs); + ret = -EINVAL; goto out; } for (i = 0; i < out_ndaddrs; i++) { if (logical[i] != test->mapped_logical[i]) { test_err("unexpected logical address mapped"); + ret = -EINVAL; goto out; } } From 08b096c1372cd69627f4f559fb47c9fb67a52b39 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 6 Jan 2026 20:26:40 +1030 Subject: [PATCH 131/443] btrfs: send: check for inline extents in range_is_hole_in_parent() Before accessing the disk_bytenr field of a file extent item we need to check if we are dealing with an inline extent. This is because for inline extents their data starts at the offset of the disk_bytenr field. So accessing the disk_bytenr means we are accessing inline data or in case the inline data is less than 8 bytes we can actually cause an invalid memory access if this inline extent item is the first item in the leaf or access metadata from other items. Fixes: 82bfb2e7b645 ("Btrfs: incremental send, fix unnecessary hole writes for sparse files") Reviewed-by: Filipe Manana Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/send.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 130aabced207..d0b2f9bd4150 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -6382,6 +6382,8 @@ static int range_is_hole_in_parent(struct send_ctx *sctx, extent_end = btrfs_file_extent_end(path); if (extent_end <= start) goto next; + if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) + return 0; if (btrfs_file_extent_disk_bytenr(leaf, fi) == 0) { search_start = extent_end; goto next; From a8f49a0043011c3dd12998a6c700bb59d5365c20 Mon Sep 17 00:00:00 2001 From: "Chia-Lin Kao (AceLan)" Date: Thu, 4 Dec 2025 10:46:47 +0800 Subject: [PATCH 132/443] drm/dp: Add byte-by-byte fallback for broken USB-C adapters Some USB-C hubs and adapters have buggy firmware where multi-byte AUX reads consistently timeout, while single-byte reads from the same address work correctly. Known affected devices that exhibit this issue: - Lenovo USB-C to VGA adapter (VIA VL817 chipset) idVendor=17ef, idProduct=7217 - Dell DA310 USB-C mobile adapter hub idVendor=413c, idProduct=c010 Analysis of the failure pattern shows: - Single-byte probes to 0xf0000 (LTTPR) succeed - Single-byte probes to 0x00102 (TRAINING_AUX_RD_INTERVAL) succeed - Multi-byte reads from 0x00000 (DPCD capabilities) timeout with -ETIMEDOUT - Retrying does not help - the failure is consistent across all attempts The issue appears to be a firmware bug in the AUX transaction handling that specifically affects multi-byte reads. Add a fallback mechanism in drm_dp_dpcd_read_data() that attempts byte-by-byte reading when the normal multi-byte read fails. This workaround only activates for adapters that fail the standard read path, ensuring no impact on correctly functioning hardware. Tested with: - Lenovo USB-C to VGA adapter (VIA VL817) - now works with fallback - Dell DA310 USB-C hub - now works with fallback - Dell/Analogix Slimport adapter - continues to work with normal path Signed-off-by: Chia-Lin Kao (AceLan) Reviewed-by: Mario Limonciello (AMD) Link: https://patch.msgid.link/20251204024647.1462866-1-acelan.kao@canonical.com Signed-off-by: Mario Limonciello (AMD) --- include/drm/display/drm_dp_helper.h | 57 +++++++++++++++++++---------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index df2f24b950e4..14d2859f0bda 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -551,6 +551,22 @@ ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset, void *buffer, size_t size); +/** + * drm_dp_dpcd_readb() - read a single byte from the DPCD + * @aux: DisplayPort AUX channel + * @offset: address of the register to read + * @valuep: location where the value of the register will be stored + * + * Returns the number of bytes transferred (1) on success, or a negative + * error code on failure. In most of the cases you should be using + * drm_dp_dpcd_read_byte() instead. + */ +static inline ssize_t drm_dp_dpcd_readb(struct drm_dp_aux *aux, + unsigned int offset, u8 *valuep) +{ + return drm_dp_dpcd_read(aux, offset, valuep, 1); +} + /** * drm_dp_dpcd_read_data() - read a series of bytes from the DPCD * @aux: DisplayPort AUX channel (SST or MST) @@ -570,12 +586,29 @@ static inline int drm_dp_dpcd_read_data(struct drm_dp_aux *aux, void *buffer, size_t size) { int ret; + size_t i; + u8 *buf = buffer; ret = drm_dp_dpcd_read(aux, offset, buffer, size); - if (ret < 0) - return ret; - if (ret < size) - return -EPROTO; + if (ret >= 0) { + if (ret < size) + return -EPROTO; + return 0; + } + + /* + * Workaround for USB-C hubs/adapters with buggy firmware that fail + * multi-byte AUX reads but work with single-byte reads. + * Known affected devices: + * - Lenovo USB-C to VGA adapter (VIA VL817, idVendor=17ef, idProduct=7217) + * - Dell DA310 USB-C hub (idVendor=413c, idProduct=c010) + * Attempt byte-by-byte reading as a fallback. + */ + for (i = 0; i < size; i++) { + ret = drm_dp_dpcd_readb(aux, offset + i, &buf[i]); + if (ret < 0) + return ret; + } return 0; } @@ -609,22 +642,6 @@ static inline int drm_dp_dpcd_write_data(struct drm_dp_aux *aux, return 0; } -/** - * drm_dp_dpcd_readb() - read a single byte from the DPCD - * @aux: DisplayPort AUX channel - * @offset: address of the register to read - * @valuep: location where the value of the register will be stored - * - * Returns the number of bytes transferred (1) on success, or a negative - * error code on failure. In most of the cases you should be using - * drm_dp_dpcd_read_byte() instead. - */ -static inline ssize_t drm_dp_dpcd_readb(struct drm_dp_aux *aux, - unsigned int offset, u8 *valuep) -{ - return drm_dp_dpcd_read(aux, offset, valuep, 1); -} - /** * drm_dp_dpcd_writeb() - write a single byte to the DPCD * @aux: DisplayPort AUX channel From 3ea9fe578d1d2c1fb88410f53e378561d1531e45 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 8 Jan 2026 17:05:59 -0600 Subject: [PATCH 133/443] arm64: dts: rockchip: Drop "sitronix,st7789v" fallback compatible from rk3568-wolfvision "sitronix,st7789v" is not a defined fallback for "jasonic,jt240mhqs-hwt-ek-e3", so drop it. Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260108230600.1348699-1-robh@kernel.org Signed-off-by: Heiko Stuebner --- .../boot/dts/rockchip/rk3568-wolfvision-pf5-display-vz.dtso | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3568-wolfvision-pf5-display-vz.dtso b/arch/arm64/boot/dts/rockchip/rk3568-wolfvision-pf5-display-vz.dtso index 70c23e1bf14b..d1a906031912 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568-wolfvision-pf5-display-vz.dtso +++ b/arch/arm64/boot/dts/rockchip/rk3568-wolfvision-pf5-display-vz.dtso @@ -11,7 +11,6 @@ #include "rk3568-wolfvision-pf5-display.dtsi" &st7789 { - compatible = "jasonic,jt240mhqs-hwt-ek-e3", - "sitronix,st7789v"; + compatible = "jasonic,jt240mhqs-hwt-ek-e3"; rotation = <270>; }; From f45385c511141683379a6e090fe74c6002337b5e Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 8 Jan 2026 17:06:13 -0600 Subject: [PATCH 134/443] arm64: dts: rockchip: Fix pinctrl property typo on rk3326-odroid-go3 "pinctrl" is not a defined property name. The correct name is "pinctrl-0". Signed-off-by: Rob Herring (Arm) [added missing pinctrl-names property] Link: https://patch.msgid.link/20260108230613.1349060-1-robh@kernel.org Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3326-odroid-go3.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go3.dts b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go3.dts index 35bbaf559ca3..6b0563cb4d3a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-odroid-go3.dts +++ b/arch/arm64/boot/dts/rockchip/rk3326-odroid-go3.dts @@ -14,7 +14,8 @@ joystick_mux_controller: mux-controller { compatible = "gpio-mux"; - pinctrl = <&mux_en_pins>; + pinctrl-0 = <&mux_en_pins>; + pinctrl-names = "default"; #mux-control-cells = <0>; mux-gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>, From 5fc045974cdeafd16b25f2c360b0cf48502dd1c5 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 8 Jan 2026 17:06:23 -0600 Subject: [PATCH 135/443] arm64: dts: rockchip: Fix gpio pinctrl node names The pinctrl node names "gpios" or with "-gpio" suffix collide with GPIO property names creating false warnings. Add a "-pins?" suffix to avoid the issue. Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260108230623.1349310-1-robh@kernel.org Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi | 2 +- arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi index 587e89d7fc5e..8299e9d10c7c 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi @@ -483,7 +483,7 @@ pinctrl-names = "default"; pinctrl-0 = <&q7_thermal_pin &bios_disable_override_hog_pin>; - gpios { + gpio-pins { bios_disable_override_hog_pin: bios-disable-override-hog-pin { rockchip,pins = <3 RK_PD5 RK_FUNC_GPIO &pcfg_pull_down>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts b/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts index 74160cf89188..6d52e3723a4e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts @@ -529,11 +529,11 @@ rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; }; - vsel1_gpio: vsel1-gpio { + vsel1_gpio: vsel1-gpio-pin { rockchip,pins = <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>; }; - vsel2_gpio: vsel2-gpio { + vsel2_gpio: vsel2-gpio-pin { rockchip,pins = <1 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>; }; }; From 56e7cc8dadf91cd2164e5d6dac9258f448d50182 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 8 Jan 2026 17:06:07 -0600 Subject: [PATCH 136/443] arm64: dts: rockchip: Drop unsupported properties "pinctrl-names" is not valid without a pinctrl-N property. "max-freq" is not a defined property name. Maybe it was supposed to be "spi-max-frequency", but changing to that would be a change in behavior. Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260108230607.1348879-1-robh@kernel.org Signed-off-by: Heiko Stuebner --- arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts | 1 - arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts b/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts index 78a7775c3b22..b2de018a7d36 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts @@ -425,7 +425,6 @@ &pcie0 { ep-gpios = <&gpio2 RK_PD4 GPIO_ACTIVE_HIGH>; num-lanes = <2>; - pinctrl-names = "default"; status = "okay"; vpcie12v-supply = <&vcc12v_dcin>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts index eaaca08a7601..810ab6ff4e67 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-pinebook-pro.dts @@ -969,7 +969,6 @@ }; &spi1 { - max-freq = <10000000>; status = "okay"; spiflash: flash@0 { From ebabc32ddb84caf2c018ae6aeca2ca2989a8056b Mon Sep 17 00:00:00 2001 From: Changwoo Min Date: Thu, 8 Jan 2026 14:32:09 +0900 Subject: [PATCH 137/443] PM: EM: Fix yamllint warnings in the EM YNL spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The energy model YNL spec has the following two warnings when checking with yamlint: 3:1 warning missing document start "---" (document-start) 107:13 error wrong indentation: expected 10 but found 12 (indentation) So let’s fix whose lint warnings. Fixes: bd26631ccdfd ("PM: EM: Add em.yaml and autogen files") Suggested-by: Donald Hunter Reviewed-by: Lukasz Luba Reviewed-by: Donald Hunter Signed-off-by: Changwoo Min Link: https://patch.msgid.link/20260108053212.642478-2-changwoo@igalia.com Signed-off-by: Rafael J. Wysocki --- Documentation/netlink/specs/em.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/netlink/specs/em.yaml b/Documentation/netlink/specs/em.yaml index 9905ca482325..0c595a874f08 100644 --- a/Documentation/netlink/specs/em.yaml +++ b/Documentation/netlink/specs/em.yaml @@ -1,5 +1,8 @@ # SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) - +# +# Copyright (c) 2025 Valve Corporation. +# +--- name: em doc: | @@ -104,7 +107,7 @@ operations: attribute-set: pd-table event: attributes: - - pd-id + - pd-id mcgrp: event mcast-groups: From caa07a815d6ee32586beb66f67e7e3c103a02efd Mon Sep 17 00:00:00 2001 From: Changwoo Min Date: Thu, 8 Jan 2026 14:32:10 +0900 Subject: [PATCH 138/443] PM: EM: Rename em.yaml to dev-energymodel.yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The EM YNL specification used many acronyms, including ‘em’, ‘pd’, ‘ps’, etc. While the acronyms are short and convenient, they could be confusing. So, let’s spell them out to be more specific. The following changes were made in the spec. Note that the protocol name cannot exceed GENL_NAMSIZ (16). em -> dev-energymodel pds -> perf-domains pd -> perf-domain pd-id -> perf-domain-id pd-table -> perf-table ps -> perf-state get-pds -> get-perf-domains get-pd-table -> get-perf-table pd-created -> perf-domain-created pd-updated -> perf-domain-updated pd-deleted -> perf-domain-deleted In addition. doc strings were added to the spec. based on the comments in energy_model.h. Two flag attributes (perf-state-flags and perf-domain-flags) were added for easily interpreting the bit flags. Finally, the autogenerated files and em_netlink.c were updated accordingly to reflect the name changes. Suggested-by: Donald Hunter Reviewed-by: Lukasz Luba Reviewed-by: Donald Hunter Signed-off-by: Changwoo Min Link: https://patch.msgid.link/20260108053212.642478-3-changwoo@igalia.com Signed-off-by: Rafael J. Wysocki --- .../netlink/specs/dev-energymodel.yaml | 175 ++++++++++++++++++ Documentation/netlink/specs/em.yaml | 116 ------------ MAINTAINERS | 8 +- include/uapi/linux/dev_energymodel.h | 89 +++++++++ include/uapi/linux/energy_model.h | 63 ------- kernel/power/em_netlink.c | 135 ++++++++------ kernel/power/em_netlink_autogen.c | 44 ++--- kernel/power/em_netlink_autogen.h | 20 +- 8 files changed, 384 insertions(+), 266 deletions(-) create mode 100644 Documentation/netlink/specs/dev-energymodel.yaml delete mode 100644 Documentation/netlink/specs/em.yaml create mode 100644 include/uapi/linux/dev_energymodel.h delete mode 100644 include/uapi/linux/energy_model.h diff --git a/Documentation/netlink/specs/dev-energymodel.yaml b/Documentation/netlink/specs/dev-energymodel.yaml new file mode 100644 index 000000000000..cbc4bc38f23c --- /dev/null +++ b/Documentation/netlink/specs/dev-energymodel.yaml @@ -0,0 +1,175 @@ +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +# +# Copyright (c) 2025 Valve Corporation. +# +--- +name: dev-energymodel + +doc: | + Energy model netlink interface to notify its changes. + +protocol: genetlink + +uapi-header: linux/dev_energymodel.h + +definitions: + - + type: flags + name: perf-state-flags + entries: + - + name: perf-state-inefficient + doc: >- + The performance state is inefficient. There is in this perf-domain, + another performance state with a higher frequency but a lower or + equal power cost. + - + type: flags + name: perf-domain-flags + entries: + - + name: perf-domain-microwatts + doc: >- + The power values are in micro-Watts or some other scale. + - + name: perf-domain-skip-inefficiencies + doc: >- + Skip inefficient states when estimating energy consumption. + - + name: perf-domain-artificial + doc: >- + The power values are artificial and might be created by platform + missing real power information. + +attribute-sets: + - + name: perf-domains + doc: >- + Information on all the performance domains. + attributes: + - + name: perf-domain + type: nest + nested-attributes: perf-domain + multi-attr: true + - + name: perf-domain + doc: >- + Information on a single performance domains. + attributes: + - + name: pad + type: pad + - + name: perf-domain-id + type: u32 + doc: >- + A unique ID number for each performance domain. + - + name: flags + type: u64 + doc: >- + Bitmask of performance domain flags. + enum: perf-domain-flags + - + name: cpus + type: string + doc: >- + CPUs that belong to this performance domain. + - + name: perf-table + doc: >- + Performance states table. + attributes: + - + name: perf-domain-id + type: u32 + doc: >- + A unique ID number for each performance domain. + - + name: perf-state + type: nest + nested-attributes: perf-state + multi-attr: true + - + name: perf-state + doc: >- + Performance state of a performance domain. + attributes: + - + name: pad + type: pad + - + name: performance + type: u64 + doc: >- + CPU performance (capacity) at a given frequency. + - + name: frequency + type: u64 + doc: >- + The frequency in KHz, for consistency with CPUFreq. + - + name: power + type: u64 + doc: >- + The power consumed at this level (by 1 CPU or by a registered + device). It can be a total power: static and dynamic. + - + name: cost + type: u64 + doc: >- + The cost coefficient associated with this level, used during energy + calculation. Equal to: power * max_frequency / frequency. + - + name: flags + type: u64 + doc: >- + Bitmask of performance state flags. + enum: perf-state-flags + +operations: + list: + - + name: get-perf-domains + attribute-set: perf-domains + doc: Get the list of information for all performance domains. + do: + reply: + attributes: + - perf-domain + - + name: get-perf-table + attribute-set: perf-table + doc: Get the energy model table of a performance domain. + do: + request: + attributes: + - perf-domain-id + reply: + attributes: + - perf-domain-id + - perf-state + - + name: perf-domain-created + doc: A performance domain is created. + notify: get-perf-table + mcgrp: event + - + name: perf-domain-updated + doc: A performance domain is updated. + notify: get-perf-table + mcgrp: event + - + name: perf-domain-deleted + doc: A performance domain is deleted. + attribute-set: perf-table + event: + attributes: + - perf-domain-id + mcgrp: event + +mcast-groups: + list: + - + name: event diff --git a/Documentation/netlink/specs/em.yaml b/Documentation/netlink/specs/em.yaml deleted file mode 100644 index 0c595a874f08..000000000000 --- a/Documentation/netlink/specs/em.yaml +++ /dev/null @@ -1,116 +0,0 @@ -# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) -# -# Copyright (c) 2025 Valve Corporation. -# ---- -name: em - -doc: | - Energy model netlink interface to notify its changes. - -protocol: genetlink - -uapi-header: linux/energy_model.h - -attribute-sets: - - - name: pds - attributes: - - - name: pd - type: nest - nested-attributes: pd - multi-attr: true - - - name: pd - attributes: - - - name: pad - type: pad - - - name: pd-id - type: u32 - - - name: flags - type: u64 - - - name: cpus - type: string - - - name: pd-table - attributes: - - - name: pd-id - type: u32 - - - name: ps - type: nest - nested-attributes: ps - multi-attr: true - - - name: ps - attributes: - - - name: pad - type: pad - - - name: performance - type: u64 - - - name: frequency - type: u64 - - - name: power - type: u64 - - - name: cost - type: u64 - - - name: flags - type: u64 - -operations: - list: - - - name: get-pds - attribute-set: pds - doc: Get the list of information for all performance domains. - do: - reply: - attributes: - - pd - - - name: get-pd-table - attribute-set: pd-table - doc: Get the energy model table of a performance domain. - do: - request: - attributes: - - pd-id - reply: - attributes: - - pd-id - - ps - - - name: pd-created - doc: A performance domain is created. - notify: get-pd-table - mcgrp: event - - - name: pd-updated - doc: A performance domain is updated. - notify: get-pd-table - mcgrp: event - - - name: pd-deleted - doc: A performance domain is deleted. - attribute-set: pd-table - event: - attributes: - - pd-id - mcgrp: event - -mcast-groups: - list: - - - name: event diff --git a/MAINTAINERS b/MAINTAINERS index 765ad2daa218..1e208243b28e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9298,12 +9298,12 @@ M: Lukasz Luba M: "Rafael J. Wysocki" L: linux-pm@vger.kernel.org S: Maintained -F: kernel/power/energy_model.c -F: include/linux/energy_model.h +F: Documentation/netlink/specs/dev-energymodel.yaml F: Documentation/power/energy-model.rst -F: Documentation/netlink/specs/em.yaml -F: include/uapi/linux/energy_model.h +F: include/linux/energy_model.h +F: include/uapi/linux/dev_energymodel.h F: kernel/power/em_netlink*.* +F: kernel/power/energy_model.c EPAPR HYPERVISOR BYTE CHANNEL DEVICE DRIVER M: Laurentiu Tudor diff --git a/include/uapi/linux/dev_energymodel.h b/include/uapi/linux/dev_energymodel.h new file mode 100644 index 000000000000..3399967e1f93 --- /dev/null +++ b/include/uapi/linux/dev_energymodel.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/dev-energymodel.yaml */ +/* YNL-GEN uapi header */ +/* To regenerate run: tools/net/ynl/ynl-regen.sh */ + +#ifndef _UAPI_LINUX_DEV_ENERGYMODEL_H +#define _UAPI_LINUX_DEV_ENERGYMODEL_H + +#define DEV_ENERGYMODEL_FAMILY_NAME "dev-energymodel" +#define DEV_ENERGYMODEL_FAMILY_VERSION 1 + +/** + * enum dev_energymodel_perf_state_flags + * @DEV_ENERGYMODEL_PERF_STATE_FLAGS_PERF_STATE_INEFFICIENT: The performance + * state is inefficient. There is in this perf-domain, another performance + * state with a higher frequency but a lower or equal power cost. + */ +enum dev_energymodel_perf_state_flags { + DEV_ENERGYMODEL_PERF_STATE_FLAGS_PERF_STATE_INEFFICIENT = 1, +}; + +/** + * enum dev_energymodel_perf_domain_flags + * @DEV_ENERGYMODEL_PERF_DOMAIN_FLAGS_PERF_DOMAIN_MICROWATTS: The power values + * are in micro-Watts or some other scale. + * @DEV_ENERGYMODEL_PERF_DOMAIN_FLAGS_PERF_DOMAIN_SKIP_INEFFICIENCIES: Skip + * inefficient states when estimating energy consumption. + * @DEV_ENERGYMODEL_PERF_DOMAIN_FLAGS_PERF_DOMAIN_ARTIFICIAL: The power values + * are artificial and might be created by platform missing real power + * information. + */ +enum dev_energymodel_perf_domain_flags { + DEV_ENERGYMODEL_PERF_DOMAIN_FLAGS_PERF_DOMAIN_MICROWATTS = 1, + DEV_ENERGYMODEL_PERF_DOMAIN_FLAGS_PERF_DOMAIN_SKIP_INEFFICIENCIES = 2, + DEV_ENERGYMODEL_PERF_DOMAIN_FLAGS_PERF_DOMAIN_ARTIFICIAL = 4, +}; + +enum { + DEV_ENERGYMODEL_A_PERF_DOMAINS_PERF_DOMAIN = 1, + + __DEV_ENERGYMODEL_A_PERF_DOMAINS_MAX, + DEV_ENERGYMODEL_A_PERF_DOMAINS_MAX = (__DEV_ENERGYMODEL_A_PERF_DOMAINS_MAX - 1) +}; + +enum { + DEV_ENERGYMODEL_A_PERF_DOMAIN_PAD = 1, + DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID, + DEV_ENERGYMODEL_A_PERF_DOMAIN_FLAGS, + DEV_ENERGYMODEL_A_PERF_DOMAIN_CPUS, + + __DEV_ENERGYMODEL_A_PERF_DOMAIN_MAX, + DEV_ENERGYMODEL_A_PERF_DOMAIN_MAX = (__DEV_ENERGYMODEL_A_PERF_DOMAIN_MAX - 1) +}; + +enum { + DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID = 1, + DEV_ENERGYMODEL_A_PERF_TABLE_PERF_STATE, + + __DEV_ENERGYMODEL_A_PERF_TABLE_MAX, + DEV_ENERGYMODEL_A_PERF_TABLE_MAX = (__DEV_ENERGYMODEL_A_PERF_TABLE_MAX - 1) +}; + +enum { + DEV_ENERGYMODEL_A_PERF_STATE_PAD = 1, + DEV_ENERGYMODEL_A_PERF_STATE_PERFORMANCE, + DEV_ENERGYMODEL_A_PERF_STATE_FREQUENCY, + DEV_ENERGYMODEL_A_PERF_STATE_POWER, + DEV_ENERGYMODEL_A_PERF_STATE_COST, + DEV_ENERGYMODEL_A_PERF_STATE_FLAGS, + + __DEV_ENERGYMODEL_A_PERF_STATE_MAX, + DEV_ENERGYMODEL_A_PERF_STATE_MAX = (__DEV_ENERGYMODEL_A_PERF_STATE_MAX - 1) +}; + +enum { + DEV_ENERGYMODEL_CMD_GET_PERF_DOMAINS = 1, + DEV_ENERGYMODEL_CMD_GET_PERF_TABLE, + DEV_ENERGYMODEL_CMD_PERF_DOMAIN_CREATED, + DEV_ENERGYMODEL_CMD_PERF_DOMAIN_UPDATED, + DEV_ENERGYMODEL_CMD_PERF_DOMAIN_DELETED, + + __DEV_ENERGYMODEL_CMD_MAX, + DEV_ENERGYMODEL_CMD_MAX = (__DEV_ENERGYMODEL_CMD_MAX - 1) +}; + +#define DEV_ENERGYMODEL_MCGRP_EVENT "event" + +#endif /* _UAPI_LINUX_DEV_ENERGYMODEL_H */ diff --git a/include/uapi/linux/energy_model.h b/include/uapi/linux/energy_model.h deleted file mode 100644 index 0bcad967854f..000000000000 --- a/include/uapi/linux/energy_model.h +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ -/* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/em.yaml */ -/* YNL-GEN uapi header */ -/* To regenerate run: tools/net/ynl/ynl-regen.sh */ - -#ifndef _UAPI_LINUX_ENERGY_MODEL_H -#define _UAPI_LINUX_ENERGY_MODEL_H - -#define EM_FAMILY_NAME "em" -#define EM_FAMILY_VERSION 1 - -enum { - EM_A_PDS_PD = 1, - - __EM_A_PDS_MAX, - EM_A_PDS_MAX = (__EM_A_PDS_MAX - 1) -}; - -enum { - EM_A_PD_PAD = 1, - EM_A_PD_PD_ID, - EM_A_PD_FLAGS, - EM_A_PD_CPUS, - - __EM_A_PD_MAX, - EM_A_PD_MAX = (__EM_A_PD_MAX - 1) -}; - -enum { - EM_A_PD_TABLE_PD_ID = 1, - EM_A_PD_TABLE_PS, - - __EM_A_PD_TABLE_MAX, - EM_A_PD_TABLE_MAX = (__EM_A_PD_TABLE_MAX - 1) -}; - -enum { - EM_A_PS_PAD = 1, - EM_A_PS_PERFORMANCE, - EM_A_PS_FREQUENCY, - EM_A_PS_POWER, - EM_A_PS_COST, - EM_A_PS_FLAGS, - - __EM_A_PS_MAX, - EM_A_PS_MAX = (__EM_A_PS_MAX - 1) -}; - -enum { - EM_CMD_GET_PDS = 1, - EM_CMD_GET_PD_TABLE, - EM_CMD_PD_CREATED, - EM_CMD_PD_UPDATED, - EM_CMD_PD_DELETED, - - __EM_CMD_MAX, - EM_CMD_MAX = (__EM_CMD_MAX - 1) -}; - -#define EM_MCGRP_EVENT "event" - -#endif /* _UAPI_LINUX_ENERGY_MODEL_H */ diff --git a/kernel/power/em_netlink.c b/kernel/power/em_netlink.c index 4b85da138a06..6f6238c465bb 100644 --- a/kernel/power/em_netlink.c +++ b/kernel/power/em_netlink.c @@ -12,27 +12,31 @@ #include #include #include -#include +#include #include "em_netlink.h" #include "em_netlink_autogen.h" -#define EM_A_PD_CPUS_LEN 256 +#define DEV_ENERGYMODEL_A_PERF_DOMAIN_CPUS_LEN 256 /*************************** Command encoding ********************************/ static int __em_nl_get_pd_size(struct em_perf_domain *pd, void *data) { - char cpus_buf[EM_A_PD_CPUS_LEN]; + char cpus_buf[DEV_ENERGYMODEL_A_PERF_DOMAIN_CPUS_LEN]; int *tot_msg_sz = data; int msg_sz, cpus_sz; cpus_sz = snprintf(cpus_buf, sizeof(cpus_buf), "%*pb", cpumask_pr_args(to_cpumask(pd->cpus))); - msg_sz = nla_total_size(0) + /* EM_A_PDS_PD */ - nla_total_size(sizeof(u32)) + /* EM_A_PD_PD_ID */ - nla_total_size_64bit(sizeof(u64)) + /* EM_A_PD_FLAGS */ - nla_total_size(cpus_sz); /* EM_A_PD_CPUS */ + msg_sz = nla_total_size(0) + + /* DEV_ENERGYMODEL_A_PERF_DOMAINS_PERF_DOMAIN */ + nla_total_size(sizeof(u32)) + + /* DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID */ + nla_total_size_64bit(sizeof(u64)) + + /* DEV_ENERGYMODEL_A_PERF_DOMAIN_FLAGS */ + nla_total_size(cpus_sz); + /* DEV_ENERGYMODEL_A_PERF_DOMAIN_CPUS */ *tot_msg_sz += nlmsg_total_size(genlmsg_msg_size(msg_sz)); return 0; @@ -40,23 +44,26 @@ static int __em_nl_get_pd_size(struct em_perf_domain *pd, void *data) static int __em_nl_get_pd(struct em_perf_domain *pd, void *data) { - char cpus_buf[EM_A_PD_CPUS_LEN]; + char cpus_buf[DEV_ENERGYMODEL_A_PERF_DOMAIN_CPUS_LEN]; struct sk_buff *msg = data; struct nlattr *entry; - entry = nla_nest_start(msg, EM_A_PDS_PD); + entry = nla_nest_start(msg, + DEV_ENERGYMODEL_A_PERF_DOMAINS_PERF_DOMAIN); if (!entry) goto out_cancel_nest; - if (nla_put_u32(msg, EM_A_PD_PD_ID, pd->id)) + if (nla_put_u32(msg, DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID, + pd->id)) goto out_cancel_nest; - if (nla_put_u64_64bit(msg, EM_A_PD_FLAGS, pd->flags, EM_A_PD_PAD)) + if (nla_put_u64_64bit(msg, DEV_ENERGYMODEL_A_PERF_DOMAIN_FLAGS, + pd->flags, DEV_ENERGYMODEL_A_PERF_DOMAIN_PAD)) goto out_cancel_nest; snprintf(cpus_buf, sizeof(cpus_buf), "%*pb", cpumask_pr_args(to_cpumask(pd->cpus))); - if (nla_put_string(msg, EM_A_PD_CPUS, cpus_buf)) + if (nla_put_string(msg, DEV_ENERGYMODEL_A_PERF_DOMAIN_CPUS, cpus_buf)) goto out_cancel_nest; nla_nest_end(msg, entry); @@ -69,7 +76,8 @@ out_cancel_nest: return -EMSGSIZE; } -int em_nl_get_pds_doit(struct sk_buff *skb, struct genl_info *info) +int dev_energymodel_nl_get_perf_domains_doit(struct sk_buff *skb, + struct genl_info *info) { struct sk_buff *msg; void *hdr; @@ -82,7 +90,7 @@ int em_nl_get_pds_doit(struct sk_buff *skb, struct genl_info *info) if (!msg) return -ENOMEM; - hdr = genlmsg_put_reply(msg, info, &em_nl_family, 0, cmd); + hdr = genlmsg_put_reply(msg, info, &dev_energymodel_nl_family, 0, cmd); if (!hdr) goto out_free_msg; @@ -107,10 +115,10 @@ static struct em_perf_domain *__em_nl_get_pd_table_id(struct nlattr **attrs) struct em_perf_domain *pd; int id; - if (!attrs[EM_A_PD_TABLE_PD_ID]) + if (!attrs[DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID]) return NULL; - id = nla_get_u32(attrs[EM_A_PD_TABLE_PD_ID]); + id = nla_get_u32(attrs[DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID]); pd = em_perf_domain_get_by_id(id); return pd; } @@ -119,25 +127,34 @@ static int __em_nl_get_pd_table_size(const struct em_perf_domain *pd) { int id_sz, ps_sz; - id_sz = nla_total_size(sizeof(u32)); /* EM_A_PD_TABLE_PD_ID */ - ps_sz = nla_total_size(0) + /* EM_A_PD_TABLE_PS */ - nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_PERFORMANCE */ - nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_FREQUENCY */ - nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_POWER */ - nla_total_size_64bit(sizeof(u64)) + /* EM_A_PS_COST */ - nla_total_size_64bit(sizeof(u64)); /* EM_A_PS_FLAGS */ + id_sz = nla_total_size(sizeof(u32)); + /* DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID */ + ps_sz = nla_total_size(0) + + /* DEV_ENERGYMODEL_A_PERF_TABLE_PERF_STATE */ + nla_total_size_64bit(sizeof(u64)) + + /* DEV_ENERGYMODEL_A_PERF_STATE_PERFORMANCE */ + nla_total_size_64bit(sizeof(u64)) + + /* DEV_ENERGYMODEL_A_PERF_STATE_FREQUENCY */ + nla_total_size_64bit(sizeof(u64)) + + /* DEV_ENERGYMODEL_A_PERF_STATE_POWER */ + nla_total_size_64bit(sizeof(u64)) + + /* DEV_ENERGYMODEL_A_PERF_STATE_COST */ + nla_total_size_64bit(sizeof(u64)); + /* DEV_ENERGYMODEL_A_PERF_STATE_FLAGS */ ps_sz *= pd->nr_perf_states; return nlmsg_total_size(genlmsg_msg_size(id_sz + ps_sz)); } -static int __em_nl_get_pd_table(struct sk_buff *msg, const struct em_perf_domain *pd) +static +int __em_nl_get_pd_table(struct sk_buff *msg, const struct em_perf_domain *pd) { struct em_perf_state *table, *ps; struct nlattr *entry; int i; - if (nla_put_u32(msg, EM_A_PD_TABLE_PD_ID, pd->id)) + if (nla_put_u32(msg, DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID, + pd->id)) goto out_err; rcu_read_lock(); @@ -146,24 +163,35 @@ static int __em_nl_get_pd_table(struct sk_buff *msg, const struct em_perf_domain for (i = 0; i < pd->nr_perf_states; i++) { ps = &table[i]; - entry = nla_nest_start(msg, EM_A_PD_TABLE_PS); + entry = nla_nest_start(msg, + DEV_ENERGYMODEL_A_PERF_TABLE_PERF_STATE); if (!entry) goto out_unlock_ps; - if (nla_put_u64_64bit(msg, EM_A_PS_PERFORMANCE, - ps->performance, EM_A_PS_PAD)) + if (nla_put_u64_64bit(msg, + DEV_ENERGYMODEL_A_PERF_STATE_PERFORMANCE, + ps->performance, + DEV_ENERGYMODEL_A_PERF_STATE_PAD)) goto out_cancel_ps_nest; - if (nla_put_u64_64bit(msg, EM_A_PS_FREQUENCY, - ps->frequency, EM_A_PS_PAD)) + if (nla_put_u64_64bit(msg, + DEV_ENERGYMODEL_A_PERF_STATE_FREQUENCY, + ps->frequency, + DEV_ENERGYMODEL_A_PERF_STATE_PAD)) goto out_cancel_ps_nest; - if (nla_put_u64_64bit(msg, EM_A_PS_POWER, - ps->power, EM_A_PS_PAD)) + if (nla_put_u64_64bit(msg, + DEV_ENERGYMODEL_A_PERF_STATE_POWER, + ps->power, + DEV_ENERGYMODEL_A_PERF_STATE_PAD)) goto out_cancel_ps_nest; - if (nla_put_u64_64bit(msg, EM_A_PS_COST, - ps->cost, EM_A_PS_PAD)) + if (nla_put_u64_64bit(msg, + DEV_ENERGYMODEL_A_PERF_STATE_COST, + ps->cost, + DEV_ENERGYMODEL_A_PERF_STATE_PAD)) goto out_cancel_ps_nest; - if (nla_put_u64_64bit(msg, EM_A_PS_FLAGS, - ps->flags, EM_A_PS_PAD)) + if (nla_put_u64_64bit(msg, + DEV_ENERGYMODEL_A_PERF_STATE_FLAGS, + ps->flags, + DEV_ENERGYMODEL_A_PERF_STATE_PAD)) goto out_cancel_ps_nest; nla_nest_end(msg, entry); @@ -179,7 +207,8 @@ out_err: return -EMSGSIZE; } -int em_nl_get_pd_table_doit(struct sk_buff *skb, struct genl_info *info) +int dev_energymodel_nl_get_perf_table_doit(struct sk_buff *skb, + struct genl_info *info) { int cmd = info->genlhdr->cmd; int msg_sz, ret = -EMSGSIZE; @@ -197,7 +226,7 @@ int em_nl_get_pd_table_doit(struct sk_buff *skb, struct genl_info *info) if (!msg) return -ENOMEM; - hdr = genlmsg_put_reply(msg, info, &em_nl_family, 0, cmd); + hdr = genlmsg_put_reply(msg, info, &dev_energymodel_nl_family, 0, cmd); if (!hdr) goto out_free_msg; @@ -221,7 +250,7 @@ static void __em_notify_pd_table(const struct em_perf_domain *pd, int ntf_type) int msg_sz, ret = -EMSGSIZE; void *hdr; - if (!genl_has_listeners(&em_nl_family, &init_net, EM_NLGRP_EVENT)) + if (!genl_has_listeners(&dev_energymodel_nl_family, &init_net, DEV_ENERGYMODEL_NLGRP_EVENT)) return; msg_sz = __em_nl_get_pd_table_size(pd); @@ -230,7 +259,7 @@ static void __em_notify_pd_table(const struct em_perf_domain *pd, int ntf_type) if (!msg) return; - hdr = genlmsg_put(msg, 0, 0, &em_nl_family, 0, ntf_type); + hdr = genlmsg_put(msg, 0, 0, &dev_energymodel_nl_family, 0, ntf_type); if (!hdr) goto out_free_msg; @@ -240,28 +269,28 @@ static void __em_notify_pd_table(const struct em_perf_domain *pd, int ntf_type) genlmsg_end(msg, hdr); - genlmsg_multicast(&em_nl_family, msg, 0, EM_NLGRP_EVENT, GFP_KERNEL); + genlmsg_multicast(&dev_energymodel_nl_family, msg, 0, + DEV_ENERGYMODEL_NLGRP_EVENT, GFP_KERNEL); return; out_free_msg: nlmsg_free(msg); - return; } void em_notify_pd_created(const struct em_perf_domain *pd) { - __em_notify_pd_table(pd, EM_CMD_PD_CREATED); + __em_notify_pd_table(pd, DEV_ENERGYMODEL_CMD_PERF_DOMAIN_CREATED); } void em_notify_pd_updated(const struct em_perf_domain *pd) { - __em_notify_pd_table(pd, EM_CMD_PD_UPDATED); + __em_notify_pd_table(pd, DEV_ENERGYMODEL_CMD_PERF_DOMAIN_UPDATED); } static int __em_notify_pd_deleted_size(const struct em_perf_domain *pd) { - int id_sz = nla_total_size(sizeof(u32)); /* EM_A_PD_TABLE_PD_ID */ + int id_sz = nla_total_size(sizeof(u32)); /* DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID */ return nlmsg_total_size(genlmsg_msg_size(id_sz)); } @@ -272,7 +301,8 @@ void em_notify_pd_deleted(const struct em_perf_domain *pd) void *hdr; int msg_sz; - if (!genl_has_listeners(&em_nl_family, &init_net, EM_NLGRP_EVENT)) + if (!genl_has_listeners(&dev_energymodel_nl_family, &init_net, + DEV_ENERGYMODEL_NLGRP_EVENT)) return; msg_sz = __em_notify_pd_deleted_size(pd); @@ -281,28 +311,29 @@ void em_notify_pd_deleted(const struct em_perf_domain *pd) if (!msg) return; - hdr = genlmsg_put(msg, 0, 0, &em_nl_family, 0, EM_CMD_PD_DELETED); + hdr = genlmsg_put(msg, 0, 0, &dev_energymodel_nl_family, 0, + DEV_ENERGYMODEL_CMD_PERF_DOMAIN_DELETED); if (!hdr) goto out_free_msg; - if (nla_put_u32(msg, EM_A_PD_TABLE_PD_ID, pd->id)) { + if (nla_put_u32(msg, DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID, + pd->id)) goto out_free_msg; - } genlmsg_end(msg, hdr); - genlmsg_multicast(&em_nl_family, msg, 0, EM_NLGRP_EVENT, GFP_KERNEL); + genlmsg_multicast(&dev_energymodel_nl_family, msg, 0, + DEV_ENERGYMODEL_NLGRP_EVENT, GFP_KERNEL); return; out_free_msg: nlmsg_free(msg); - return; } /**************************** Initialization *********************************/ static int __init em_netlink_init(void) { - return genl_register_family(&em_nl_family); + return genl_register_family(&dev_energymodel_nl_family); } postcore_initcall(em_netlink_init); diff --git a/kernel/power/em_netlink_autogen.c b/kernel/power/em_netlink_autogen.c index ceb3b2bb6ebe..44acef0e7df2 100644 --- a/kernel/power/em_netlink_autogen.c +++ b/kernel/power/em_netlink_autogen.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) /* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/em.yaml */ +/* Documentation/netlink/specs/dev-energymodel.yaml */ /* YNL-GEN kernel source */ /* To regenerate run: tools/net/ynl/ynl-regen.sh */ @@ -9,41 +9,41 @@ #include "em_netlink_autogen.h" -#include +#include -/* EM_CMD_GET_PD_TABLE - do */ -static const struct nla_policy em_get_pd_table_nl_policy[EM_A_PD_TABLE_PD_ID + 1] = { - [EM_A_PD_TABLE_PD_ID] = { .type = NLA_U32, }, +/* DEV_ENERGYMODEL_CMD_GET_PERF_TABLE - do */ +static const struct nla_policy dev_energymodel_get_perf_table_nl_policy[DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID + 1] = { + [DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID] = { .type = NLA_U32, }, }; -/* Ops table for em */ -static const struct genl_split_ops em_nl_ops[] = { +/* Ops table for dev_energymodel */ +static const struct genl_split_ops dev_energymodel_nl_ops[] = { { - .cmd = EM_CMD_GET_PDS, - .doit = em_nl_get_pds_doit, + .cmd = DEV_ENERGYMODEL_CMD_GET_PERF_DOMAINS, + .doit = dev_energymodel_nl_get_perf_domains_doit, .flags = GENL_CMD_CAP_DO, }, { - .cmd = EM_CMD_GET_PD_TABLE, - .doit = em_nl_get_pd_table_doit, - .policy = em_get_pd_table_nl_policy, - .maxattr = EM_A_PD_TABLE_PD_ID, + .cmd = DEV_ENERGYMODEL_CMD_GET_PERF_TABLE, + .doit = dev_energymodel_nl_get_perf_table_doit, + .policy = dev_energymodel_get_perf_table_nl_policy, + .maxattr = DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID, .flags = GENL_CMD_CAP_DO, }, }; -static const struct genl_multicast_group em_nl_mcgrps[] = { - [EM_NLGRP_EVENT] = { "event", }, +static const struct genl_multicast_group dev_energymodel_nl_mcgrps[] = { + [DEV_ENERGYMODEL_NLGRP_EVENT] = { "event", }, }; -struct genl_family em_nl_family __ro_after_init = { - .name = EM_FAMILY_NAME, - .version = EM_FAMILY_VERSION, +struct genl_family dev_energymodel_nl_family __ro_after_init = { + .name = DEV_ENERGYMODEL_FAMILY_NAME, + .version = DEV_ENERGYMODEL_FAMILY_VERSION, .netnsok = true, .parallel_ops = true, .module = THIS_MODULE, - .split_ops = em_nl_ops, - .n_split_ops = ARRAY_SIZE(em_nl_ops), - .mcgrps = em_nl_mcgrps, - .n_mcgrps = ARRAY_SIZE(em_nl_mcgrps), + .split_ops = dev_energymodel_nl_ops, + .n_split_ops = ARRAY_SIZE(dev_energymodel_nl_ops), + .mcgrps = dev_energymodel_nl_mcgrps, + .n_mcgrps = ARRAY_SIZE(dev_energymodel_nl_mcgrps), }; diff --git a/kernel/power/em_netlink_autogen.h b/kernel/power/em_netlink_autogen.h index 140ab548103c..f7e4bddcbd53 100644 --- a/kernel/power/em_netlink_autogen.h +++ b/kernel/power/em_netlink_autogen.h @@ -1,24 +1,26 @@ /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ /* Do not edit directly, auto-generated from: */ -/* Documentation/netlink/specs/em.yaml */ +/* Documentation/netlink/specs/dev-energymodel.yaml */ /* YNL-GEN kernel header */ /* To regenerate run: tools/net/ynl/ynl-regen.sh */ -#ifndef _LINUX_EM_GEN_H -#define _LINUX_EM_GEN_H +#ifndef _LINUX_DEV_ENERGYMODEL_GEN_H +#define _LINUX_DEV_ENERGYMODEL_GEN_H #include #include -#include +#include -int em_nl_get_pds_doit(struct sk_buff *skb, struct genl_info *info); -int em_nl_get_pd_table_doit(struct sk_buff *skb, struct genl_info *info); +int dev_energymodel_nl_get_perf_domains_doit(struct sk_buff *skb, + struct genl_info *info); +int dev_energymodel_nl_get_perf_table_doit(struct sk_buff *skb, + struct genl_info *info); enum { - EM_NLGRP_EVENT, + DEV_ENERGYMODEL_NLGRP_EVENT, }; -extern struct genl_family em_nl_family; +extern struct genl_family dev_energymodel_nl_family; -#endif /* _LINUX_EM_GEN_H */ +#endif /* _LINUX_DEV_ENERGYMODEL_GEN_H */ From d29b900cf412c31f18bab67d04db619f64acb43d Mon Sep 17 00:00:00 2001 From: Changwoo Min Date: Thu, 8 Jan 2026 14:32:11 +0900 Subject: [PATCH 139/443] PM: EM: Change cpus' type from string to u64 array in the EM YNL spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the cpus attribute was a string format which was a "%*pb" stringification of a bitmap. That is not very consumable for a UAPI, so let’s change it to an u64 array of CPU ids. Suggested-by: Donald Hunter Reviewed-by: Lukasz Luba Reviewed-by: Donald Hunter Signed-off-by: Changwoo Min Link: https://patch.msgid.link/20260108053212.642478-4-changwoo@igalia.com Signed-off-by: Rafael J. Wysocki --- .../netlink/specs/dev-energymodel.yaml | 3 ++- kernel/power/em_netlink.c | 22 +++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Documentation/netlink/specs/dev-energymodel.yaml b/Documentation/netlink/specs/dev-energymodel.yaml index cbc4bc38f23c..af8b8f72f722 100644 --- a/Documentation/netlink/specs/dev-energymodel.yaml +++ b/Documentation/netlink/specs/dev-energymodel.yaml @@ -73,7 +73,8 @@ attribute-sets: enum: perf-domain-flags - name: cpus - type: string + type: u64 + multi-attr: true doc: >- CPUs that belong to this performance domain. - diff --git a/kernel/power/em_netlink.c b/kernel/power/em_netlink.c index 6f6238c465bb..b6edb018c65a 100644 --- a/kernel/power/em_netlink.c +++ b/kernel/power/em_netlink.c @@ -17,17 +17,14 @@ #include "em_netlink.h" #include "em_netlink_autogen.h" -#define DEV_ENERGYMODEL_A_PERF_DOMAIN_CPUS_LEN 256 - /*************************** Command encoding ********************************/ static int __em_nl_get_pd_size(struct em_perf_domain *pd, void *data) { - char cpus_buf[DEV_ENERGYMODEL_A_PERF_DOMAIN_CPUS_LEN]; + int nr_cpus, msg_sz, cpus_sz; int *tot_msg_sz = data; - int msg_sz, cpus_sz; - cpus_sz = snprintf(cpus_buf, sizeof(cpus_buf), "%*pb", - cpumask_pr_args(to_cpumask(pd->cpus))); + nr_cpus = cpumask_weight(to_cpumask(pd->cpus)); + cpus_sz = nla_total_size_64bit(sizeof(u64)) * nr_cpus; msg_sz = nla_total_size(0) + /* DEV_ENERGYMODEL_A_PERF_DOMAINS_PERF_DOMAIN */ @@ -44,9 +41,10 @@ static int __em_nl_get_pd_size(struct em_perf_domain *pd, void *data) static int __em_nl_get_pd(struct em_perf_domain *pd, void *data) { - char cpus_buf[DEV_ENERGYMODEL_A_PERF_DOMAIN_CPUS_LEN]; struct sk_buff *msg = data; + struct cpumask *cpumask; struct nlattr *entry; + int cpu; entry = nla_nest_start(msg, DEV_ENERGYMODEL_A_PERF_DOMAINS_PERF_DOMAIN); @@ -61,10 +59,12 @@ static int __em_nl_get_pd(struct em_perf_domain *pd, void *data) pd->flags, DEV_ENERGYMODEL_A_PERF_DOMAIN_PAD)) goto out_cancel_nest; - snprintf(cpus_buf, sizeof(cpus_buf), "%*pb", - cpumask_pr_args(to_cpumask(pd->cpus))); - if (nla_put_string(msg, DEV_ENERGYMODEL_A_PERF_DOMAIN_CPUS, cpus_buf)) - goto out_cancel_nest; + cpumask = to_cpumask(pd->cpus); + for_each_cpu(cpu, cpumask) { + if (nla_put_u64_64bit(msg, DEV_ENERGYMODEL_A_PERF_DOMAIN_CPUS, + cpu, DEV_ENERGYMODEL_A_PERF_DOMAIN_PAD)) + goto out_cancel_nest; + } nla_nest_end(msg, entry); From 380ff27af25e49e2cb2ff8fd0ecd7c95be2976ee Mon Sep 17 00:00:00 2001 From: Changwoo Min Date: Thu, 8 Jan 2026 14:32:12 +0900 Subject: [PATCH 140/443] PM: EM: Add dump to get-perf-domains in the EM YNL spec Add dump to get-perf-domains, so that a user can fetch either information about a specific performance domain with do or information about all performance domains with dump. Share the reply format of do and dump using perf-domain-attrs, so remove perf-domains. The YNL spec, autogenerated files, and the do implementation are updated, and the dump implementation is added. Suggested-by: Donald Hunter Reviewed-by: Lukasz Luba Reviewed-by: Donald Hunter Signed-off-by: Changwoo Min Link: https://patch.msgid.link/20260108053212.642478-5-changwoo@igalia.com Signed-off-by: Rafael J. Wysocki --- .../netlink/specs/dev-energymodel.yaml | 25 ++++--- include/uapi/linux/dev_energymodel.h | 7 -- kernel/power/em_netlink.c | 68 ++++++++++++++----- kernel/power/em_netlink_autogen.c | 16 ++++- kernel/power/em_netlink_autogen.h | 2 + 5 files changed, 80 insertions(+), 38 deletions(-) diff --git a/Documentation/netlink/specs/dev-energymodel.yaml b/Documentation/netlink/specs/dev-energymodel.yaml index af8b8f72f722..11faabfdfbe8 100644 --- a/Documentation/netlink/specs/dev-energymodel.yaml +++ b/Documentation/netlink/specs/dev-energymodel.yaml @@ -42,16 +42,6 @@ definitions: missing real power information. attribute-sets: - - - name: perf-domains - doc: >- - Information on all the performance domains. - attributes: - - - name: perf-domain - type: nest - nested-attributes: perf-domain - multi-attr: true - name: perf-domain doc: >- @@ -133,12 +123,21 @@ operations: list: - name: get-perf-domains - attribute-set: perf-domains + attribute-set: perf-domain doc: Get the list of information for all performance domains. do: - reply: + request: attributes: - - perf-domain + - perf-domain-id + reply: + attributes: &perf-domain-attrs + - pad + - perf-domain-id + - flags + - cpus + dump: + reply: + attributes: *perf-domain-attrs - name: get-perf-table attribute-set: perf-table diff --git a/include/uapi/linux/dev_energymodel.h b/include/uapi/linux/dev_energymodel.h index 3399967e1f93..355d8885c9a0 100644 --- a/include/uapi/linux/dev_energymodel.h +++ b/include/uapi/linux/dev_energymodel.h @@ -36,13 +36,6 @@ enum dev_energymodel_perf_domain_flags { DEV_ENERGYMODEL_PERF_DOMAIN_FLAGS_PERF_DOMAIN_ARTIFICIAL = 4, }; -enum { - DEV_ENERGYMODEL_A_PERF_DOMAINS_PERF_DOMAIN = 1, - - __DEV_ENERGYMODEL_A_PERF_DOMAINS_MAX, - DEV_ENERGYMODEL_A_PERF_DOMAINS_MAX = (__DEV_ENERGYMODEL_A_PERF_DOMAINS_MAX - 1) -}; - enum { DEV_ENERGYMODEL_A_PERF_DOMAIN_PAD = 1, DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID, diff --git a/kernel/power/em_netlink.c b/kernel/power/em_netlink.c index b6edb018c65a..5a611d3950fd 100644 --- a/kernel/power/em_netlink.c +++ b/kernel/power/em_netlink.c @@ -18,6 +18,13 @@ #include "em_netlink_autogen.h" /*************************** Command encoding ********************************/ +struct dump_ctx { + int idx; + int start; + struct sk_buff *skb; + struct netlink_callback *cb; +}; + static int __em_nl_get_pd_size(struct em_perf_domain *pd, void *data) { int nr_cpus, msg_sz, cpus_sz; @@ -43,14 +50,8 @@ static int __em_nl_get_pd(struct em_perf_domain *pd, void *data) { struct sk_buff *msg = data; struct cpumask *cpumask; - struct nlattr *entry; int cpu; - entry = nla_nest_start(msg, - DEV_ENERGYMODEL_A_PERF_DOMAINS_PERF_DOMAIN); - if (!entry) - goto out_cancel_nest; - if (nla_put_u32(msg, DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID, pd->id)) goto out_cancel_nest; @@ -66,26 +67,50 @@ static int __em_nl_get_pd(struct em_perf_domain *pd, void *data) goto out_cancel_nest; } - nla_nest_end(msg, entry); - return 0; out_cancel_nest: - nla_nest_cancel(msg, entry); - return -EMSGSIZE; } +static int __em_nl_get_pd_for_dump(struct em_perf_domain *pd, void *data) +{ + const struct genl_info *info; + struct dump_ctx *ctx = data; + void *hdr; + int ret; + + if (ctx->idx++ < ctx->start) + return 0; + + info = genl_info_dump(ctx->cb); + hdr = genlmsg_iput(ctx->skb, info); + if (!hdr) { + genlmsg_cancel(ctx->skb, hdr); + return -EMSGSIZE; + } + + ret = __em_nl_get_pd(pd, ctx->skb); + genlmsg_end(ctx->skb, hdr); + return ret; +} + int dev_energymodel_nl_get_perf_domains_doit(struct sk_buff *skb, struct genl_info *info) { + int id, ret = -EMSGSIZE, msg_sz = 0; + int cmd = info->genlhdr->cmd; + struct em_perf_domain *pd; struct sk_buff *msg; void *hdr; - int cmd = info->genlhdr->cmd; - int ret = -EMSGSIZE, msg_sz = 0; - for_each_em_perf_domain(__em_nl_get_pd_size, &msg_sz); + if (!info->attrs[DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID]) + return -EINVAL; + id = nla_get_u32(info->attrs[DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID]); + pd = em_perf_domain_get_by_id(id); + + __em_nl_get_pd_size(pd, &msg_sz); msg = genlmsg_new(msg_sz, GFP_KERNEL); if (!msg) return -ENOMEM; @@ -94,10 +119,9 @@ int dev_energymodel_nl_get_perf_domains_doit(struct sk_buff *skb, if (!hdr) goto out_free_msg; - ret = for_each_em_perf_domain(__em_nl_get_pd, msg); + ret = __em_nl_get_pd(pd, msg); if (ret) goto out_cancel_msg; - genlmsg_end(msg, hdr); return genlmsg_reply(msg, info); @@ -106,10 +130,22 @@ out_cancel_msg: genlmsg_cancel(msg, hdr); out_free_msg: nlmsg_free(msg); - return ret; } +int dev_energymodel_nl_get_perf_domains_dumpit(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct dump_ctx ctx = { + .idx = 0, + .start = cb->args[0], + .skb = skb, + .cb = cb, + }; + + return for_each_em_perf_domain(__em_nl_get_pd_for_dump, &ctx); +} + static struct em_perf_domain *__em_nl_get_pd_table_id(struct nlattr **attrs) { struct em_perf_domain *pd; diff --git a/kernel/power/em_netlink_autogen.c b/kernel/power/em_netlink_autogen.c index 44acef0e7df2..fedd473e4244 100644 --- a/kernel/power/em_netlink_autogen.c +++ b/kernel/power/em_netlink_autogen.c @@ -11,6 +11,11 @@ #include +/* DEV_ENERGYMODEL_CMD_GET_PERF_DOMAINS - do */ +static const struct nla_policy dev_energymodel_get_perf_domains_nl_policy[DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID + 1] = { + [DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID] = { .type = NLA_U32, }, +}; + /* DEV_ENERGYMODEL_CMD_GET_PERF_TABLE - do */ static const struct nla_policy dev_energymodel_get_perf_table_nl_policy[DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID + 1] = { [DEV_ENERGYMODEL_A_PERF_TABLE_PERF_DOMAIN_ID] = { .type = NLA_U32, }, @@ -18,10 +23,17 @@ static const struct nla_policy dev_energymodel_get_perf_table_nl_policy[DEV_ENER /* Ops table for dev_energymodel */ static const struct genl_split_ops dev_energymodel_nl_ops[] = { + { + .cmd = DEV_ENERGYMODEL_CMD_GET_PERF_DOMAINS, + .doit = dev_energymodel_nl_get_perf_domains_doit, + .policy = dev_energymodel_get_perf_domains_nl_policy, + .maxattr = DEV_ENERGYMODEL_A_PERF_DOMAIN_PERF_DOMAIN_ID, + .flags = GENL_CMD_CAP_DO, + }, { .cmd = DEV_ENERGYMODEL_CMD_GET_PERF_DOMAINS, - .doit = dev_energymodel_nl_get_perf_domains_doit, - .flags = GENL_CMD_CAP_DO, + .dumpit = dev_energymodel_nl_get_perf_domains_dumpit, + .flags = GENL_CMD_CAP_DUMP, }, { .cmd = DEV_ENERGYMODEL_CMD_GET_PERF_TABLE, diff --git a/kernel/power/em_netlink_autogen.h b/kernel/power/em_netlink_autogen.h index f7e4bddcbd53..5caf2f7e18a5 100644 --- a/kernel/power/em_netlink_autogen.h +++ b/kernel/power/em_netlink_autogen.h @@ -14,6 +14,8 @@ int dev_energymodel_nl_get_perf_domains_doit(struct sk_buff *skb, struct genl_info *info); +int dev_energymodel_nl_get_perf_domains_dumpit(struct sk_buff *skb, + struct netlink_callback *cb); int dev_energymodel_nl_get_perf_table_doit(struct sk_buff *skb, struct genl_info *info); From 49d106347913201b6bc6d810c964b90781db8343 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Fri, 9 Jan 2026 11:49:44 -0800 Subject: [PATCH 141/443] cxl/acpi: Restore HBIW check before dereferencing platform_data Commit 4fe516d2ad1a ("cxl/acpi: Make the XOR calculations available for testing") split xormap handling code to create a reusable helper function but inadvertently dropped the check of HBIW values before dereferencing cxlrd->platform_data. When HBIW is 1 or 3, no xormaps are needed and platform_data may be NULL, leading to a potential NULL pointer dereference. Affects platform configs using XOR Arithmetic with HBIWs of 1 or 3, when performing DPA->HPA address translation for CXL events. Those events would be any of poison ops, general media, or dram. Restore the early return check for HBIW values of 1 and 3 before dereferencing platform_data. Fixes: 4fe516d2ad1a ("cxl/acpi: Make the XOR calculations available for testing") Signed-off-by: Alison Schofield Reviewed-by: Dave Jiang Link: https://patch.msgid.link/20260109194946.431083-1-alison.schofield@intel.com Signed-off-by: Dave Jiang --- drivers/cxl/acpi.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index 77ac940e3013..49bba2b9a3c4 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -75,9 +75,16 @@ EXPORT_SYMBOL_FOR_MODULES(cxl_do_xormap_calc, "cxl_translate"); static u64 cxl_apply_xor_maps(struct cxl_root_decoder *cxlrd, u64 addr) { - struct cxl_cxims_data *cximsd = cxlrd->platform_data; + int hbiw = cxlrd->cxlsd.nr_targets; + struct cxl_cxims_data *cximsd; - return cxl_do_xormap_calc(cximsd, addr, cxlrd->cxlsd.nr_targets); + /* No xormaps for host bridge interleave ways of 1 or 3 */ + if (hbiw == 1 || hbiw == 3) + return addr; + + cximsd = cxlrd->platform_data; + + return cxl_do_xormap_calc(cximsd, addr, hbiw); } struct cxl_cxims_context { From ca22c566b89164f6e670af56ecc45f47ef3df819 Mon Sep 17 00:00:00 2001 From: Caleb Sander Mateos Date: Thu, 8 Jan 2026 10:22:10 -0700 Subject: [PATCH 142/443] block: zero non-PI portion of auto integrity buffer The auto-generated integrity buffer for writes needs to be fully initialized before being passed to the underlying block device, otherwise the uninitialized memory can be read back by userspace or anyone with physical access to the storage device. If protection information is generated, that portion of the integrity buffer is already initialized. The integrity data is also zeroed if PI generation is disabled via sysfs or the PI tuple size is 0. However, this misses the case where PI is generated and the PI tuple size is nonzero, but the metadata size is larger than the PI tuple. In this case, the remainder ("opaque") of the metadata is left uninitialized. Generalize the BLK_INTEGRITY_CSUM_NONE check to cover any case when the metadata is larger than just the PI tuple. Signed-off-by: Caleb Sander Mateos Fixes: c546d6f43833 ("block: only zero non-PI metadata tuples in bio_integrity_prep") Reviewed-by: Anuj Gupta Reviewed-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Signed-off-by: Jens Axboe --- block/bio-integrity-auto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/bio-integrity-auto.c b/block/bio-integrity-auto.c index 9850c338548d..cff025b06be1 100644 --- a/block/bio-integrity-auto.c +++ b/block/bio-integrity-auto.c @@ -140,7 +140,7 @@ bool bio_integrity_prep(struct bio *bio) return true; set_flags = false; gfp |= __GFP_ZERO; - } else if (bi->csum_type == BLK_INTEGRITY_CSUM_NONE) + } else if (bi->metadata_size > bi->pi_tuple_size) gfp |= __GFP_ZERO; break; default: From db8061bbb9b23534ecd69bccdfbd70f5c9543189 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Sat, 10 Jan 2026 23:12:11 +0200 Subject: [PATCH 143/443] drm/rockchip: dw_hdmi_qp: Switch to gpiod_set_value_cansleep() Since commit 20cf2aed89ac ("gpio: rockchip: mark the GPIO controller as sleeping"), the Rockchip GPIO chip operations potentially sleep, hence the kernel complains when trying to make use of the non-sleeping API: [ 16.653343] WARNING: drivers/gpio/gpiolib.c:3902 at gpiod_set_value+0xd0/0x108, CPU#5: kworker/5:1/93 ... [ 16.678470] Hardware name: Radxa ROCK 5B (DT) [ 16.682374] Workqueue: events dw_hdmi_qp_rk3588_hpd_work [rockchipdrm] ... [ 16.729314] Call trace: [ 16.731846] gpiod_set_value+0xd0/0x108 (P) [ 16.734548] dw_hdmi_qp_rockchip_encoder_enable+0xbc/0x3a8 [rockchipdrm] [ 16.737487] drm_atomic_helper_commit_encoder_bridge_enable+0x314/0x380 [drm_kms_helper] [ 16.740555] drm_atomic_helper_commit_tail_rpm+0xa4/0x100 [drm_kms_helper] [ 16.743501] commit_tail+0x1e0/0x2c0 [drm_kms_helper] [ 16.746290] drm_atomic_helper_commit+0x274/0x2b8 [drm_kms_helper] [ 16.749178] drm_atomic_commit+0x1f0/0x248 [drm] [ 16.752000] drm_client_modeset_commit_atomic+0x490/0x5d0 [drm] [ 16.754954] drm_client_modeset_commit_locked+0xf4/0x400 [drm] [ 16.757911] drm_client_modeset_commit+0x50/0x80 [drm] [ 16.760791] __drm_fb_helper_restore_fbdev_mode_unlocked+0x9c/0x170 [drm_kms_helper] [ 16.763843] drm_fb_helper_hotplug_event+0x340/0x368 [drm_kms_helper] [ 16.766780] drm_fbdev_client_hotplug+0x64/0x1d0 [drm_client_lib] [ 16.769634] drm_client_hotplug+0x178/0x240 [drm] [ 16.772455] drm_client_dev_hotplug+0x170/0x1c0 [drm] [ 16.775303] drm_connector_helper_hpd_irq_event+0xa4/0x178 [drm_kms_helper] [ 16.778248] dw_hdmi_qp_rk3588_hpd_work+0x44/0xb8 [rockchipdrm] [ 16.781080] process_one_work+0xc3c/0x1658 [ 16.783719] worker_thread+0xa24/0xc40 [ 16.786333] kthread+0x3b4/0x3d8 [ 16.788889] ret_from_fork+0x10/0x20 Since gpiod_get_value() is called from a context that can sleep, switch to its *_cansleep() variant and get rid of the issue. Signed-off-by: Cristian Ciocaltea Signed-off-by: Heiko Stuebner Link: https://patch.msgid.link/20260110-dw-hdmi-qp-cansleep-v1-1-1ce937c5b201@collabora.com --- drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c index 6e39e8a00774..8604342f9943 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c @@ -121,7 +121,7 @@ static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder) struct drm_crtc *crtc = encoder->crtc; /* Unconditionally switch to TMDS as FRL is not yet supported */ - gpiod_set_value(hdmi->frl_enable_gpio, 0); + gpiod_set_value_cansleep(hdmi->frl_enable_gpio, 0); if (!crtc || !crtc->state) return; From 3f747004bbd641131d9396d87b5d2d3d1e182728 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Wed, 29 Oct 2025 20:34:19 +0800 Subject: [PATCH 144/443] dmaengine: qcom: gpi: Fix memory leak in gpi_peripheral_config() Fix a memory leak in gpi_peripheral_config() where the original memory pointed to by gchan->config could be lost if krealloc() fails. The issue occurs when: 1. gchan->config points to previously allocated memory 2. krealloc() fails and returns NULL 3. The function directly assigns NULL to gchan->config, losing the reference to the original memory 4. The original memory becomes unreachable and cannot be freed Fix this by using a temporary variable to hold the krealloc() result and only updating gchan->config when the allocation succeeds. Found via static analysis and code review. Fixes: 5d0c3533a19f ("dmaengine: qcom: Add GPI dma driver") Cc: stable@vger.kernel.org Signed-off-by: Miaoqian Lin Reviewed-by: Bjorn Andersson Link: https://patch.msgid.link/20251029123421.91973-1-linmq006@gmail.com Signed-off-by: Vinod Koul --- drivers/dma/qcom/gpi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index 66bfea1f156d..6e30f3aa401e 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -1605,14 +1605,16 @@ static int gpi_peripheral_config(struct dma_chan *chan, struct dma_slave_config *config) { struct gchan *gchan = to_gchan(chan); + void *new_config; if (!config->peripheral_config) return -EINVAL; - gchan->config = krealloc(gchan->config, config->peripheral_size, GFP_NOWAIT); - if (!gchan->config) + new_config = krealloc(gchan->config, config->peripheral_size, GFP_NOWAIT); + if (!new_config) return -ENOMEM; + gchan->config = new_config; memcpy(gchan->config, config->peripheral_config, config->peripheral_size); return 0; From 2e1136acf8a8887c29f52e35a77b537309af321f Mon Sep 17 00:00:00 2001 From: Haotian Zhang Date: Mon, 3 Nov 2025 15:30:18 +0800 Subject: [PATCH 145/443] dmaengine: omap-dma: fix dma_pool resource leak in error paths The dma_pool created by dma_pool_create() is not destroyed when dma_async_device_register() or of_dma_controller_register() fails, causing a resource leak in the probe error paths. Add dma_pool_destroy() in both error paths to properly release the allocated dma_pool resource. Fixes: 7bedaa553760 ("dmaengine: add OMAP DMA engine driver") Signed-off-by: Haotian Zhang Link: https://patch.msgid.link/20251103073018.643-1-vulab@iscas.ac.cn Signed-off-by: Vinod Koul --- drivers/dma/ti/omap-dma.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c index 8c023c6e623a..73ed4b794630 100644 --- a/drivers/dma/ti/omap-dma.c +++ b/drivers/dma/ti/omap-dma.c @@ -1808,6 +1808,8 @@ static int omap_dma_probe(struct platform_device *pdev) if (rc) { pr_warn("OMAP-DMA: failed to register slave DMA engine device: %d\n", rc); + if (od->ll123_supported) + dma_pool_destroy(od->desc_pool); omap_dma_free(od); return rc; } @@ -1823,6 +1825,8 @@ static int omap_dma_probe(struct platform_device *pdev) if (rc) { pr_warn("OMAP-DMA: failed to register DMA controller\n"); dma_async_device_unregister(&od->ddev); + if (od->ll123_supported) + dma_pool_destroy(od->desc_pool); omap_dma_free(od); } } From 76cba1e60b69c9cd53b9127d017a7dc5945455b1 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Wed, 31 Dec 2025 13:34:59 +0100 Subject: [PATCH 146/443] dmaengine: apple-admac: Add "apple,t8103-admac" compatible After discussion with the devicetree maintainers we agreed to not extend lists with the generic compatible "apple,admac" anymore [1]. Use "apple,t8103-admac" as base compatible as it is the SoC the driver and bindings were written for. [1]: https://lore.kernel.org/asahi/12ab93b7-1fc2-4ce0-926e-c8141cfe81bf@kernel.org/ Fixes: b127315d9a78 ("dmaengine: apple-admac: Add Apple ADMAC driver") Cc: stable@vger.kernel.org Reviewed-by: Neal Gompa Signed-off-by: Janne Grunau Link: https://patch.msgid.link/20251231-apple-admac-t8103-base-compat-v1-1-ec24a3708f76@jannau.net Signed-off-by: Vinod Koul --- drivers/dma/apple-admac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/dma/apple-admac.c b/drivers/dma/apple-admac.c index bd49f0374291..04bbd774b3b4 100644 --- a/drivers/dma/apple-admac.c +++ b/drivers/dma/apple-admac.c @@ -936,6 +936,7 @@ static void admac_remove(struct platform_device *pdev) } static const struct of_device_id admac_of_match[] = { + { .compatible = "apple,t8103-admac", }, { .compatible = "apple,admac", }, { } }; From c18790018799155e58d5a11c6697f9c398bf8b60 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 9 Jan 2026 14:08:32 +0100 Subject: [PATCH 147/443] gpio: davinci: implement .get_direction() It's strongly recommended for GPIO drivers to always implement the .get_direction() callback - even for fixed-direction controllers. GPIO core will even emit a warning if the callback is missing, when users try to read the direction of a pin. Implement .get_direction() for gpio-davinci. Reported-by: Michael Walle Closes: https://lore.kernel.org/all/DFJAFK3DTBOZ.3G2P3A5IH34GF@kernel.org/ Reviewed-by: Linus Walleij Fixes: a060b8c511ab ("gpiolib: implement low-level, shared GPIO support") Tested-by: Michael Walle # on sa67 Link: https://lore.kernel.org/r/20260109130832.27326-1-bartosz.golaszewski@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-davinci.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 538f27209ce7..97780f27ce5b 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -6,6 +6,7 @@ * Copyright (c) 2007, MontaVista Software, Inc. */ +#include #include #include #include @@ -109,6 +110,22 @@ davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value) return __davinci_direction(chip, offset, true, value); } +static int davinci_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + struct davinci_gpio_controller *d = gpiochip_get_data(chip); + struct davinci_gpio_regs __iomem *g; + u32 mask = __gpio_mask(offset), val; + int bank = offset / 32; + + g = d->regs[bank]; + + guard(spinlock_irqsave)(&d->lock); + + val = readl_relaxed(&g->dir); + + return (val & mask) ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; +} + /* * Read the pin's value (works even if it's set up as output); * returns zero/nonzero. @@ -203,6 +220,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) chips->chip.get = davinci_gpio_get; chips->chip.direction_output = davinci_direction_out; chips->chip.set = davinci_gpio_set; + chips->chip.get_direction = davinci_get_direction; chips->chip.ngpio = ngpio; chips->chip.base = -1; From 471e998c0e31206ff0eac7202b2659698cf9b46e Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 9 Jan 2026 11:55:56 +0100 Subject: [PATCH 148/443] gpiolib: remove redundant callback check The presence of the .get_direction() callback is already checked in gpiochip_get_direction(). Remove the duplicated check which also returns the wrong error code to user-space. Fixes: e623c4303ed1 ("gpiolib: sanitize the return value of gpio_chip::get_direction()") Reported-by: Michael Walle Closes: https://lore.kernel.org/all/DFJAFK3DTBOZ.3G2P3A5IH34GF@kernel.org/ Link: https://lore.kernel.org/r/20260109105557.20024-1-bartosz.golaszewski@oss.qualcomm.com Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index dcf427d3cf43..fe2d107b0a84 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -468,9 +468,6 @@ int gpiod_get_direction(struct gpio_desc *desc) test_bit(GPIOD_FLAG_IS_OUT, &flags)) return 0; - if (!guard.gc->get_direction) - return -ENOTSUPP; - ret = gpiochip_get_direction(guard.gc, offset); if (ret < 0) return ret; From 81d0223832f99c0833e46be114a8310888015f8b Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 8 Jan 2026 15:12:03 -0500 Subject: [PATCH 149/443] drm/i915/guc: make 'guc_hw_reg_state' static as it isn't exported The guc_hw_reg_state array is not exported, so make it static. Fixes the following sparse warning: drivers/gpu/drm/i915/i915_gpu_error.c:692:3: warning: symbol 'guc_hw_reg_state' was not declared. Should it be static? Fixes: ba391a102ec11 ("drm/i915/guc: Include the GuC registers in the error state") Signed-off-by: Ben Dooks Reviewed-by: Rodrigo Vivi Link: https://patch.msgid.link/20260108201202.59250-2-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi (cherry picked from commit 701c47493328a8173996e7590733be3493af572f) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_gpu_error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 7582ef34bf3f..303d8d9b7775 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -686,7 +686,7 @@ static void err_print_guc_ctb(struct drm_i915_error_state_buf *m, } /* This list includes registers that are useful in debugging GuC hangs. */ -const struct { +static const struct { u32 start; u32 count; } guc_hw_reg_state[] = { From 101b982654ac0305ab286b54d46de79b5b982f3a Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 8 Jan 2026 15:53:05 -0600 Subject: [PATCH 150/443] ASoC: dt-bindings: realtek,rt5640: Add missing properties/node The RT5640 has an MCLK pin and several users already define a clocks entry. A 'port' node is also in use and a common node for codecs. Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260108215307.1138515-1-robh@kernel.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/realtek,rt5640.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml index 3f4f59287c1c..a0b8bf6cb110 100644 --- a/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml +++ b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml @@ -47,6 +47,12 @@ properties: reg: maxItems: 1 + clocks: + maxItems: 1 + + clock-names: + const: mclk + interrupts: maxItems: 1 description: The CODEC's interrupt output. @@ -121,6 +127,9 @@ properties: - 2 # Scale current by 1.0 - 3 # Scale current by 1.5 + port: + $ref: /schemas/graph.yaml#/properties/port + required: - compatible - reg From f66e7da2a6b1ba055d47d7c97c9c855729f868ed Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 8 Jan 2026 15:53:06 -0600 Subject: [PATCH 151/443] ASoC: dt-bindings: realtek,rt5640: Allow 7 for realtek,jack-detect-source The driver accepts and uses a value of 7 for realtek,jack-detect-source. What exactly it means isn't clear though. Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260108215307.1138515-2-robh@kernel.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/realtek,rt5640.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml index a0b8bf6cb110..cd95d7189d34 100644 --- a/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml +++ b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml @@ -104,6 +104,7 @@ properties: - 4 # Use GPIO2 for jack-detect - 5 # Use GPIO3 for jack-detect - 6 # Use GPIO4 for jack-detect + - 7 # HDA? realtek,jack-detect-not-inverted: description: From 70d95c5d2081faca7e849fa9c6665c9e0dae3923 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 8 Jan 2026 16:49:36 -0600 Subject: [PATCH 152/443] ASoC: dt-bindings: rockchip-spdif: Allow "port" node Add a "port" node entry for Rockchip S/PDIF binding. It's already in use and a common property for DAIs. Signed-off-by: Rob Herring (Arm) Link: https://patch.msgid.link/20260108224938.1320809-1-robh@kernel.org Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rockchip-spdif.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml b/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml index 32dea7392e8d..56c755c22945 100644 --- a/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml +++ b/Documentation/devicetree/bindings/sound/rockchip-spdif.yaml @@ -70,6 +70,9 @@ properties: "#sound-dai-cells": const: 0 + port: + $ref: /schemas/graph.yaml#/properties/port + required: - compatible - reg From 64dd1caf88f96146edee24e82834cf2a11c3932b Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Fri, 9 Jan 2026 14:01:14 +1030 Subject: [PATCH 153/443] btrfs: update the Kconfig string for CONFIG_BTRFS_EXPERIMENTAL The following new features are missing: - Async checksum - Shutdown ioctl and auto-degradation - Larger block size support Which is dependent on larger folios. Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/Kconfig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig index 4438637c8900..6d6fc85835d4 100644 --- a/fs/btrfs/Kconfig +++ b/fs/btrfs/Kconfig @@ -115,6 +115,10 @@ config BTRFS_EXPERIMENTAL - extent tree v2 - complex rework of extent tracking - - large folio support + - large folio and block size (> page size) support + + - shutdown ioctl and auto-degradation support + + - asynchronous checksum generation for data writes If unsure, say N. From 882680774933fd276023e01cf0261c2350d7201e Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Thu, 8 Jan 2026 16:16:38 +0000 Subject: [PATCH 154/443] btrfs: invalidate pages instead of truncate after reflinking Qu reported that generic/164 often fails because the read operations get zeroes when it expects to either get all bytes with a value of 0x61 or 0x62. The issue stems from truncating the pages from the page cache instead of invalidating, as truncating can zero page contents. This zeroing is not just in case the range is not page sized (as it's commented in truncate_inode_pages_range()) but also in case we are using large folios, they need to be split and the splitting fails. Stealing Qu's comment in the thread linked below: "We can have the following case: 0 4K 8K 12K 16K | | | | | |<---- Extent A ----->|<----- Extent B ------>| The page size is still 4K, but the folio we got is 16K. Then if we remap the range for [8K, 16K), then truncate_inode_pages_range() will get the large folio 0 sized 16K, then call truncate_inode_partial_folio(). Which later calls folio_zero_range() for the [8K, 16K) range first, then tries to split the folio into smaller ones to properly drop them from the cache. But if splitting failed (e.g. racing with other operations holding the filemap lock), the partially zeroed large folio will be kept, resulting the range [8K, 16K) being zeroed meanwhile the folio is still a 16K sized large one." So instead of truncating, invalidate the page cache range with a call to filemap_invalidate_inode(), which besides not doing any zeroing also ensures that while it's invalidating folios, no new folios are added. This helps ensure that buffered reads that happen while a reflink operation is in progress always get either the whole old data (the one before the reflink) or the whole new data, which is what generic/164 expects. Link: https://lore.kernel.org/linux-btrfs/7fb9b44f-9680-4c22-a47f-6648cb109ddf@suse.com/ Reported-by: Qu Wenruo Reviewed-by: Qu Wenruo Reviewed-by: Boris Burkov Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/reflink.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c index b5fe95baf92e..58dc3e5057ce 100644 --- a/fs/btrfs/reflink.c +++ b/fs/btrfs/reflink.c @@ -705,7 +705,6 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, struct inode *src = file_inode(file_src); struct btrfs_fs_info *fs_info = inode_to_fs_info(inode); int ret; - int wb_ret; u64 len = olen; u64 bs = fs_info->sectorsize; u64 end; @@ -750,25 +749,29 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, btrfs_lock_extent(&BTRFS_I(inode)->io_tree, destoff, end, &cached_state); ret = btrfs_clone(src, inode, off, olen, len, destoff, 0); btrfs_unlock_extent(&BTRFS_I(inode)->io_tree, destoff, end, &cached_state); + if (ret < 0) + return ret; /* * We may have copied an inline extent into a page of the destination - * range, so wait for writeback to complete before truncating pages + * range, so wait for writeback to complete before invalidating pages * from the page cache. This is a rare case. */ - wb_ret = btrfs_wait_ordered_range(BTRFS_I(inode), destoff, len); - ret = ret ? ret : wb_ret; + ret = btrfs_wait_ordered_range(BTRFS_I(inode), destoff, len); + if (ret < 0) + return ret; + /* - * Truncate page cache pages so that future reads will see the cloned - * data immediately and not the previous data. + * Invalidate page cache so that future reads will see the cloned data + * immediately and not the previous data. */ - truncate_inode_pages_range(&inode->i_data, - round_down(destoff, PAGE_SIZE), - round_up(destoff + len, PAGE_SIZE) - 1); + ret = filemap_invalidate_inode(inode, false, destoff, end); + if (ret < 0) + return ret; btrfs_btree_balance_dirty(fs_info); - return ret; + return 0; } static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in, From a11224a016d6d1d46a4d9b6573244448a80d4d7f Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Sun, 11 Jan 2026 19:20:37 +0000 Subject: [PATCH 155/443] btrfs: fix memory leaks in create_space_info() error paths In create_space_info(), the 'space_info' object is allocated at the beginning of the function. However, there are two error paths where the function returns an error code without freeing the allocated memory: 1. When create_space_info_sub_group() fails in zoned mode. 2. When btrfs_sysfs_add_space_info_type() fails. In both cases, 'space_info' has not yet been added to the fs_info->space_info list, resulting in a memory leak. Fix this by adding an error handling label to kfree(space_info) before returning. Fixes: 2be12ef79fe9 ("btrfs: Separate space_info create/update") Reviewed-by: Qu Wenruo Signed-off-by: Jiasheng Jiang Signed-off-by: David Sterba --- fs/btrfs/space-info.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c index 6babbe333741..3f08e450f796 100644 --- a/fs/btrfs/space-info.c +++ b/fs/btrfs/space-info.c @@ -306,18 +306,22 @@ static int create_space_info(struct btrfs_fs_info *info, u64 flags) 0); if (ret) - return ret; + goto out_free; } ret = btrfs_sysfs_add_space_info_type(space_info); if (ret) - return ret; + goto out_free; list_add(&space_info->list, &info->space_info); if (flags & BTRFS_BLOCK_GROUP_DATA) info->data_sinfo = space_info; return ret; + +out_free: + kfree(space_info); + return ret; } int btrfs_init_space_info(struct btrfs_fs_info *fs_info) From d4026a44626490dc4eca4dd2c4d0816338fa179b Mon Sep 17 00:00:00 2001 From: Li Ming Date: Mon, 12 Jan 2026 20:05:26 +0800 Subject: [PATCH 156/443] cxl/hdm: Fix potential infinite loop in __cxl_dpa_reserve() In __cxl_dpa_reserve(), it will check if the new resource range is included in one of paritions of the cxl memory device. cxlds->nr_paritions is used to represent how many partitions information the cxl memory device has. In the loop, if driver cannot find a partition including the new resource range, it will be an infinite loop. [ dj: Removed incorrect fixes tag ] Fixes: 991d98f17d31 ("cxl: Make cxl_dpa_alloc() DPA partition number agnostic") Signed-off-by: Li Ming Reviewed-by: Ira Weiny Reviewed-by: Dave Jiang Link: https://patch.msgid.link/20260112120526.530232-1-ming.li@zohomail.com Signed-off-by: Dave Jiang --- drivers/cxl/core/hdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index 1c5d2022c87a..a470099a69f1 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -403,7 +403,7 @@ static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled, * is not set. */ if (cxled->part < 0) - for (int i = 0; cxlds->nr_partitions; i++) + for (int i = 0; i < cxlds->nr_partitions; i++) if (resource_contains(&cxlds->part[i].res, res)) { cxled->part = i; break; From 6abbb8703aeeb645a681ab6ad155e0b450413787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Noack?= Date: Sun, 11 Jan 2026 18:52:04 +0100 Subject: [PATCH 157/443] landlock: Clarify documentation for the IOCTL access right MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the description of the LANDLOCK_ACCESS_FS_IOCTL_DEV access right together with the file access rights. This group of access rights applies to files (in this case device files), and they can be added to file or directory inodes using landlock_add_rule(2). The check for that works the same for all file access rights, including LANDLOCK_ACCESS_FS_IOCTL_DEV. Invoking ioctl(2) on directory FDs can not currently be restricted with Landlock. Having it grouped separately in the documentation is a remnant from earlier revisions of the LANDLOCK_ACCESS_FS_IOCTL_DEV patch set. Link: https://lore.kernel.org/all/20260108.Thaex5ruach2@digikod.net/ Signed-off-by: Günther Noack Link: https://lore.kernel.org/r/20260111175203.6545-2-gnoack3000@gmail.com Signed-off-by: Mickaël Salaün --- include/uapi/linux/landlock.h | 37 ++++++++++++++++------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h index f030adc462ee..75fd7f5e6cc3 100644 --- a/include/uapi/linux/landlock.h +++ b/include/uapi/linux/landlock.h @@ -216,6 +216,23 @@ struct landlock_net_port_attr { * :manpage:`ftruncate(2)`, :manpage:`creat(2)`, or :manpage:`open(2)` with * ``O_TRUNC``. This access right is available since the third version of the * Landlock ABI. + * - %LANDLOCK_ACCESS_FS_IOCTL_DEV: Invoke :manpage:`ioctl(2)` commands on an opened + * character or block device. + * + * This access right applies to all `ioctl(2)` commands implemented by device + * drivers. However, the following common IOCTL commands continue to be + * invokable independent of the %LANDLOCK_ACCESS_FS_IOCTL_DEV right: + * + * * IOCTL commands targeting file descriptors (``FIOCLEX``, ``FIONCLEX``), + * * IOCTL commands targeting file descriptions (``FIONBIO``, ``FIOASYNC``), + * * IOCTL commands targeting file systems (``FIFREEZE``, ``FITHAW``, + * ``FIGETBSZ``, ``FS_IOC_GETFSUUID``, ``FS_IOC_GETFSSYSFSPATH``) + * * Some IOCTL commands which do not make sense when used with devices, but + * whose implementations are safe and return the right error codes + * (``FS_IOC_FIEMAP``, ``FICLONE``, ``FICLONERANGE``, ``FIDEDUPERANGE``) + * + * This access right is available since the fifth version of the Landlock + * ABI. * * Whether an opened file can be truncated with :manpage:`ftruncate(2)` or used * with `ioctl(2)` is determined during :manpage:`open(2)`, in the same way as @@ -275,26 +292,6 @@ struct landlock_net_port_attr { * If multiple requirements are not met, the ``EACCES`` error code takes * precedence over ``EXDEV``. * - * The following access right applies both to files and directories: - * - * - %LANDLOCK_ACCESS_FS_IOCTL_DEV: Invoke :manpage:`ioctl(2)` commands on an opened - * character or block device. - * - * This access right applies to all `ioctl(2)` commands implemented by device - * drivers. However, the following common IOCTL commands continue to be - * invokable independent of the %LANDLOCK_ACCESS_FS_IOCTL_DEV right: - * - * * IOCTL commands targeting file descriptors (``FIOCLEX``, ``FIONCLEX``), - * * IOCTL commands targeting file descriptions (``FIONBIO``, ``FIOASYNC``), - * * IOCTL commands targeting file systems (``FIFREEZE``, ``FITHAW``, - * ``FIGETBSZ``, ``FS_IOC_GETFSUUID``, ``FS_IOC_GETFSSYSFSPATH``) - * * Some IOCTL commands which do not make sense when used with devices, but - * whose implementations are safe and return the right error codes - * (``FS_IOC_FIEMAP``, ``FICLONE``, ``FICLONERANGE``, ``FIDEDUPERANGE``) - * - * This access right is available since the fifth version of the Landlock - * ABI. - * * .. warning:: * * It is currently not possible to restrict some file-related actions From 05f66cf5e7a5fc7c7227541f8a4a476037999916 Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Fri, 26 Dec 2025 19:39:38 +0800 Subject: [PATCH 158/443] PCI: Provide pci_free_irq_vectors() stub 473b9f331718 ("rust: pci: fix build failure when CONFIG_PCI_MSI is disabled") fixed a build error by providing Rust helpers when CONFIG_PCI_MSI is not set. However the Rust helpers rely on pci_free_irq_vectors(), which is only available when CONFIG_PCI=y. When CONFIG_PCI is not set, there is already a stub for pci_alloc_irq_vectors(). Add a similar stub for pci_free_irq_vectors(). Fixes: 473b9f331718 ("rust: pci: fix build failure when CONFIG_PCI_MSI is disabled") Reported-by: FUJITA Tomonori Closes: https://lore.kernel.org/rust-for-linux/20251209014312.575940-1-fujita.tomonori@gmail.com/ Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202512220740.4Kexm4dW-lkp@intel.com/ Reported-by: Liang Jie Closes: https://lore.kernel.org/rust-for-linux/20251222034415.1384223-1-buaajxlj@163.com/ Signed-off-by: Boqun Feng Signed-off-by: Bjorn Helgaas Reviewed-by: Drew Fustini Reviewed-by: David Gow Reviewed-by: Joel Fernandes Reviewed-by: Danilo Krummrich Link: https://patch.msgid.link/20251226113938.52145-1-boqun.feng@gmail.com --- include/linux/pci.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/pci.h b/include/linux/pci.h index 864775651c6f..b5cc0c2b9906 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -2210,6 +2210,10 @@ pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, { return -ENOSPC; } + +static inline void pci_free_irq_vectors(struct pci_dev *dev) +{ +} #endif /* CONFIG_PCI */ /* Include architecture-dependent settings and functions */ From 803e18641fd444a614415711a5af53dcde21104b Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Fri, 9 Jan 2026 15:41:14 -0500 Subject: [PATCH 159/443] NFS: Don't immediately return directory delegations when disabled The function nfs_inode_evict_delegation() immediately and synchronously returns a delegation when called. This means we can't call it from nfs4_have_delegation(), since that function could be called under a lock. Instead we should mark the delegation for return and let the state manager handle it for us. Fixes: b6d2a520f463 ("NFS: Add a module option to disable directory delegations") Signed-off-by: Anna Schumaker Signed-off-by: Trond Myklebust --- fs/nfs/delegation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index c9fa4c1f68fc..8a3857a49d84 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -149,7 +149,7 @@ static int nfs4_do_check_delegation(struct inode *inode, fmode_t type, int nfs4_have_delegation(struct inode *inode, fmode_t type, int flags) { if (S_ISDIR(inode->i_mode) && !directory_delegations) - nfs_inode_evict_delegation(inode); + nfs4_inode_set_return_delegation_on_close(inode); return nfs4_do_check_delegation(inode, type, flags, true); } From 8f334e35220721f65180bc2e0fe9187436c2c475 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 7 Jan 2026 16:14:55 +0100 Subject: [PATCH 160/443] ACPI: PM: s2idle: Add missing checks to acpi_s2idle_begin_lps0() Commit 32ece31db4df ("ACPI: PM: s2idle: Only retrieve constraints when needed"), that attempted to avoid useless evaluation of LPS0 _DSM Function 1 in lps0_device_attach(), forgot to add checks for lps0_device_handle and sleep_no_lps0 to acpi_s2idle_begin_lps0() where they should be done before calling lpi_device_get_constraints() or lpi_device_get_constraints_amd(). Add the missing checks. Fixes: 32ece31db4df ("ACPI: PM: s2idle: Only retrieve constraints when needed") Signed-off-by: Rafael J. Wysocki Reviewed-by: Mario Limonciello (AMD) Link: https://patch.msgid.link/2818730.mvXUDI8C0e@rafael.j.wysocki --- drivers/acpi/x86/s2idle.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c index 6d4d06236f61..2a9edb53d5d4 100644 --- a/drivers/acpi/x86/s2idle.c +++ b/drivers/acpi/x86/s2idle.c @@ -515,7 +515,8 @@ static struct acpi_scan_handler lps0_handler = { static int acpi_s2idle_begin_lps0(void) { - if (pm_debug_messages_on && !lpi_constraints_table) { + if (lps0_device_handle && !sleep_no_lps0 && pm_debug_messages_on && + !lpi_constraints_table) { if (acpi_s2idle_vendor_amd()) lpi_device_get_constraints_amd(); else From 4f431d88ea8093afc7ba55edf4652978c5a68f33 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 10 Jan 2026 00:56:29 +0100 Subject: [PATCH 161/443] wifi: rsi: Fix memory corruption due to not set vif driver data size The struct ieee80211_vif contains trailing space for vif driver data, when struct ieee80211_vif is allocated, the total memory size that is allocated is sizeof(struct ieee80211_vif) + size of vif driver data. The size of vif driver data is set by each WiFi driver as needed. The RSI911x driver does not set vif driver data size, no trailing space for vif driver data is therefore allocated past struct ieee80211_vif . The RSI911x driver does however use the vif driver data to store its vif driver data structure "struct vif_priv". An access to vif->drv_priv leads to access out of struct ieee80211_vif bounds and corruption of some memory. In case of the failure observed locally, rsi_mac80211_add_interface() would write struct vif_priv *vif_info = (struct vif_priv *)vif->drv_priv; vif_info->vap_id = vap_idx. This write corrupts struct fq_tin member struct list_head new_flows . The flow = list_first_entry(head, struct fq_flow, flowchain); in fq_tin_reset() then reports non-NULL bogus address, which when accessed causes a crash. The trigger is very simple, boot the machine with init=/bin/sh , mount devtmpfs, sysfs, procfs, and then do "ip link set wlan0 up", "sleep 1", "ip link set wlan0 down" and the crash occurs. Fix this by setting the correct size of vif driver data, which is the size of "struct vif_priv", so that memory is allocated and the driver can store its driver data in it, instead of corrupting memory around it. Cc: stable@vger.kernel.org Fixes: dad0d04fa7ba ("rsi: Add RS9113 wireless driver") Signed-off-by: Marek Vasut Link: https://patch.msgid.link/20260109235817.150330-1-marex@nabladev.com Signed-off-by: Johannes Berg --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index f3a853edfc11..8c8e074a3a70 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -2035,6 +2035,7 @@ int rsi_mac80211_attach(struct rsi_common *common) hw->queues = MAX_HW_QUEUES; hw->extra_tx_headroom = RSI_NEEDED_HEADROOM; + hw->vif_data_size = sizeof(struct vif_priv); hw->max_rates = 1; hw->max_rate_tries = MAX_RETRIES; From a3034bf0746d88a00cceda9541534a5721445a24 Mon Sep 17 00:00:00 2001 From: Veerendranath Jakkam Date: Fri, 9 Jan 2026 20:30:04 +0530 Subject: [PATCH 162/443] wifi: cfg80211: Fix bitrate calculation overflow for HE rates An integer overflow occurs in cfg80211_calculate_bitrate_he() when calculating bitrates for high throughput HE configurations. For example, with 160 MHz bandwidth, HE-MCS 13, HE-NSS 4, and HE-GI 0, the multiplication (result * rate->nss) overflows the 32-bit 'result' variable before division by 8, leading to significantly underestimated bitrate values. The overflow occurs because the NSS multiplication operates on a 32-bit integer that cannot accommodate intermediate values exceeding 4,294,967,295. When overflow happens, the value wraps around, producing incorrect bitrates for high MCS and NSS combinations. Fix this by utilizing the 64-bit 'tmp' variable for the NSS multiplication and subsequent divisions via do_div(). This approach preserves full precision throughout the entire calculation, with the final value assigned to 'result' only after completing all operations. Signed-off-by: Veerendranath Jakkam Link: https://patch.msgid.link/20260109-he_bitrate_overflow-v1-1-95575e466b6e@oss.qualcomm.com Signed-off-by: Johannes Berg --- net/wireless/util.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/wireless/util.c b/net/wireless/util.c index 27e8a2f52f04..4f581aed45b7 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1561,12 +1561,14 @@ static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate) tmp = result; tmp *= SCALE; do_div(tmp, mcs_divisors[rate->mcs]); - result = tmp; /* and take NSS, DCM into account */ - result = (result * rate->nss) / 8; + tmp *= rate->nss; + do_div(tmp, 8); if (rate->he_dcm) - result /= 2; + do_div(tmp, 2); + + result = tmp; return result / 10000; } From db1d0b6ab11f612ea8a327663a578c8946efeee9 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sun, 11 Jan 2026 19:19:30 +0200 Subject: [PATCH 163/443] wifi: mac80211: correctly check if CSA is active We are not adding an interface if an existing one is doing CSA. But the check won't work for MLO station interfaces, since for those, vif->bss_conf is zeroed out. Fix this by checking if any link of the vif has an active CSA. Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260111191912.7ceff62fc561.Ia38d27f42684d1cfd82d930d232bd5dea6ab9282@changeid Signed-off-by: Johannes Berg --- net/mac80211/iface.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 7b0aa24c1f97..515384ca2f8f 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -350,6 +350,8 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, /* we hold the RTNL here so can safely walk the list */ list_for_each_entry(nsdata, &local->interfaces, list) { if (nsdata != sdata && ieee80211_sdata_running(nsdata)) { + struct ieee80211_link_data *link; + /* * Only OCB and monitor mode may coexist */ @@ -376,8 +378,10 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, * will not add another interface while any channel * switch is active. */ - if (nsdata->vif.bss_conf.csa_active) - return -EBUSY; + for_each_link_data(nsdata, link) { + if (link->conf->csa_active) + return -EBUSY; + } /* * The remaining checks are only performed for interfaces From 2120f3a3738a65730c81bf10447b1ff776078915 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 8 Jan 2026 23:00:24 +0300 Subject: [PATCH 164/443] wifi: mwifiex: Fix a loop in mwifiex_update_ampdu_rxwinsize() The "i" iterator variable is used to count two different things but unfortunately we can't store two different numbers in the same variable. Use "i" for the outside loop and "j" for the inside loop. Cc: stable@vger.kernel.org Fixes: d219b7eb3792 ("mwifiex: handle BT coex event to adjust Rx BA window size") Signed-off-by: Dan Carpenter Reviewed-by: Jeff Chen Link: https://patch.msgid.link/aWAM2MGUWRP0zWUd@stanley.mountain Signed-off-by: Johannes Berg --- drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c index 354c5ce66045..f3397dc6c422 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c @@ -825,7 +825,7 @@ void mwifiex_update_rxreor_flags(struct mwifiex_adapter *adapter, u8 flags) static void mwifiex_update_ampdu_rxwinsize(struct mwifiex_adapter *adapter, bool coex_flag) { - u8 i; + u8 i, j; u32 rx_win_size; struct mwifiex_private *priv; @@ -863,8 +863,8 @@ static void mwifiex_update_ampdu_rxwinsize(struct mwifiex_adapter *adapter, if (rx_win_size != priv->add_ba_param.rx_win_size) { if (!priv->media_connected) continue; - for (i = 0; i < MAX_NUM_TID; i++) - mwifiex_11n_delba(priv, i); + for (j = 0; j < MAX_NUM_TID; j++) + mwifiex_11n_delba(priv, j); } } } From f34b32745e2c9f85ee33b42e7a8cdaa1ee1c16a3 Mon Sep 17 00:00:00 2001 From: sheetal Date: Wed, 17 Dec 2025 18:55:24 +0530 Subject: [PATCH 165/443] ASoC: tegra: Revert fix for uninitialized flat cache warning in tegra210_ahub Commit 4d4021b0bbd1 ("ASoC: tegra: Fix uninitialized flat cache warning in tegra210_ahub") attempted to fix the uninitialized flat cache warning that is observed for the Tegra210 AHUB driver. However, the change broke various audio tests because an -EBUSY error is returned when accessing registers from cache before they are read from hardware. Revert this change for now, until a proper fix is available. Fixes: 4d4021b0bbd1 ("ASoC: tegra: Fix uninitialized flat cache warning in tegra210_ahub") Signed-off-by: sheetal Acked-by: Jon Hunter Link: https://patch.msgid.link/20251217132524.2844499-1-sheetal@nvidia.com Signed-off-by: Mark Brown --- sound/soc/tegra/tegra210_ahub.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c index 261d9067d27b..e795907a3963 100644 --- a/sound/soc/tegra/tegra210_ahub.c +++ b/sound/soc/tegra/tegra210_ahub.c @@ -2077,7 +2077,7 @@ static const struct regmap_config tegra210_ahub_regmap_config = { .val_bits = 32, .reg_stride = 4, .max_register = TEGRA210_MAX_REGISTER_ADDR, - .cache_type = REGCACHE_FLAT_S, + .cache_type = REGCACHE_FLAT, }; static const struct regmap_config tegra186_ahub_regmap_config = { @@ -2085,7 +2085,7 @@ static const struct regmap_config tegra186_ahub_regmap_config = { .val_bits = 32, .reg_stride = 4, .max_register = TEGRA186_MAX_REGISTER_ADDR, - .cache_type = REGCACHE_FLAT_S, + .cache_type = REGCACHE_FLAT, }; static const struct regmap_config tegra264_ahub_regmap_config = { @@ -2094,7 +2094,7 @@ static const struct regmap_config tegra264_ahub_regmap_config = { .reg_stride = 4, .writeable_reg = tegra264_ahub_wr_reg, .max_register = TEGRA264_MAX_REGISTER_ADDR, - .cache_type = REGCACHE_FLAT_S, + .cache_type = REGCACHE_FLAT, }; static const struct tegra_ahub_soc_data soc_data_tegra210 = { From f2edf797dab185cce439e5bc5185fe20dd536300 Mon Sep 17 00:00:00 2001 From: Luo Haiyang Date: Tue, 13 Jan 2026 11:19:30 +0800 Subject: [PATCH 166/443] irqchip/riscv-imsic: Revert "Remove redundant irq_data lookups" Commit c475c0b71314("irqchip/riscv-imsic: Remove redundant irq_data lookups") leads to a NULL pointer deference in imsic_msi_update_msg(): virtio_blk virtio1: 8/0/0 default/read/poll queues Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 Current kworker/u32:2 pgtable: 4K pagesize, 48-bit VAs, pgdp=0x0000000081c33000 [0000000000000000] pgd=0000000000000000, p4d=0000000000000000 CPU: 5 UID: 0 PID: 75 Comm: kworker/u32:2 Not tainted 6.19.0-rc4-next-20260109 #1 NONE epc : 0x0 ra : imsic_irq_set_affinity+0x110/0x130 The irq_data argument of imsic_irq_set_affinity() is associated with the imsic domain and not with the top-level MSI domain. As a consequence the code dereferences the wrong interrupt chip, which has the irq_write_msi_msg() callback not populated. Signed-off-by: Luo Haiyang Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260113111930821RrC26avITHWSFCN0bYbgI@zte.com.cn --- drivers/irqchip/irq-riscv-imsic-platform.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-riscv-imsic-platform.c b/drivers/irqchip/irq-riscv-imsic-platform.c index 7228a33f6c37..643c8e459611 100644 --- a/drivers/irqchip/irq-riscv-imsic-platform.c +++ b/drivers/irqchip/irq-riscv-imsic-platform.c @@ -158,11 +158,11 @@ static int imsic_irq_set_affinity(struct irq_data *d, const struct cpumask *mask tmp_vec.local_id = new_vec->local_id; /* Point device to the temporary vector */ - imsic_msi_update_msg(d, &tmp_vec); + imsic_msi_update_msg(irq_get_irq_data(d->irq), &tmp_vec); } /* Point device to the new vector */ - imsic_msi_update_msg(d, new_vec); + imsic_msi_update_msg(irq_get_irq_data(d->irq), new_vec); /* Update irq descriptors with the new vector */ d->chip_data = new_vec; From 6ab3d4353bf75005eaa375677c9fed31148154d6 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 10 Jan 2026 16:27:28 +0100 Subject: [PATCH 167/443] drm/panel-simple: fix connector type for DataImage SCF0700C48GGU18 panel The connector type for the DataImage SCF0700C48GGU18 panel is missing and devm_drm_panel_bridge_add() requires connector type to be set. This leads to a warning and a backtrace in the kernel log and panel does not work: " WARNING: CPU: 3 PID: 38 at drivers/gpu/drm/bridge/panel.c:379 devm_drm_of_get_bridge+0xac/0xb8 " The warning is triggered by a check for valid connector type in devm_drm_panel_bridge_add(). If there is no valid connector type set for a panel, the warning is printed and panel is not added. Fill in the missing connector type to fix the warning and make the panel operational once again. Cc: stable@vger.kernel.org Fixes: 97ceb1fb08b6 ("drm/panel: simple: Add support for DataImage SCF0700C48GGU18") Signed-off-by: Marek Vasut Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20260110152750.73848-1-marex@nabladev.com --- drivers/gpu/drm/panel/panel-simple.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index b26b682826bc..246d6883fbf7 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1900,6 +1900,7 @@ static const struct panel_desc dataimage_scf0700c48ggu18 = { }, .bus_format = MEDIA_BUS_FMT_RGB888_1X24, .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, + .connector_type = DRM_MODE_CONNECTOR_DPI, }; static const struct display_timing dlc_dlc0700yzg_1_timing = { From 9380dc33cd6ae4a6857818fcefce31cf716f3fae Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 18 Dec 2025 14:34:43 +0100 Subject: [PATCH 168/443] drm/panel: simple: restore connector_type fallback The switch from devm_kzalloc() + drm_panel_init() to devm_drm_panel_alloc() introduced a regression. Several panel descriptors do not set connector_type. For those panels, panel_simple_probe() used to compute a connector type (currently DPI as a fallback) and pass that value to drm_panel_init(). After the conversion to devm_drm_panel_alloc(), the call unconditionally used desc->connector_type instead, ignoring the computed fallback and potentially passing DRM_MODE_CONNECTOR_Unknown, which drm_panel_bridge_add() does not allow. Move the connector_type validation / fallback logic before the devm_drm_panel_alloc() call and pass the computed connector_type to devm_drm_panel_alloc(), so panels without an explicit connector_type once again get the DPI default. Signed-off-by: Ludovic Desroches Fixes: de04bb0089a9 ("drm/panel/panel-simple: Use the new allocation in place of devm_kzalloc()") Cc: stable@vger.kernel.org Reviewed-by: Luca Ceresoli Link: https://lore.kernel.org/stable/20251126-lcd_panel_connector_type_fix-v2-1-c15835d1f7cb%40microchip.com Signed-off-by: Neil Armstrong Link: https://patch.msgid.link/20251218-lcd_panel_connector_type_fix-v3-1-ddcea6d8d7ef@microchip.com --- drivers/gpu/drm/panel/panel-simple.c | 109 +++++++++++++-------------- 1 file changed, 54 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 246d6883fbf7..162cc58c7b8f 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -623,8 +623,61 @@ static struct panel_simple *panel_simple_probe(struct device *dev) if (IS_ERR(desc)) return ERR_CAST(desc); + connector_type = desc->connector_type; + /* Catch common mistakes for panels. */ + switch (connector_type) { + case 0: + dev_warn(dev, "Specify missing connector_type\n"); + connector_type = DRM_MODE_CONNECTOR_DPI; + break; + case DRM_MODE_CONNECTOR_LVDS: + WARN_ON(desc->bus_flags & + ~(DRM_BUS_FLAG_DE_LOW | + DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_DATA_MSB_TO_LSB | + DRM_BUS_FLAG_DATA_LSB_TO_MSB)); + WARN_ON(desc->bus_format != MEDIA_BUS_FMT_RGB666_1X7X3_SPWG && + desc->bus_format != MEDIA_BUS_FMT_RGB888_1X7X4_SPWG && + desc->bus_format != MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA); + WARN_ON(desc->bus_format == MEDIA_BUS_FMT_RGB666_1X7X3_SPWG && + desc->bpc != 6); + WARN_ON((desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_SPWG || + desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA) && + desc->bpc != 8); + break; + case DRM_MODE_CONNECTOR_eDP: + dev_warn(dev, "eDP panels moved to panel-edp\n"); + return ERR_PTR(-EINVAL); + case DRM_MODE_CONNECTOR_DSI: + if (desc->bpc != 6 && desc->bpc != 8) + dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc); + break; + case DRM_MODE_CONNECTOR_DPI: + bus_flags = DRM_BUS_FLAG_DE_LOW | + DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE | + DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE | + DRM_BUS_FLAG_DATA_MSB_TO_LSB | + DRM_BUS_FLAG_DATA_LSB_TO_MSB | + DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE | + DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE; + if (desc->bus_flags & ~bus_flags) + dev_warn(dev, "Unexpected bus_flags(%d)\n", desc->bus_flags & ~bus_flags); + if (!(desc->bus_flags & bus_flags)) + dev_warn(dev, "Specify missing bus_flags\n"); + if (desc->bus_format == 0) + dev_warn(dev, "Specify missing bus_format\n"); + if (desc->bpc != 6 && desc->bpc != 8) + dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc); + break; + default: + dev_warn(dev, "Specify a valid connector_type: %d\n", desc->connector_type); + connector_type = DRM_MODE_CONNECTOR_DPI; + break; + } + panel = devm_drm_panel_alloc(dev, struct panel_simple, base, - &panel_simple_funcs, desc->connector_type); + &panel_simple_funcs, connector_type); if (IS_ERR(panel)) return ERR_CAST(panel); @@ -666,60 +719,6 @@ static struct panel_simple *panel_simple_probe(struct device *dev) goto free_ddc; } - connector_type = desc->connector_type; - /* Catch common mistakes for panels. */ - switch (connector_type) { - case 0: - dev_warn(dev, "Specify missing connector_type\n"); - connector_type = DRM_MODE_CONNECTOR_DPI; - break; - case DRM_MODE_CONNECTOR_LVDS: - WARN_ON(desc->bus_flags & - ~(DRM_BUS_FLAG_DE_LOW | - DRM_BUS_FLAG_DE_HIGH | - DRM_BUS_FLAG_DATA_MSB_TO_LSB | - DRM_BUS_FLAG_DATA_LSB_TO_MSB)); - WARN_ON(desc->bus_format != MEDIA_BUS_FMT_RGB666_1X7X3_SPWG && - desc->bus_format != MEDIA_BUS_FMT_RGB888_1X7X4_SPWG && - desc->bus_format != MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA); - WARN_ON(desc->bus_format == MEDIA_BUS_FMT_RGB666_1X7X3_SPWG && - desc->bpc != 6); - WARN_ON((desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_SPWG || - desc->bus_format == MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA) && - desc->bpc != 8); - break; - case DRM_MODE_CONNECTOR_eDP: - dev_warn(dev, "eDP panels moved to panel-edp\n"); - err = -EINVAL; - goto free_ddc; - case DRM_MODE_CONNECTOR_DSI: - if (desc->bpc != 6 && desc->bpc != 8) - dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc); - break; - case DRM_MODE_CONNECTOR_DPI: - bus_flags = DRM_BUS_FLAG_DE_LOW | - DRM_BUS_FLAG_DE_HIGH | - DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE | - DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE | - DRM_BUS_FLAG_DATA_MSB_TO_LSB | - DRM_BUS_FLAG_DATA_LSB_TO_MSB | - DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE | - DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE; - if (desc->bus_flags & ~bus_flags) - dev_warn(dev, "Unexpected bus_flags(%d)\n", desc->bus_flags & ~bus_flags); - if (!(desc->bus_flags & bus_flags)) - dev_warn(dev, "Specify missing bus_flags\n"); - if (desc->bus_format == 0) - dev_warn(dev, "Specify missing bus_format\n"); - if (desc->bpc != 6 && desc->bpc != 8) - dev_warn(dev, "Expected bpc in {6,8} but got: %u\n", desc->bpc); - break; - default: - dev_warn(dev, "Specify a valid connector_type: %d\n", desc->connector_type); - connector_type = DRM_MODE_CONNECTOR_DPI; - break; - } - dev_set_drvdata(dev, panel); /* From 6b2d155366581705a848833a9b626bfea41d5a8d Mon Sep 17 00:00:00 2001 From: "Nirjhar Roy (IBM)" Date: Mon, 12 Jan 2026 15:35:23 +0530 Subject: [PATCH 169/443] xfs: Fix the return value of xfs_rtcopy_summary() xfs_rtcopy_summary() should return the appropriate error code instead of always returning 0. The caller of this function which is xfs_growfs_rt_bmblock() is already handling the error. Fixes: e94b53ff699c ("xfs: cache last bitmap block in realtime allocator") Signed-off-by: Nirjhar Roy (IBM) Reviewed-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Cc: stable@vger.kernel.org # v6.7 Signed-off-by: Carlos Maiolino --- fs/xfs/xfs_rtalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 167298ad88dd..202dcd2f4039 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -126,7 +126,7 @@ xfs_rtcopy_summary( error = 0; out: xfs_rtbuf_cache_relse(oargs); - return 0; + return error; } /* * Mark an extent specified by start and len allocated. From e0aea42a32984a6fd13410aed7afd3bd0caeb1c1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 9 Jan 2026 16:18:53 +0100 Subject: [PATCH 170/443] xfs: mark __xfs_rtgroup_extents static __xfs_rtgroup_extents is not used outside of xfs_rtgroup.c, so mark it static. Move it and xfs_rtgroup_extents up in the file to avoid forward declarations. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Carlos Maiolino --- fs/xfs/libxfs/xfs_rtgroup.c | 50 ++++++++++++++++++------------------- fs/xfs/libxfs/xfs_rtgroup.h | 2 -- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/fs/xfs/libxfs/xfs_rtgroup.c b/fs/xfs/libxfs/xfs_rtgroup.c index 9186c58e83d5..5a3d0dc6ae1b 100644 --- a/fs/xfs/libxfs/xfs_rtgroup.c +++ b/fs/xfs/libxfs/xfs_rtgroup.c @@ -48,6 +48,31 @@ xfs_rtgroup_min_block( return 0; } +/* Compute the number of rt extents in this realtime group. */ +static xfs_rtxnum_t +__xfs_rtgroup_extents( + struct xfs_mount *mp, + xfs_rgnumber_t rgno, + xfs_rgnumber_t rgcount, + xfs_rtbxlen_t rextents) +{ + ASSERT(rgno < rgcount); + if (rgno == rgcount - 1) + return rextents - ((xfs_rtxnum_t)rgno * mp->m_sb.sb_rgextents); + + ASSERT(xfs_has_rtgroups(mp)); + return mp->m_sb.sb_rgextents; +} + +xfs_rtxnum_t +xfs_rtgroup_extents( + struct xfs_mount *mp, + xfs_rgnumber_t rgno) +{ + return __xfs_rtgroup_extents(mp, rgno, mp->m_sb.sb_rgcount, + mp->m_sb.sb_rextents); +} + /* Precompute this group's geometry */ void xfs_rtgroup_calc_geometry( @@ -136,31 +161,6 @@ out_unwind_new_rtgs: return error; } -/* Compute the number of rt extents in this realtime group. */ -xfs_rtxnum_t -__xfs_rtgroup_extents( - struct xfs_mount *mp, - xfs_rgnumber_t rgno, - xfs_rgnumber_t rgcount, - xfs_rtbxlen_t rextents) -{ - ASSERT(rgno < rgcount); - if (rgno == rgcount - 1) - return rextents - ((xfs_rtxnum_t)rgno * mp->m_sb.sb_rgextents); - - ASSERT(xfs_has_rtgroups(mp)); - return mp->m_sb.sb_rgextents; -} - -xfs_rtxnum_t -xfs_rtgroup_extents( - struct xfs_mount *mp, - xfs_rgnumber_t rgno) -{ - return __xfs_rtgroup_extents(mp, rgno, mp->m_sb.sb_rgcount, - mp->m_sb.sb_rextents); -} - /* * Update the rt extent count of the previous tail rtgroup if it changed during * recovery (i.e. recovery of a growfs). diff --git a/fs/xfs/libxfs/xfs_rtgroup.h b/fs/xfs/libxfs/xfs_rtgroup.h index 03f1e2493334..73cace4d25c7 100644 --- a/fs/xfs/libxfs/xfs_rtgroup.h +++ b/fs/xfs/libxfs/xfs_rtgroup.h @@ -285,8 +285,6 @@ void xfs_free_rtgroups(struct xfs_mount *mp, xfs_rgnumber_t first_rgno, int xfs_initialize_rtgroups(struct xfs_mount *mp, xfs_rgnumber_t first_rgno, xfs_rgnumber_t end_rgno, xfs_rtbxlen_t rextents); -xfs_rtxnum_t __xfs_rtgroup_extents(struct xfs_mount *mp, xfs_rgnumber_t rgno, - xfs_rgnumber_t rgcount, xfs_rtbxlen_t rextents); xfs_rtxnum_t xfs_rtgroup_extents(struct xfs_mount *mp, xfs_rgnumber_t rgno); void xfs_rtgroup_calc_geometry(struct xfs_mount *mp, struct xfs_rtgroup *rtg, xfs_rgnumber_t rgno, xfs_rgnumber_t rgcount, From baed03efe223b1649320e835d7e0c03b3dde0b0c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 9 Jan 2026 16:18:54 +0100 Subject: [PATCH 171/443] xfs: fix an overly long line in xfs_rtgroup_calc_geometry Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Carlos Maiolino --- fs/xfs/libxfs/xfs_rtgroup.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_rtgroup.c b/fs/xfs/libxfs/xfs_rtgroup.c index 5a3d0dc6ae1b..be16efaa6925 100644 --- a/fs/xfs/libxfs/xfs_rtgroup.c +++ b/fs/xfs/libxfs/xfs_rtgroup.c @@ -83,7 +83,8 @@ xfs_rtgroup_calc_geometry( xfs_rtbxlen_t rextents) { rtg->rtg_extents = __xfs_rtgroup_extents(mp, rgno, rgcount, rextents); - rtg_group(rtg)->xg_block_count = rtg->rtg_extents * mp->m_sb.sb_rextsize; + rtg_group(rtg)->xg_block_count = + rtg->rtg_extents * mp->m_sb.sb_rextsize; rtg_group(rtg)->xg_min_gbno = xfs_rtgroup_min_block(mp, rgno); } From df7ec7226fbe14d8654193933da81b2470cc5814 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 9 Jan 2026 16:18:21 +0100 Subject: [PATCH 172/443] xfs: improve the assert at the top of xfs_log_cover Move each condition into a separate assert so that we can see which on triggered. Signed-off-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Carlos Maiolino --- fs/xfs/xfs_log.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index a311385b23d8..d4544ccafea5 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -1180,9 +1180,11 @@ xfs_log_cover( int error = 0; bool need_covered; - ASSERT((xlog_cil_empty(mp->m_log) && xlog_iclogs_empty(mp->m_log) && - !xfs_ail_min_lsn(mp->m_log->l_ailp)) || - xlog_is_shutdown(mp->m_log)); + if (!xlog_is_shutdown(mp->m_log)) { + ASSERT(xlog_cil_empty(mp->m_log)); + ASSERT(xlog_iclogs_empty(mp->m_log)); + ASSERT(!xfs_ail_min_lsn(mp->m_log->l_ailp)); + } if (!xfs_log_writable(mp)) return 0; From a65fd81207669367504b6da7758e130ee23a7dfe Mon Sep 17 00:00:00 2001 From: "Nirjhar Roy (IBM)" Date: Mon, 12 Jan 2026 13:54:02 +0530 Subject: [PATCH 173/443] xfs: Fix xfs_grow_last_rtg() The last rtg should be able to grow when the size of the last is less than (and not equal to) sb_rgextents. xfs_growfs with realtime groups fails without this patch. The reason is that, xfs_growfs_rtg() tries to grow the last rt group even when the last rt group is at its maximal size i.e, sb_rgextents. It fails with the following messages: XFS (loop0): Internal error block >= mp->m_rsumblocks at line 253 of file fs/xfs/libxfs/xfs_rtbitmap.c. Caller xfs_rtsummary_read_buf+0x20/0x80 XFS (loop0): Corruption detected. Unmount and run xfs_repair XFS (loop0): Internal error xfs_trans_cancel at line 976 of file fs/xfs/xfs_trans.c. Caller xfs_growfs_rt_bmblock+0x402/0x450 XFS (loop0): Corruption of in-memory data (0x8) detected at xfs_trans_cancel+0x10a/0x1f0 (fs/xfs/xfs_trans.c:977). Shutting down filesystem. XFS (loop0): Please unmount the filesystem and rectify the problem(s) Signed-off-by: Nirjhar Roy (IBM) Reviewed-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Carlos Maiolino --- fs/xfs/xfs_rtalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 202dcd2f4039..a12ffed12391 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -1326,7 +1326,7 @@ xfs_grow_last_rtg( return true; if (mp->m_sb.sb_rgcount == 0) return false; - return xfs_rtgroup_extents(mp, mp->m_sb.sb_rgcount - 1) <= + return xfs_rtgroup_extents(mp, mp->m_sb.sb_rgcount - 1) < mp->m_sb.sb_rgextents; } From c360004c0160dbe345870f59f24595519008926f Mon Sep 17 00:00:00 2001 From: Brian Foster Date: Fri, 9 Jan 2026 12:49:05 -0500 Subject: [PATCH 174/443] xfs: set max_agbno to allow sparse alloc of last full inode chunk Sparse inode cluster allocation sets min/max agbno values to avoid allocating an inode cluster that might map to an invalid inode chunk. For example, we can't have an inode record mapped to agbno 0 or that extends past the end of a runt AG of misaligned size. The initial calculation of max_agbno is unnecessarily conservative, however. This has triggered a corner case allocation failure where a small runt AG (i.e. 2063 blocks) is mostly full save for an extent to the EOFS boundary: [2050,13]. max_agbno is set to 2048 in this case, which happens to be the offset of the last possible valid inode chunk in the AG. In practice, we should be able to allocate the 4-block cluster at agbno 2052 to map to the parent inode record at agbno 2048, but the max_agbno value precludes it. Note that this can result in filesystem shutdown via dirty trans cancel on stable kernels prior to commit 9eb775968b68 ("xfs: walk all AGs if TRYLOCK passed to xfs_alloc_vextent_iterate_ags") because the tail AG selection by the allocator sets t_highest_agno on the transaction. If the inode allocator spins around and finds an inode chunk with free inodes in an earlier AG, the subsequent dir name creation path may still fail to allocate due to the AG restriction and cancel. To avoid this problem, update the max_agbno calculation to the agbno prior to the last chunk aligned agbno in the AG. This is not necessarily the last valid allocation target for a sparse chunk, but since inode chunks (i.e. records) are chunk aligned and sparse allocs are cluster sized/aligned, this allows the sb_spino_align alignment restriction to take over and round down the max effective agbno to within the last valid inode chunk in the AG. Note that even though the allocator improvements in the aforementioned commit seem to avoid this particular dirty trans cancel situation, the max_agbno logic improvement still applies as we should be able to allocate from an AG that has been appropriately selected. The more important target for this patch however are older/stable kernels prior to this allocator rework/improvement. Cc: stable@vger.kernel.org # v4.2 Fixes: 56d1115c9bc7 ("xfs: allocate sparse inode chunks on full chunk allocation failure") Signed-off-by: Brian Foster Reviewed-by: Darrick J. Wong Signed-off-by: Carlos Maiolino --- fs/xfs/libxfs/xfs_ialloc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index d97295eaebe6..c19d6d713780 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -848,15 +848,16 @@ sparse_alloc: * invalid inode records, such as records that start at agbno 0 * or extend beyond the AG. * - * Set min agbno to the first aligned, non-zero agbno and max to - * the last aligned agbno that is at least one full chunk from - * the end of the AG. + * Set min agbno to the first chunk aligned, non-zero agbno and + * max to one less than the last chunk aligned agbno from the + * end of the AG. We subtract 1 from max so that the cluster + * allocation alignment takes over and allows allocation within + * the last full inode chunk in the AG. */ args.min_agbno = args.mp->m_sb.sb_inoalignmt; args.max_agbno = round_down(xfs_ag_block_count(args.mp, pag_agno(pag)), - args.mp->m_sb.sb_inoalignmt) - - igeo->ialloc_blks; + args.mp->m_sb.sb_inoalignmt) - 1; error = xfs_alloc_vextent_near_bno(&args, xfs_agbno_to_fsb(pag, From 05dc4a9fc8b36d4c99d76bbc02aa9ec0132de4c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 7 Jan 2026 11:39:24 +0100 Subject: [PATCH 175/443] hrtimer: Fix softirq base check in update_needs_ipi() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 'clockid' field is not the correct way to check for a softirq base. Fix the check to correctly compare the base type instead of the clockid. Fixes: 1e7f7fbcd40c ("hrtimer: Avoid more SMP function calls in clock_was_set()") Signed-off-by: Thomas Weißschuh Signed-off-by: Thomas Gleixner Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260107-hrtimer-clock-base-check-v1-1-afb5dbce94a1@linutronix.de --- kernel/time/hrtimer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index bdb30cc5e873..0e4bc1ca15ff 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -913,7 +913,7 @@ static bool update_needs_ipi(struct hrtimer_cpu_base *cpu_base, return true; /* Extra check for softirq clock bases */ - if (base->clockid < HRTIMER_BASE_MONOTONIC_SOFT) + if (base->index < HRTIMER_BASE_MONOTONIC_SOFT) continue; if (cpu_base->softirq_activated) continue; From 26bea10450afe5ad4dd0e0bbb797c44e1df110fe Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Tue, 6 Jan 2026 12:13:15 +0100 Subject: [PATCH 176/443] objtool: fix compilation failure with the x32 toolchain When using the x32 toolchain, compilation fails because the printf specifier "%lx" (long), doesn't match the type of the "checksum" variable (long long). Fix this by changing the printf specifier to "%llx" and casting "checksum" to unsigned long long. Fixes: a3493b33384a ("objtool/klp: Add --debug-checksum= to show per-instruction checksums") Signed-off-by: Mikulas Patocka Signed-off-by: Peter Zijlstra (Intel) Link: https://patch.msgid.link/a1158c99-fe0e-a218-4b5b-ffac212489f6@redhat.com --- tools/objtool/include/objtool/warn.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/objtool/include/objtool/warn.h b/tools/objtool/include/objtool/warn.h index 25ff7942b4d5..2b27b54096b8 100644 --- a/tools/objtool/include/objtool/warn.h +++ b/tools/objtool/include/objtool/warn.h @@ -152,8 +152,8 @@ static inline void unindent(int *unused) { indent--; } if (unlikely(insn->sym && insn->sym->pfunc && \ insn->sym->pfunc->debug_checksum)) { \ char *insn_off = offstr(insn->sec, insn->offset); \ - __dbg("checksum: %s %s %016lx", \ - func->name, insn_off, checksum); \ + __dbg("checksum: %s %s %016llx", \ + func->name, insn_off, (unsigned long long)checksum);\ free(insn_off); \ } \ }) From 479972efc2e7c9e0b3743ac538b042fcd4f315d7 Mon Sep 17 00:00:00 2001 From: Pingfan Liu Date: Tue, 25 Nov 2025 11:26:29 +0800 Subject: [PATCH 177/443] sched/deadline: Remove unnecessary comment in dl_add_task_root_domain() The comments above dl_get_task_effective_cpus() and dl_add_task_root_domain() already explain how to fetch a valid root domain and protect against races. There's no need to repeat this inside dl_add_task_root_domain(). Remove the redundant comment to keep the code clean. No functional change. Signed-off-by: Pingfan Liu Signed-off-by: Peter Zijlstra (Intel) Acked-by: Juri Lelli Acked-by: Waiman Long Link: https://patch.msgid.link/20251125032630.8746-2-piliu@redhat.com --- kernel/sched/deadline.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index 319439fe1870..463ba50f9fff 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -3162,20 +3162,11 @@ void dl_add_task_root_domain(struct task_struct *p) return; } - /* - * Get an active rq, whose rq->rd traces the correct root - * domain. - * Ideally this would be under cpuset reader lock until rq->rd is - * fetched. However, sleepable locks cannot nest inside pi_lock, so we - * rely on the caller of dl_add_task_root_domain() holds 'cpuset_mutex' - * to guarantee the CPU stays in the cpuset. - */ dl_get_task_effective_cpus(p, msk); cpu = cpumask_first_and(cpu_active_mask, msk); BUG_ON(cpu >= nr_cpu_ids); rq = cpu_rq(cpu); dl_b = &rq->rd->dl_bw; - /* End of fetching rd */ raw_spin_lock(&dl_b->lock); __dl_add(dl_b, p->dl.dl_bw, cpumask_weight(rq->rd->span)); From 64e6fa76610ec970cfa8296ed057907a4b384ca5 Mon Sep 17 00:00:00 2001 From: Pingfan Liu Date: Tue, 25 Nov 2025 11:26:30 +0800 Subject: [PATCH 178/443] sched/deadline: Fix potential race in dl_add_task_root_domain() The access rule for local_cpu_mask_dl requires it to be called on the local CPU with preemption disabled. However, dl_add_task_root_domain() currently violates this rule. Without preemption disabled, the following race can occur: 1. ThreadA calls dl_add_task_root_domain() on CPU 0 2. Gets pointer to CPU 0's local_cpu_mask_dl 3. ThreadA is preempted and migrated to CPU 1 4. ThreadA continues using CPU 0's local_cpu_mask_dl 5. Meanwhile, the scheduler on CPU 0 calls find_later_rq() which also uses local_cpu_mask_dl (with preemption properly disabled) 6. Both contexts now corrupt the same per-CPU buffer concurrently Fix this by moving the local_cpu_mask_dl access to the preemption disabled section. Closes: https://lore.kernel.org/lkml/aSBjm3mN_uIy64nz@jlelli-thinkpadt14gen4.remote.csb Fixes: 318e18ed22e8 ("sched/deadline: Walk up cpuset hierarchy to decide root domain when hot-unplug") Reported-by: Juri Lelli Signed-off-by: Pingfan Liu Signed-off-by: Peter Zijlstra (Intel) Acked-by: Juri Lelli Acked-by: Waiman Long Link: https://patch.msgid.link/20251125032630.8746-3-piliu@redhat.com --- kernel/sched/deadline.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index 463ba50f9fff..e3efc40349f1 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -3154,7 +3154,7 @@ void dl_add_task_root_domain(struct task_struct *p) struct rq *rq; struct dl_bw *dl_b; unsigned int cpu; - struct cpumask *msk = this_cpu_cpumask_var_ptr(local_cpu_mask_dl); + struct cpumask *msk; raw_spin_lock_irqsave(&p->pi_lock, rf.flags); if (!dl_task(p) || dl_entity_is_special(&p->dl)) { @@ -3162,6 +3162,7 @@ void dl_add_task_root_domain(struct task_struct *p) return; } + msk = this_cpu_cpumask_var_ptr(local_cpu_mask_dl); dl_get_task_effective_cpus(p, msk); cpu = cpumask_first_and(cpu_active_mask, msk); BUG_ON(cpu >= nr_cpu_ids); From 436326bc525d467e38db1da576139ec5f28268c5 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Tue, 23 Dec 2025 07:03:57 -0500 Subject: [PATCH 179/443] objtool: fix build failure due to missing libopcodes check Commit 59953303827e ("objtool: Disassemble code with libopcodes instead of running objdump") added support for using libopcodes for disassembly. However, the feature detection checks for libbfd availability but then unconditionally links against libopcodes: ifeq ($(feature-libbfd),1) OBJTOOL_LDFLAGS += -lopcodes endif This causes build failures in environments where libbfd is installed but libopcodes is not, since the test-libbfd.c feature test only links against -lbfd and -ldl, not -lopcodes: /usr/bin/ld: cannot find -lopcodes: No such file or directory collect2: error: ld returned 1 exit status make[4]: *** [Makefile:109: objtool] Error 1 Additionally, the shared feature framework uses $(CC) which is the cross-compiler in cross-compilation builds. Since objtool is a host tool that links with $(HOSTCC) against host libraries, the feature detection can falsely report libopcodes as available when the cross-compiler's sysroot has it but the host system doesn't. Fix this by replacing the feature framework check with a direct inline test that uses $(HOSTCC) to compile and link a test program against libopcodes, similar to how xxhash availability is detected. Fixes: 59953303827e ("objtool: Disassemble code with libopcodes instead of running objdump") Assisted-by: claude-opus-4-5-20251101 Signed-off-by: Sasha Levin Signed-off-by: Peter Zijlstra (Intel) Link: https://patch.msgid.link/20251223120357.2492008-1-sashal@kernel.org --- tools/objtool/Makefile | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index ad6e1ec706ce..9b4503113ce5 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -72,23 +72,27 @@ HOST_OVERRIDES := CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)" # # To support disassembly, objtool needs libopcodes which is provided -# with libbdf (binutils-dev or binutils-devel package). +# with libbfd (binutils-dev or binutils-devel package). # -FEATURE_USER = .objtool -FEATURE_TESTS = libbfd disassembler-init-styled -FEATURE_DISPLAY = -include $(srctree)/tools/build/Makefile.feature +# We check using HOSTCC directly rather than the shared feature framework +# because objtool is a host tool that links against host libraries. +# +HAVE_LIBOPCODES := $(shell echo 'int main(void) { return 0; }' | \ + $(HOSTCC) -xc - -o /dev/null -lopcodes 2>/dev/null && echo y) -ifeq ($(feature-disassembler-init-styled), 1) - OBJTOOL_CFLAGS += -DDISASM_INIT_STYLED -endif +# Styled disassembler support requires binutils >= 2.39 +HAVE_DISASM_STYLED := $(shell echo '$(pound)include ' | \ + $(HOSTCC) -E -xc - 2>/dev/null | grep -q disassembler_style && echo y) BUILD_DISAS := n -ifeq ($(feature-libbfd),1) +ifeq ($(HAVE_LIBOPCODES),y) BUILD_DISAS := y - OBJTOOL_CFLAGS += -DDISAS -DPACKAGE="objtool" + OBJTOOL_CFLAGS += -DDISAS -DPACKAGE='"objtool"' OBJTOOL_LDFLAGS += -lopcodes +ifeq ($(HAVE_DISASM_STYLED),y) + OBJTOOL_CFLAGS += -DDISASM_INIT_STYLED +endif endif export BUILD_DISAS From 1e0a2ba7afb1b60f02599093d84b72ce62ad11c0 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 13 Jan 2026 10:50:41 +0100 Subject: [PATCH 180/443] sched: Provide idle_rq() helper A fix for the dl_server 'requires' idle_cpu() usage, which made me note that it and available_idle_cpu() are extern function calls. And while idle_cpu() is used outside of kernel/sched/, available_idle_cpu() is not. This makes it hard to make idle_cpu() an inline helper, so provide idle_rq() and implement idle_cpu() and available_idle_cpu() using that. Signed-off-by: Peter Zijlstra (Intel) --- include/linux/sched.h | 1 - kernel/sched/sched.h | 22 ++++++++++++++++++++++ kernel/sched/syscalls.c | 30 +----------------------------- 3 files changed, 23 insertions(+), 30 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index d395f2810fac..da0133524d08 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1874,7 +1874,6 @@ static inline int task_nice(const struct task_struct *p) extern int can_nice(const struct task_struct *p, const int nice); extern int task_curr(const struct task_struct *p); extern int idle_cpu(int cpu); -extern int available_idle_cpu(int cpu); extern int sched_setscheduler(struct task_struct *, int, const struct sched_param *); extern int sched_setscheduler_nocheck(struct task_struct *, int, const struct sched_param *); extern void sched_set_fifo(struct task_struct *p); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index d30cca6870f5..e885a935b716 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1364,6 +1364,28 @@ static inline u32 sched_rng(void) #define cpu_curr(cpu) (cpu_rq(cpu)->curr) #define raw_rq() raw_cpu_ptr(&runqueues) +static inline bool idle_rq(struct rq *rq) +{ + return rq->curr == rq->idle && !rq->nr_running && !rq->ttwu_pending; +} + +/** + * available_idle_cpu - is a given CPU idle for enqueuing work. + * @cpu: the CPU in question. + * + * Return: 1 if the CPU is currently idle. 0 otherwise. + */ +static inline bool available_idle_cpu(int cpu) +{ + if (!idle_rq(cpu_rq(cpu))) + return 0; + + if (vcpu_is_preempted(cpu)) + return 0; + + return 1; +} + #ifdef CONFIG_SCHED_PROXY_EXEC static inline void rq_set_donor(struct rq *rq, struct task_struct *t) { diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c index 0496dc29ed0f..cb337de679b8 100644 --- a/kernel/sched/syscalls.c +++ b/kernel/sched/syscalls.c @@ -180,35 +180,7 @@ int task_prio(const struct task_struct *p) */ int idle_cpu(int cpu) { - struct rq *rq = cpu_rq(cpu); - - if (rq->curr != rq->idle) - return 0; - - if (rq->nr_running) - return 0; - - if (rq->ttwu_pending) - return 0; - - return 1; -} - -/** - * available_idle_cpu - is a given CPU idle for enqueuing work. - * @cpu: the CPU in question. - * - * Return: 1 if the CPU is currently idle. 0 otherwise. - */ -int available_idle_cpu(int cpu) -{ - if (!idle_cpu(cpu)) - return 0; - - if (vcpu_is_preempted(cpu)) - return 0; - - return 1; + return idle_rq(cpu_rq(cpu)); } /** From ca1e8eede4fc68ce85a9fdce1a6c13ad64933318 Mon Sep 17 00:00:00 2001 From: Gabriele Monaco Date: Tue, 13 Jan 2026 09:52:01 +0100 Subject: [PATCH 181/443] sched/deadline: Fix server stopping with runnable tasks The deadline server can currently stop due to idle although fair tasks are runnable. This happens essentially when: * the server is set to idle, a task wakes up, the server stops * a task wakes up, the server sets itself to idle and stops right away Address both cases by clearing the server idle flag whenever a fair task wakes up and accounting also for pending tasks in the definition of idle. Fixes: f5a538c07df2 ("sched/deadline: Fix dl_server stop condition") Signed-off-by: Gabriele Monaco Signed-off-by: Peter Zijlstra (Intel) Link: https://patch.msgid.link/20260113085159.114226-3-gmonaco@redhat.com --- kernel/sched/deadline.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index e3efc40349f1..b5c19b17e386 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -1420,7 +1420,7 @@ update_stats_dequeue_dl(struct dl_rq *dl_rq, struct sched_dl_entity *dl_se, int static void update_curr_dl_se(struct rq *rq, struct sched_dl_entity *dl_se, s64 delta_exec) { - bool idle = rq->curr == rq->idle; + bool idle = idle_rq(rq); s64 scaled_delta_exec; if (unlikely(delta_exec <= 0)) { @@ -1603,8 +1603,8 @@ void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec) * | 8 | B:zero_laxity-wait | | | * | | | <---+ | * | +--------------------------------+ | - * | | ^ ^ 2 | - * | | 7 | 2 +--------------------+ + * | | ^ ^ 2 | + * | | 7 | 2, 1 +----------------+ * | v | * | +-------------+ | * +-- | C:idle-wait | -+ @@ -1649,8 +1649,11 @@ void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec) * dl_defer_idle = 0 * * - * [1] A->B, A->D + * [1] A->B, A->D, C->B * dl_server_start() + * dl_defer_idle = 0; + * if (dl_server_active) + * return; // [B] * dl_server_active = 1; * enqueue_dl_entity() * update_dl_entity(WAKEUP) @@ -1759,6 +1762,7 @@ void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec) * "B:zero_laxity-wait" -> "C:idle-wait" [label="7:dl_server_update_idle"] * "B:zero_laxity-wait" -> "D:running" [label="3:dl_server_timer"] * "C:idle-wait" -> "A:init" [label="8:dl_server_timer"] + * "C:idle-wait" -> "B:zero_laxity-wait" [label="1:dl_server_start"] * "C:idle-wait" -> "B:zero_laxity-wait" [label="2:dl_server_update"] * "C:idle-wait" -> "C:idle-wait" [label="7:dl_server_update_idle"] * "D:running" -> "A:init" [label="4:pick_task_dl"] @@ -1784,6 +1788,7 @@ void dl_server_start(struct sched_dl_entity *dl_se) { struct rq *rq = dl_se->rq; + dl_se->dl_defer_idle = 0; if (!dl_server(dl_se) || dl_se->dl_server_active) return; From 8af4274ab5999831f4757dfd5bd11665ba3b1569 Mon Sep 17 00:00:00 2001 From: Ulrich Mohr Date: Tue, 9 Dec 2025 21:08:41 +0100 Subject: [PATCH 182/443] USB: serial: option: add Telit LE910 MBIM composition Add support for Telit LE910 module when operating in MBIM composition with additional ttys. This USB product ID is used by the module when AT#USBCFG is set to 7. 0x1252: MBIM + tty(NMEA) + tty(MODEM) + tty(MODEM) + SAP T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=1252 Rev=03.18 S: Manufacturer=Android S: Product=LE910C1-EU S: SerialNumber=0123456789ABCDEF C: #Ifs= 6 Cfg#= 1 Atr=a0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 1 Cls=02(commc) Sub=0e Prot=00 Driver=cdc_mbim E: Ad=82(I) Atr=03(Int.) MxPS= 64 Ivl=32ms I: If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=02 Driver=cdc_mbim E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=86(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=88(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 5 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=89(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8a(I) Atr=03(Int.) MxPS= 10 Ivl=32ms Signed-off-by: Ulrich Mohr Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold --- drivers/usb/serial/option.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 4c0e5a3ab557..9f2cc5fb9f45 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1505,6 +1505,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1231, 0xff), /* Telit LE910Cx (RNDIS) */ .driver_info = NCTRL(2) | RSVD(3) }, { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x1250, 0xff, 0x00, 0x00) }, /* Telit LE910Cx (rmnet) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1252, 0xff) }, /* Telit LE910Cx (MBIM) */ { USB_DEVICE(TELIT_VENDOR_ID, 0x1260), .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, { USB_DEVICE(TELIT_VENDOR_ID, 0x1261), From 12d4fd9a657174496677cff2841315090f1c11fc Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Sat, 10 Jan 2026 12:19:58 -0800 Subject: [PATCH 183/443] soundwire: bus: fix off-by-one when allocating slave IDs ida_alloc_max() interprets its max argument as inclusive. Using SDW_FW_MAX_DEVICES(16) therefore allows an ID of 16 to be allocated, but the IRQ domain created for the bus is sized for IDs 0-15. If 16 is returned, irq_create_mapping() fails and the driver ends up with an invalid IRQ mapping. Limit the allocation to 0-15 by passing SDW_FW_MAX_DEVICES - 1. Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202512240450.hlDH3nCs-lkp@intel.com/ Fixes: aab12022b076 ("soundwire: bus: Add internal slave ID and use for IRQs") Signed-off-by: Harshit Mogalapalli Reviewed-by: Charles Keepax Link: https://patch.msgid.link/20260110201959.2523024-1-harshit.m.mogalapalli@oracle.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus_type.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index 91e70cb46fb5..5c67c13e5735 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -105,7 +105,7 @@ static int sdw_drv_probe(struct device *dev) if (ret) return ret; - ret = ida_alloc_max(&slave->bus->slave_ida, SDW_FW_MAX_DEVICES, GFP_KERNEL); + ret = ida_alloc_max(&slave->bus->slave_ida, SDW_FW_MAX_DEVICES - 1, GFP_KERNEL); if (ret < 0) { dev_err(dev, "Failed to allocated ID: %d\n", ret); return ret; From 8e29db1b08808f709231e6fd4c79dcdee5b17a17 Mon Sep 17 00:00:00 2001 From: Radhi Bajahaw Date: Mon, 12 Jan 2026 21:38:14 +0100 Subject: [PATCH 184/443] ASoC: amd: yc: Fix microphone on ASUS M6500RE Add DMI match for ASUSTeK COMPUTER INC. M6500RE to enable the internal microphone. Signed-off-by: Radhi Bajahaw Link: https://patch.msgid.link/20260112203814.155-1-bajahawradhi@gmail.com Signed-off-by: Mark Brown --- sound/soc/amd/yc/acp6x-mach.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index bf4d9d336561..0294177acc66 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -416,6 +416,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "M6500RC"), } }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "M6500RE"), + } + }, { .driver_data = &acp6x_card, .matches = { From cbd46cbc5470f9cb0bbeff70561a3dd3e0769fe1 Mon Sep 17 00:00:00 2001 From: Aleksandrs Vinarskis Date: Mon, 12 Jan 2026 01:06:37 +0100 Subject: [PATCH 185/443] ALSA: hda/realtek: Add quirk for Asus Zephyrus G14 2025 using CS35L56, fix speakers Just like GA403U, this GA403W needs to remap woofers to DAC1. Similarly to other Asus devices, headphones/headset MIC is not working, however the pin config alone is not enough to fix it. From Windows dump of GA403W: 0x12, 0x90a60140 # Correctly set by codec out of the box 0x13, 0x90a60550 0x14, 0x90170510 0x17, 0x90170120 # Correctly set by codec out of the box 0x19, 0x03a11050 # Set by ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC 0x1a, 0x411115F0 0x1b, 0x03a11c30 # Set by ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC 0x1d, 0x40663A45 # Correctly set by codec out of the box 0x21, 0x03211430 Even with all the values set, MIC of the jack is not detected. Until a complete solution is found, set ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC for GA403W which fixes audio volume control for woofers. No need to create new quirk with missing pin config just yet, since its not making the situation better. Signed-off-by: Aleksandrs Vinarskis Link: https://patch.msgid.link/20260112-asus-rog-audio-v1-1-513957b4704e@vinarskis.com Signed-off-by: Takashi Iwai --- sound/hda/codecs/realtek/alc269.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index 61c7372e6307..dbbe8b498583 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -6817,6 +6817,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8f42, "HP ZBook 8 G2a 14W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x8f57, "HP Trekker G7JC", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8f62, "HP ZBook 8 G2a 16W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED), + SND_PCI_QUIRK(0x1043, 0x1024, "ASUS Zephyrus G14 2025", ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC), SND_PCI_QUIRK(0x1043, 0x1032, "ASUS VivoBook X513EA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1034, "ASUS GU605C", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), From ea4d4ea6d10a561043922d285f1765c7e4bfd32a Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 12 Jan 2026 13:20:46 +0100 Subject: [PATCH 186/443] ata: ahci: Do not read the per port area for unimplemented ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An AHCI HBA specifies the number of ports it supports using CAP.NP. The HBA is free to only make a subset of the number of ports available using the PI (Ports Implemented) register. libata currently creates dummy ports for HBA ports that are provided by the HBA, but which are marked as "unavailable" using the PI register. Each port will have a per port area of registers in the HBA, regardless if the port is marked as "unavailable" or not. ahci_mark_external_port() currently reads this per port area of registers using readl() to see if the port is marked as external/hotplug-capable. However, AHCI 1.3.1, section "3.1.4 Offset 0Ch: PI – Ports Implemented" states: "Software must not read or write to registers within unavailable ports." Thus, make sure that we only call ahci_mark_external_port() and ahci_update_initial_lpm_policy() for ports that are implemented. From a libata perspective, this should not change anything related to LPM, as dummy ports do not provide any ap->ops (they do not have a .set_lpm() callback), so even if EH were to call .set_lpm() on a dummy port, it was already a no-op. Fixes: f7131935238d ("ata: ahci: move marking of external port earlier") Signed-off-by: Niklas Cassel Tested-by: Wolf Signed-off-by: Damien Le Moal --- drivers/ata/ahci.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 7a7f88b3fa2b..931d0081169b 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -2094,13 +2094,13 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (ap->flags & ATA_FLAG_EM) ap->em_message_type = hpriv->em_msg_type; - ahci_mark_external_port(ap); - - ahci_update_initial_lpm_policy(ap); - /* disabled/not-implemented port */ - if (!(hpriv->port_map & (1 << i))) + if (!(hpriv->port_map & (1 << i))) { ap->ops = &ata_dummy_port_ops; + } else { + ahci_mark_external_port(ap); + ahci_update_initial_lpm_policy(ap); + } } /* apply workaround for ASUS P5W DH Deluxe mainboard */ From 8f3fb33f8f3f825c708ece800c921977c157f9b6 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 12 Jan 2026 13:20:47 +0100 Subject: [PATCH 187/443] ata: libata: Call ata_dev_config_lpm() for ATAPI devices Commit d360121832d8 ("ata: libata-core: Introduce ata_dev_config_lpm()") introduced ata_dev_config_lpm(). However, it only called this function for ATA_DEV_ATA and ATA_DEV_ZAC devices, not for ATA_DEV_ATAPI devices. Additionally, commit d99a9142e782 ("ata: libata-core: Move device LPM quirk settings to ata_dev_config_lpm()") moved the LPM quirk application from ata_dev_configure() to ata_dev_config_lpm(), causing LPM quirks for ATAPI devices to no longer be applied. Call ata_dev_config_lpm() also for ATAPI devices, such that LPM quirks are applied for ATAPI devices with an entry in __ata_dev_quirks once again. Fixes: d360121832d8 ("ata: libata-core: Introduce ata_dev_config_lpm()") Fixes: d99a9142e782 ("ata: libata-core: Move device LPM quirk settings to ata_dev_config_lpm()") Signed-off-by: Niklas Cassel Tested-by: Wolf Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 09d8c035fcdf..0d9e527fa8ff 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3116,6 +3116,8 @@ int ata_dev_configure(struct ata_device *dev) ata_mode_string(xfer_mask), cdb_intr_string, atapi_an_string, dma_dir_string); + + ata_dev_config_lpm(dev); } /* determine max_sectors */ From ce83767ea323baf8509a75eb0c783cd203e14789 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 12 Jan 2026 13:20:48 +0100 Subject: [PATCH 188/443] ata: libata-sata: Improve link_power_management_supported sysfs attribute The link_power_management_supported sysfs attribute is currently set as true even for ata ports that lack a .set_lpm() callback, e.g. dummy ports. This is a bit silly, because while writing to the link_power_management_policy sysfs attribute will make ata_scsi_lpm_store() update ap->target_lpm_policy (thus sysfs will reflect the new value) and call ata_port_schedule_eh() for the port, it is essentially a no-op. This is because for a port without a .set_lpm() callback, once EH gets to run, the ata_eh_link_set_lpm() will simply return, since the port does not provide a .set_lpm() callback. Thus, make sure that the link_power_management_supported sysfs attribute is set to false for ports that lack a .set_lpm() callback. This way the link_power_management_policy sysfs attribute will no longer be writable, so we will no longer be misleading users to think that their sysfs write actually does something. Fixes: 0060beec0bfa ("ata: libata-sata: Add link_power_management_supported sysfs attribute") Signed-off-by: Niklas Cassel Tested-by: Wolf Signed-off-by: Damien Le Moal --- drivers/ata/libata-sata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index b2817a2995d6..04e1e774645e 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -909,7 +909,7 @@ static bool ata_scsi_lpm_supported(struct ata_port *ap) struct ata_link *link; struct ata_device *dev; - if (ap->flags & ATA_FLAG_NO_LPM) + if ((ap->flags & ATA_FLAG_NO_LPM) || !ap->ops->set_lpm) return false; ata_for_each_link(link, ap, EDGE) { From a6bee5e5243ad02cae575becc4c83df66fc29573 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 12 Jan 2026 13:20:49 +0100 Subject: [PATCH 189/443] ata: libata: Add cpr_log to ata_dev_print_features() early return ata_dev_print_features() is supposed to return early and not print anything if there are no features supported. However, commit fe22e1c2f705 ("libata: support concurrent positioning ranges log") added another feature to ata_dev_print_features() without updating the early return conditional. Add the missing feature to the early return conditional. Fixes: fe22e1c2f705 ("libata: support concurrent positioning ranges log") Signed-off-by: Niklas Cassel Tested-by: Wolf Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 0d9e527fa8ff..9301c262eabb 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2872,7 +2872,7 @@ static void ata_dev_config_lpm(struct ata_device *dev) static void ata_dev_print_features(struct ata_device *dev) { - if (!(dev->flags & ATA_DFLAG_FEATURES_MASK)) + if (!(dev->flags & ATA_DFLAG_FEATURES_MASK) && !dev->cpr_log) return; ata_dev_info(dev, From 89531b68fc293e91187bf0992147e8d22c65cff3 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 12 Jan 2026 13:20:50 +0100 Subject: [PATCH 190/443] ata: libata: Add DIPM and HIPM to ata_dev_print_features() early return ata_dev_print_features() is supposed to return early and not print anything if there are no features supported. However, commit b1f5af54f1f5 ("ata: libata-core: Advertize device support for DIPM and HIPM features") added additional features to ata_dev_print_features() without updating the early return conditional. Add the missing features to the early return conditional. Fixes: b1f5af54f1f5 ("ata: libata-core: Advertize device support for DIPM and HIPM features") Signed-off-by: Niklas Cassel Tested-by: Wolf Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9301c262eabb..2e7df131fdde 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2872,7 +2872,8 @@ static void ata_dev_config_lpm(struct ata_device *dev) static void ata_dev_print_features(struct ata_device *dev) { - if (!(dev->flags & ATA_DFLAG_FEATURES_MASK) && !dev->cpr_log) + if (!(dev->flags & ATA_DFLAG_FEATURES_MASK) && !dev->cpr_log && + !ata_id_has_hipm(dev->id) && !ata_id_has_dipm(dev->id)) return; ata_dev_info(dev, From c8c6fb886f57d5bf71fb6de6334a143608d35707 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 12 Jan 2026 13:20:51 +0100 Subject: [PATCH 191/443] ata: libata: Print features also for ATAPI devices Commit d633b8a702ab ("libata: print feature list on device scan") added a print of the features supported by the device for ATA_DEV_ATA and ATA_DEV_ZAC devices, but not for ATA_DEV_ATAPI devices. Fix this by printing the features also for ATAPI devices. Before changes: ata1.00: ATAPI: Slimtype DVD A DU8AESH, 6C2M, max UDMA/133 After changes: ata1.00: ATAPI: Slimtype DVD A DU8AESH, 6C2M, max UDMA/133 ata1.00: Features: Dev-Attention HIPM DIPM Fixes: d633b8a702ab ("libata: print feature list on device scan") Signed-off-by: Niklas Cassel Tested-by: Wolf Signed-off-by: Damien Le Moal --- drivers/ata/libata-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 2e7df131fdde..ddf9a7b28a59 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3119,6 +3119,9 @@ int ata_dev_configure(struct ata_device *dev) dma_dir_string); ata_dev_config_lpm(dev); + + if (print_info) + ata_dev_print_features(dev); } /* determine max_sectors */ From c0afe95e62984ceea171c3ea319beaf84a21181c Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Wed, 10 Dec 2025 18:01:17 -0800 Subject: [PATCH 192/443] USB: serial: ftdi_sio: add support for PICAXE AXE027 cable The vendor provides instructions to write "0403 bd90" to /sys/bus/usb-serial/drivers/ftdi_sio/new_id; see: https://picaxe.com/docs/picaxe_linux_instructions.pdf Cc: stable@vger.kernel.org Signed-off-by: Ethan Nelson-Moore Signed-off-by: Johan Hovold --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index fe2f21d85737..acb48b1c83f7 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -848,6 +848,7 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, LMI_LM3S_DEVEL_BOARD_PID, 1) }, { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID, 1) }, { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID, 1) }, + { USB_DEVICE(FTDI_VID, FTDI_AXE027_PID) }, { USB_DEVICE_INTERFACE_NUMBER(FTDI_VID, FTDI_TURTELIZER_PID, 1) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_SCU18) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 2539b9e2f712..6c76cfebfd0e 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -96,6 +96,8 @@ #define LMI_LM3S_EVAL_BOARD_PID 0xbcd9 #define LMI_LM3S_ICDI_BOARD_PID 0xbcda +#define FTDI_AXE027_PID 0xBD90 /* PICAXE AXE027 USB download cable */ + #define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmbH */ /* OpenDCC (www.opendcc.de) product id */ From c5e96e54eca3876d4ce8857e2e22adbe9f44f4a2 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 13 Jan 2026 13:09:54 +0000 Subject: [PATCH 193/443] ALSA: hda/cirrus_scodec_test: Fix incorrect setup of gpiochip Set gpiochip parent to the struct device of the dummy GPIO driver so that the software node will be associated with the GPIO chip. The recent commit e5d527be7e698 ("gpio: swnode: don't use the swnode's name as the key for GPIO lookup") broke cirrus_scodec_test, because the software node no longer gets associated with the GPIO driver by name. Instead, setting struct gpio_chip.parent to the owning struct device will find the node using a normal fwnode lookup. Signed-off-by: Richard Fitzgerald Fixes: 2144833e7b414 ("ALSA: hda: cirrus_scodec: Add KUnit test") Link: https://patch.msgid.link/20260113130954.574670-1-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/hda/codecs/side-codecs/cirrus_scodec_test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/hda/codecs/side-codecs/cirrus_scodec_test.c b/sound/hda/codecs/side-codecs/cirrus_scodec_test.c index 3cca750857b6..159ac80a9314 100644 --- a/sound/hda/codecs/side-codecs/cirrus_scodec_test.c +++ b/sound/hda/codecs/side-codecs/cirrus_scodec_test.c @@ -103,6 +103,7 @@ static int cirrus_scodec_test_gpio_probe(struct platform_device *pdev) /* GPIO core modifies our struct gpio_chip so use a copy */ gpio_priv->chip = cirrus_scodec_test_gpio_chip; + gpio_priv->chip.parent = &pdev->dev; ret = devm_gpiochip_add_data(&pdev->dev, &gpio_priv->chip, gpio_priv); if (ret) return dev_err_probe(&pdev->dev, ret, "Failed to add gpiochip\n"); From 6a0243c4020636482797acfd48d7d9b0ea2f2a20 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 13 Jan 2026 13:40:56 +0000 Subject: [PATCH 194/443] ALSA: hda/cirrus_scodec_test: Fix test suite name Change the test suite name string to "snd-hda-cirrus-scodec-test". It was incorrectly named "snd-hda-scodec-cs35l56-test", a leftover from when the code under test was actually in the cs35l56 driver. Signed-off-by: Richard Fitzgerald Fixes: 2144833e7b414 ("ALSA: hda: cirrus_scodec: Add KUnit test") Link: https://patch.msgid.link/20260113134056.619051-1-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/hda/codecs/side-codecs/cirrus_scodec_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/hda/codecs/side-codecs/cirrus_scodec_test.c b/sound/hda/codecs/side-codecs/cirrus_scodec_test.c index 159ac80a9314..dc35932b6b22 100644 --- a/sound/hda/codecs/side-codecs/cirrus_scodec_test.c +++ b/sound/hda/codecs/side-codecs/cirrus_scodec_test.c @@ -320,7 +320,7 @@ static struct kunit_case cirrus_scodec_test_cases[] = { }; static struct kunit_suite cirrus_scodec_test_suite = { - .name = "snd-hda-scodec-cs35l56-test", + .name = "snd-hda-cirrus-scodec-test", .init = cirrus_scodec_test_case_init, .test_cases = cirrus_scodec_test_cases, }; From dc2d5ddb193e363187bae2ad358245642d2721fb Mon Sep 17 00:00:00 2001 From: Shenghao Yang Date: Wed, 31 Dec 2025 13:50:26 +0800 Subject: [PATCH 195/443] drm/gud: fix NULL fb and crtc dereferences on USB disconnect On disconnect drm_atomic_helper_disable_all() is called which sets both the fb and crtc for a plane to NULL before invoking a commit. This causes a kernel oops on every display disconnect. Add guards for those dereferences. Cc: # 6.18.x Fixes: 73cfd166e045 ("drm/gud: Replace simple display pipe with DRM atomic helpers") Signed-off-by: Shenghao Yang Reviewed-by: Ruben Wauters Signed-off-by: Ruben Wauters Link: https://patch.msgid.link/20251231055039.44266-1-me@shenghaoyang.info --- drivers/gpu/drm/gud/gud_pipe.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index 76d77a736d84..4b77be94348d 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -457,27 +457,20 @@ int gud_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); struct drm_crtc *crtc = new_plane_state->crtc; - struct drm_crtc_state *crtc_state; + struct drm_crtc_state *crtc_state = NULL; const struct drm_display_mode *mode; struct drm_framebuffer *old_fb = old_plane_state->fb; struct drm_connector_state *connector_state = NULL; struct drm_framebuffer *fb = new_plane_state->fb; - const struct drm_format_info *format = fb->format; + const struct drm_format_info *format; struct drm_connector *connector; unsigned int i, num_properties; struct gud_state_req *req; int idx, ret; size_t len; - if (drm_WARN_ON_ONCE(plane->dev, !fb)) - return -EINVAL; - - if (drm_WARN_ON_ONCE(plane->dev, !crtc)) - return -EINVAL; - - crtc_state = drm_atomic_get_new_crtc_state(state, crtc); - - mode = &crtc_state->mode; + if (crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, DRM_PLANE_NO_SCALING, @@ -492,6 +485,9 @@ int gud_plane_atomic_check(struct drm_plane *plane, if (old_plane_state->rotation != new_plane_state->rotation) crtc_state->mode_changed = true; + mode = &crtc_state->mode; + format = fb->format; + if (old_fb && old_fb->format != format) crtc_state->mode_changed = true; @@ -598,7 +594,7 @@ void gud_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_helper_damage_iter iter; int ret, idx; - if (crtc->state->mode_changed || !crtc->state->enable) { + if (!crtc || crtc->state->mode_changed || !crtc->state->enable) { cancel_work_sync(&gdrm->work); mutex_lock(&gdrm->damage_lock); if (gdrm->fb) { From ef5749ef8b307bf8717945701b1b79d036af0a15 Mon Sep 17 00:00:00 2001 From: Edward Adam Davis Date: Tue, 13 Jan 2026 16:29:23 +0800 Subject: [PATCH 196/443] ALSA: usb-audio: Prevent excessive number of frames In this case, the user constructed the parameters with maxpacksize 40 for rate 22050 / pps 1000, and packsize[0] 22 packsize[1] 23. The buffer size for each data URB is maxpacksize * packets, which in this example is 40 * 6 = 240; When the user performs a write operation to send audio data into the ALSA PCM playback stream, the calculated number of frames is packsize[0] * packets = 264, which exceeds the allocated URB buffer size, triggering the out-of-bounds (OOB) issue reported by syzbot [1]. Added a check for the number of single data URB frames when calculating the number of frames to prevent [1]. [1] BUG: KASAN: slab-out-of-bounds in copy_to_urb+0x261/0x460 sound/usb/pcm.c:1487 Write of size 264 at addr ffff88804337e800 by task syz.0.17/5506 Call Trace: copy_to_urb+0x261/0x460 sound/usb/pcm.c:1487 prepare_playback_urb+0x953/0x13d0 sound/usb/pcm.c:1611 prepare_outbound_urb+0x377/0xc50 sound/usb/endpoint.c:333 Reported-by: syzbot+6db0415d6d5c635f72cb@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=6db0415d6d5c635f72cb Tested-by: syzbot+6db0415d6d5c635f72cb@syzkaller.appspotmail.com Signed-off-by: Edward Adam Davis Link: https://patch.msgid.link/tencent_9AECE6CD2C7A826D902D696C289724E8120A@qq.com Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 54d01dfd820f..263abb36bb2d 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -1553,7 +1553,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, for (i = 0; i < ctx->packets; i++) { counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, avail); - if (counts < 0) + if (counts < 0 || frames + counts >= ep->max_urb_frames) break; /* set up descriptor */ urb->iso_frame_desc[i].offset = frames * stride; From 40b94ec7edbbb867c4e26a1a43d2b898f04b93c5 Mon Sep 17 00:00:00 2001 From: Nilay Shroff Date: Tue, 13 Jan 2026 12:27:22 +0530 Subject: [PATCH 197/443] null_blk: fix kmemleak by releasing references to fault configfs items When CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION is enabled, the null-blk driver sets up fault injection support by creating the timeout_inject, requeue_inject, and init_hctx_fault_inject configfs items as children of the top-level nullbX configfs group. However, when the nullbX device is removed, the references taken to these fault-config configfs items are not released. As a result, kmemleak reports a memory leak, for example: unreferenced object 0xc00000021ff25c40 (size 32): comm "mkdir", pid 10665, jiffies 4322121578 hex dump (first 32 bytes): 69 6e 69 74 5f 68 63 74 78 5f 66 61 75 6c 74 5f init_hctx_fault_ 69 6e 6a 65 63 74 00 88 00 00 00 00 00 00 00 00 inject.......... backtrace (crc 1a018c86): __kmalloc_node_track_caller_noprof+0x494/0xbd8 kvasprintf+0x74/0xf4 config_item_set_name+0xf0/0x104 config_group_init_type_name+0x48/0xfc fault_config_init+0x48/0xf0 0xc0080000180559e4 configfs_mkdir+0x304/0x814 vfs_mkdir+0x49c/0x604 do_mkdirat+0x314/0x3d0 sys_mkdir+0xa0/0xd8 system_call_exception+0x1b0/0x4f0 system_call_vectored_common+0x15c/0x2ec Fix this by explicitly releasing the references to the fault-config configfs items when dropping the reference to the top-level nullbX configfs group. Cc: stable@vger.kernel.org Reviewed-by: Chaitanya Kulkarni Fixes: bb4c19e030f4 ("block: null_blk: make fault-injection dynamically configurable per device") Signed-off-by: Nilay Shroff Signed-off-by: Jens Axboe --- drivers/block/null_blk/main.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c index c7c0fb79a6bf..4c0632ab4e1b 100644 --- a/drivers/block/null_blk/main.c +++ b/drivers/block/null_blk/main.c @@ -665,12 +665,22 @@ static void nullb_add_fault_config(struct nullb_device *dev) configfs_add_default_group(&dev->init_hctx_fault_config.group, &dev->group); } +static void nullb_del_fault_config(struct nullb_device *dev) +{ + config_item_put(&dev->init_hctx_fault_config.group.cg_item); + config_item_put(&dev->requeue_config.group.cg_item); + config_item_put(&dev->timeout_config.group.cg_item); +} + #else static void nullb_add_fault_config(struct nullb_device *dev) { } +static void nullb_del_fault_config(struct nullb_device *dev) +{ +} #endif static struct @@ -702,7 +712,7 @@ nullb_group_drop_item(struct config_group *group, struct config_item *item) null_del_dev(dev->nullb); mutex_unlock(&lock); } - + nullb_del_fault_config(dev); config_item_put(item); } From cd644b805da8a253198718741bf363c4c58862ff Mon Sep 17 00:00:00 2001 From: "Ji-Ze Hong (Peter Hong)" Date: Fri, 12 Dec 2025 15:08:31 +0800 Subject: [PATCH 198/443] USB: serial: f81232: fix incomplete serial port generation The Fintek F81532A/534A/535/536 family relies on the F81534A_CTRL_CMD_ENABLE_PORT (116h) register during initialization to both determine serial port status and control port creation. If the driver experiences fast load/unload cycles, the device state may becomes unstable, resulting in the incomplete generation of serial ports. Performing a dummy read operation on the register prior to the initial write command resolves the issue. This clears the device's stale internal state. Subsequent write operations will correctly generate all serial ports. This patch also removes the retry loop in f81534a_ctrl_set_register() because the stale state has been fixed. Tested on: HygonDM1SLT(Hygon C86 3250 8-core Processor) Signed-off-by: Ji-Ze Hong (Peter Hong) Signed-off-by: Johan Hovold --- drivers/usb/serial/f81232.c | 77 ++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 530b77fc2f78..9262a2ac97f5 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -70,7 +70,6 @@ MODULE_DEVICE_TABLE(usb, combined_id_table); #define F81232_REGISTER_REQUEST 0xa0 #define F81232_GET_REGISTER 0xc0 #define F81232_SET_REGISTER 0x40 -#define F81534A_ACCESS_REG_RETRY 2 #define SERIAL_BASE_ADDRESS 0x0120 #define RECEIVE_BUFFER_REGISTER (0x00 + SERIAL_BASE_ADDRESS) @@ -824,36 +823,31 @@ static void f81232_lsr_worker(struct work_struct *work) static int f81534a_ctrl_set_register(struct usb_interface *intf, u16 reg, u16 size, void *val) { - struct usb_device *dev = interface_to_usbdev(intf); - int retry = F81534A_ACCESS_REG_RETRY; - int status; + return usb_control_msg_send(interface_to_usbdev(intf), + 0, + F81232_REGISTER_REQUEST, + F81232_SET_REGISTER, + reg, + 0, + val, + size, + USB_CTRL_SET_TIMEOUT, + GFP_KERNEL); +} - while (retry--) { - status = usb_control_msg_send(dev, - 0, - F81232_REGISTER_REQUEST, - F81232_SET_REGISTER, - reg, - 0, - val, - size, - USB_CTRL_SET_TIMEOUT, - GFP_KERNEL); - if (status) { - status = usb_translate_errors(status); - if (status == -EIO) - continue; - } - - break; - } - - if (status) { - dev_err(&intf->dev, "failed to set register 0x%x: %d\n", - reg, status); - } - - return status; +static int f81534a_ctrl_get_register(struct usb_interface *intf, u16 reg, + u16 size, void *val) +{ + return usb_control_msg_recv(interface_to_usbdev(intf), + 0, + F81232_REGISTER_REQUEST, + F81232_GET_REGISTER, + reg, + 0, + val, + size, + USB_CTRL_GET_TIMEOUT, + GFP_KERNEL); } static int f81534a_ctrl_enable_all_ports(struct usb_interface *intf, bool en) @@ -869,6 +863,29 @@ static int f81534a_ctrl_enable_all_ports(struct usb_interface *intf, bool en) * bit 0~11 : Serial port enable bit. */ if (en) { + /* + * The Fintek F81532A/534A/535/536 family relies on the + * F81534A_CTRL_CMD_ENABLE_PORT (116h) register during + * initialization to both determine serial port status and + * control port creation. + * + * If the driver experiences fast load/unload cycles, the + * device state may becomes unstable, resulting in the + * incomplete generation of serial ports. + * + * Performing a dummy read operation on the register prior + * to the initial write command resolves the issue. + * + * This clears the device's stale internal state. Subsequent + * write operations will correctly generate all serial ports. + */ + status = f81534a_ctrl_get_register(intf, + F81534A_CTRL_CMD_ENABLE_PORT, + sizeof(enable), + enable); + if (status) + return status; + enable[0] = 0xff; enable[1] = 0x8f; } From 6ee98aabdc700b5705e4f1833e2edc82a826b53b Mon Sep 17 00:00:00 2001 From: Xiaochen Shen Date: Tue, 9 Dec 2025 14:26:49 +0800 Subject: [PATCH 199/443] x86/resctrl: Add missing resctrl initialization for Hygon Hygon CPUs supporting Platform QoS features currently undergo partial resctrl initialization through resctrl_cpu_detect() in the Hygon BSP init helper and AMD/Hygon common initialization code. However, several critical data structures remain uninitialized for Hygon CPUs in the following paths: - get_mem_config()-> __rdt_get_mem_config_amd(): rdt_resource::membw,alloc_capable hw_res::num_closid - rdt_init_res_defs()->rdt_init_res_defs_amd(): rdt_resource::cache hw_res::msr_base,msr_update Add the missing AMD/Hygon common initialization to ensure proper Platform QoS functionality on Hygon CPUs. Fixes: d8df126349da ("x86/cpu/hygon: Add missing resctrl_cpu_detect() in bsp_init helper") Signed-off-by: Xiaochen Shen Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Reinette Chatre Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251209062650.1536952-2-shenxiaochen@open-hieco.net --- arch/x86/kernel/cpu/resctrl/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index 3792ab4819dc..10de1594d328 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -825,7 +825,8 @@ static __init bool get_mem_config(void) if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) return __get_mem_config_intel(&hw_res->r_resctrl); - else if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + else if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD || + boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) return __rdt_get_mem_config_amd(&hw_res->r_resctrl); return false; @@ -987,7 +988,8 @@ static __init void rdt_init_res_defs(void) { if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) rdt_init_res_defs_intel(); - else if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + else if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD || + boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) rdt_init_res_defs_amd(); } From 39c90b1a1dbe6d7c49d19da6e5aec00980c55d8b Mon Sep 17 00:00:00 2001 From: Manish Dharanenthiran Date: Wed, 7 Jan 2026 11:32:35 +0530 Subject: [PATCH 200/443] wifi: ath12k: cancel scan only on active scan vdev Cancel the scheduled scan request only on the vdev that has an active scan running. Currently, ahvif->links_map is used to obtain the links, but this includes links for which no scan is scheduled. In failure cases where the scan fails due to an invalid channel definition, other links which are not yet brought up (vdev not created) may also be accessed, leading to the following trace: Unable to handle kernel paging request at virtual address 0000000000004c8c pc : _raw_spin_lock_bh+0x1c/0x54 lr : ath12k_scan_abort+0x20/0xc8 [ath12k] Call trace: _raw_spin_lock_bh+0x1c/0x54 (P) ath12k_mac_op_cancel_hw_scan+0xac/0xc4 [ath12k] ieee80211_scan_cancel+0xcc/0x12c [mac80211] ieee80211_do_stop+0x6c4/0x7a8 [mac80211] ieee80211_stop+0x60/0xd8 [mac80211] Skip links that are not created or are not the current scan vdev. This ensures only the scan for the matching links is aborted and avoids aborting unrelated links during cancellation, thus aligning with how start/cleanup manage ar->scan.arvif. Also, remove the redundant arvif->is_started check from ath12k_mac_op_cancel_hw_scan() that was introduced in commit 3863f014ad23 ("wifi: ath12k: symmetrize scan vdev creation and deletion during HW scan") to avoid deleting the scan interface if the scan is triggered on the existing AP vdev as this use case is already handled in ath12k_scan_vdev_clean_work(). Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Fixes: feed05f1526e ("wifi: ath12k: Split scan request for split band device") Signed-off-by: Manish Dharanenthiran Reviewed-by: Baochen Qiang Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20260107-scan_vdev-v1-1-b600aedc645a@qti.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index f7a2a544bef2..088b5ffd0797 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -5495,7 +5495,8 @@ static void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw, for_each_set_bit(link_id, &links_map, ATH12K_NUM_MAX_LINKS) { arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); - if (!arvif || arvif->is_started) + if (!arvif || !arvif->is_created || + arvif->ar->scan.arvif != arvif) continue; ar = arvif->ar; From 8b8d6ee53dfdee61b0beff66afe3f712456e707a Mon Sep 17 00:00:00 2001 From: Yingying Tang Date: Mon, 12 Jan 2026 19:55:16 +0800 Subject: [PATCH 201/443] wifi: ath12k: Fix scan state stuck in ABORTING after cancel_remain_on_channel Scan finish workqueue was introduced in __ath12k_mac_scan_finish() by [1]. During ath12k_mac_op_cancel_remain_on_channel(), scan state is set to ABORTING and should be reset to IDLE in the queued work. However, wiphy_work_cancel() is called before exiting ath12k_mac_op_cancel_remain_on_channel(), which prevents the work from running and leaves the state in ABORTING. This blocks all subsequent scan requests. Replace wiphy_work_cancel() with wiphy_work_flush() to ensure the queued work runs and scan state is reset to IDLE. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Fixes: 3863f014ad23 ("wifi: ath12k: symmetrize scan vdev creation and deletion during HW scan") # [1] Signed-off-by: Yingying Tang Reviewed-by: Vasanthakumar Thiagarajan Reviewed-by: Baochen Qiang Link: https://patch.msgid.link/20260112115516.2144219-1-yingying.tang@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 088b5ffd0797..ed2ac2fe12f0 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -13344,7 +13344,7 @@ static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw, ath12k_scan_abort(ar); cancel_delayed_work_sync(&ar->scan.timeout); - wiphy_work_cancel(hw->wiphy, &ar->scan.vdev_clean_wk); + wiphy_work_flush(hw->wiphy, &ar->scan.vdev_clean_wk); return 0; } From f88e9fc30a261d63946ddc6cc6a33405e6aa27c3 Mon Sep 17 00:00:00 2001 From: Baochen Qiang Date: Tue, 13 Jan 2026 09:48:11 +0800 Subject: [PATCH 202/443] wifi: ath12k: fix dead lock while flushing management frames Commit [1] converted the management transmission work item into a wiphy work. Since a wiphy work can only run under wiphy lock protection, a race condition happens in below scenario: 1. a management frame is queued for transmission. 2. ath12k_mac_op_flush() gets called to flush pending frames associated with the hardware (i.e, vif being NULL). Then in ath12k_mac_flush() the process waits for the transmission done. 3. Since wiphy lock has been taken by the flush process, the transmission work item has no chance to run, hence the dead lock. >From user view, this dead lock results in below issue: wlp8s0: authenticate with xxxxxx (local address=xxxxxx) wlp8s0: send auth to xxxxxx (try 1/3) wlp8s0: authenticate with xxxxxx (local address=xxxxxx) wlp8s0: send auth to xxxxxx (try 1/3) wlp8s0: authenticated wlp8s0: associate with xxxxxx (try 1/3) wlp8s0: aborting association with xxxxxx by local choice (Reason: 3=DEAUTH_LEAVING) ath12k_pci 0000:08:00.0: failed to flush mgmt transmit queue, mgmt pkts pending 1 The dead lock can be avoided by invoking wiphy_work_flush() to proactively run the queued work item. Note actually it is already present in ath12k_mac_op_flush(), however it does not protect the case where vif being NULL. Hence move it ahead to cover this case as well. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Fixes: 56dcbf0b5207 ("wifi: ath12k: convert struct ath12k::wmi_mgmt_tx_work to struct wiphy_work") # [1] Reported-by: Stuart Hayhurst Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220959 Signed-off-by: Baochen Qiang Reviewed-by: Vasanthakumar Thiagarajan Link: https://patch.msgid.link/20260113-ath12k-fix-dead-lock-while-flushing-v1-1-9713621f3a0f@oss.qualcomm.com Signed-off-by: Jeff Johnson --- drivers/net/wireless/ath/ath12k/mac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index ed2ac2fe12f0..8476a1ff308d 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -12143,6 +12143,9 @@ static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v if (drop) return; + for_each_ar(ah, ar, i) + wiphy_work_flush(hw->wiphy, &ar->wmi_mgmt_tx_work); + /* vif can be NULL when flush() is considered for hw */ if (!vif) { for_each_ar(ah, ar, i) @@ -12150,9 +12153,6 @@ static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v return; } - for_each_ar(ah, ar, i) - wiphy_work_flush(hw->wiphy, &ar->wmi_mgmt_tx_work); - ahvif = ath12k_vif_to_ahvif(vif); links = ahvif->links_map; for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { From 31707572108da55a005e7fed32cc3869c16b7c16 Mon Sep 17 00:00:00 2001 From: Yingying Tang Date: Tue, 13 Jan 2026 13:46:36 +0800 Subject: [PATCH 203/443] wifi: ath12k: Fix wrong P2P device link id issue Wrong P2P device link id value of 0 was introduced in ath12k_mac_op_tx() by [1]. During the P2P negotiation process, there is only one scan vdev with link ID 15. Currently, the device link ID is incorrectly set to 0 in ath12k_mac_op_tx() during the P2P negotiation process, which leads to TX failures. Set the correct P2P device link ID to 15 to fix the TX failure issue. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3 Fixes: 648a121bafa3 ("wifi: ath12k: ath12k_mac_op_tx(): MLO support") # [1] Signed-off-by: Yingying Tang Reviewed-by: Baochen Qiang Reviewed-by: Vasanthakumar Thiagarajan Cc: linux-next@vger.kernel.org Cc: netdev@vger.kernel.org Link: https://patch.msgid.link/20260113054636.2620035-1-yingying.tang@oss.qualcomm.com Signed-off-by: Jeff Johnson --- Note to linux-next and netdev maintainers: This patch going through the "current" tree conflicts with the following going through the "next" tree: commit 631ee338f04d ("Merge branch 'ath12k-ng' into ath-next") The conflict resolution is to leave the following file unmodified: drivers/net/wireless/ath/ath12k/mac. And to apply the following patch to ath12k_wifi7_mac_op_tx() in the file drivers/net/wireless/ath/ath12k/wifi7/hw.c -705,7 +705,10 return; } } else { - link_id = 0; + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) + link_id = ATH12K_FIRST_SCAN_LINK; + else + link_id = 0; } arvif = rcu_dereference(ahvif->link[link_id]); --- drivers/net/wireless/ath/ath12k/mac.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 8476a1ff308d..e0e49f782bf8 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -9173,7 +9173,10 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, return; } } else { - link_id = 0; + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) + link_id = ATH12K_FIRST_SCAN_LINK; + else + link_id = 0; } arvif = rcu_dereference(ahvif->link[link_id]); From 2fa8961d3a6a1c2395d8d560ffed2c782681bade Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 18 Aug 2025 11:32:45 +0200 Subject: [PATCH 204/443] nvmet-tcp: fixup hang in nvmet_tcp_listen_data_ready() When the socket is closed while in TCP_LISTEN a callback is run to flush all outstanding packets, which in turns calls nvmet_tcp_listen_data_ready() with the sk_callback_lock held. So we need to check if we are in TCP_LISTEN before attempting to get the sk_callback_lock() to avoid a deadlock. Link: https://lore.kernel.org/linux-nvme/CAHj4cs-zu7eVB78yUpFjVe2UqMWFkLk8p+DaS3qj+uiGCXBAoA@mail.gmail.com/ Tested-by: Yi Zhang Reviewed-by: Sagi Grimberg Signed-off-by: Hannes Reinecke Signed-off-by: Keith Busch --- drivers/nvme/target/tcp.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index d5966d007ba3..549a4786d1c3 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -2004,14 +2004,13 @@ static void nvmet_tcp_listen_data_ready(struct sock *sk) trace_sk_data_ready(sk); + if (sk->sk_state != TCP_LISTEN) + return; + read_lock_bh(&sk->sk_callback_lock); port = sk->sk_user_data; - if (!port) - goto out; - - if (sk->sk_state == TCP_LISTEN) + if (port) queue_work(nvmet_wq, &port->accept_work); -out: read_unlock_bh(&sk->sk_callback_lock); } From 747d2464e6e3c690184fabc7cc104c1a2064c9c3 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Mon, 15 Dec 2025 15:28:05 -0600 Subject: [PATCH 205/443] dt-bindings: i2c: brcm,iproc-i2c: Allow 2 reg entries for brcm,iproc-nic-i2c The brcm,iproc-nic-i2c variant has 2 reg entries. The second one is related to the brcm,ape-hsls-addr-mask property, but it's not clear what a proper description would be. Signed-off-by: Rob Herring (Arm) Reviewed-by: Florian Fainelli Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/brcm,iproc-i2c.yaml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.yaml b/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.yaml index 2aa75b7add7b..daa70a8500e9 100644 --- a/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.yaml +++ b/Documentation/devicetree/bindings/i2c/brcm,iproc-i2c.yaml @@ -16,7 +16,8 @@ properties: - brcm,iproc-nic-i2c reg: - maxItems: 1 + minItems: 1 + maxItems: 2 clock-frequency: enum: [ 100000, 400000 ] @@ -41,8 +42,15 @@ allOf: contains: const: brcm,iproc-nic-i2c then: + properties: + reg: + minItems: 2 required: - brcm,ape-hsls-addr-mask + else: + properties: + reg: + maxItems: 1 unevaluatedProperties: false From 8441c7d3bd6c5a52ab2ecf77e43a5bf262004f5c Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Wed, 7 Jan 2026 13:05:43 +0100 Subject: [PATCH 206/443] cxl: Check for invalid addresses returned from translation functions on errors Translation functions may return an invalid address in case of errors. If the address is not checked the further use of the invalid value will cause an address corruption. Consistently check for a valid address returned by translation functions. Use RESOURCE_SIZE_MAX to indicate an invalid address for type resource_size_t. Depending on the type either RESOURCE_SIZE_MAX or ULLONG_MAX is used to indicate an address error. Propagating an invalid address from a failed translation may cause userspace to think it has received a valid SPA, when in fact it is wrong. The CXL userspace API, using trace events, expects ULLONG_MAX to indicate a translation failure. If ULLONG_MAX is not returned immediately, subsequent calculations can transform that bad address into a different value (!ULLONG_MAX), and an invalid SPA may be returned to userspace. This can lead to incorrect diagnostics and erroneous corrective actions. [ dj: Added user impact statement from Alison. ] [ dj: Fixed checkpatch tab alignment issue. ] Reviewed-by: Dave Jiang Signed-off-by: Robert Richter Fixes: c3dd67681c70 ("cxl/region: Add inject and clear poison by region offset") Fixes: b78b9e7b7979 ("cxl/region: Refactor address translation funcs for testing") Reviewed-by: Alison Schofield Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20260107120544.410993-1-rrichter@amd.com Signed-off-by: Dave Jiang --- drivers/cxl/core/hdm.c | 2 +- drivers/cxl/core/region.c | 34 ++++++++++++++++++++------ tools/testing/cxl/test/cxl_translate.c | 26 ++++++++++++-------- 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index a470099a69f1..eb5a3a7640c6 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -530,7 +530,7 @@ resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled) resource_size_t cxl_dpa_resource_start(struct cxl_endpoint_decoder *cxled) { - resource_size_t base = -1; + resource_size_t base = RESOURCE_SIZE_MAX; lockdep_assert_held(&cxl_rwsem.dpa); if (cxled->dpa_res) diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index fc36a5413d3f..5bd1213737fa 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -3118,7 +3118,7 @@ u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent); struct cxl_region_params *p = &cxlr->params; struct cxl_endpoint_decoder *cxled = NULL; - u64 dpa_offset, hpa_offset, hpa; + u64 base, dpa_offset, hpa_offset, hpa; u16 eig = 0; u8 eiw = 0; int pos; @@ -3136,8 +3136,14 @@ u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, ways_to_eiw(p->interleave_ways, &eiw); granularity_to_eig(p->interleave_granularity, &eig); - dpa_offset = dpa - cxl_dpa_resource_start(cxled); + base = cxl_dpa_resource_start(cxled); + if (base == RESOURCE_SIZE_MAX) + return ULLONG_MAX; + + dpa_offset = dpa - base; hpa_offset = cxl_calculate_hpa_offset(dpa_offset, pos, eiw, eig); + if (hpa_offset == ULLONG_MAX) + return ULLONG_MAX; /* Apply the hpa_offset to the region base address */ hpa = hpa_offset + p->res->start + p->cache_size; @@ -3146,6 +3152,9 @@ u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, if (cxlrd->ops.hpa_to_spa) hpa = cxlrd->ops.hpa_to_spa(cxlrd, hpa); + if (hpa == ULLONG_MAX) + return ULLONG_MAX; + if (!cxl_resource_contains_addr(p->res, hpa)) { dev_dbg(&cxlr->dev, "Addr trans fail: hpa 0x%llx not in region\n", hpa); @@ -3170,7 +3179,8 @@ static int region_offset_to_dpa_result(struct cxl_region *cxlr, u64 offset, struct cxl_region_params *p = &cxlr->params; struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent); struct cxl_endpoint_decoder *cxled; - u64 hpa, hpa_offset, dpa_offset; + u64 hpa_offset = offset; + u64 dpa, dpa_offset; u16 eig = 0; u8 eiw = 0; int pos; @@ -3187,10 +3197,13 @@ static int region_offset_to_dpa_result(struct cxl_region *cxlr, u64 offset, * CXL HPA is assumed to equal SPA. */ if (cxlrd->ops.spa_to_hpa) { - hpa = cxlrd->ops.spa_to_hpa(cxlrd, p->res->start + offset); - hpa_offset = hpa - p->res->start; - } else { - hpa_offset = offset; + hpa_offset = cxlrd->ops.spa_to_hpa(cxlrd, p->res->start + offset); + if (hpa_offset == ULLONG_MAX) { + dev_dbg(&cxlr->dev, "HPA not found for %pr offset %#llx\n", + p->res, offset); + return -ENXIO; + } + hpa_offset -= p->res->start; } pos = cxl_calculate_position(hpa_offset, eiw, eig); @@ -3207,8 +3220,13 @@ static int region_offset_to_dpa_result(struct cxl_region *cxlr, u64 offset, cxled = p->targets[i]; if (cxled->pos != pos) continue; + + dpa = cxl_dpa_resource_start(cxled); + if (dpa != RESOURCE_SIZE_MAX) + dpa += dpa_offset; + result->cxlmd = cxled_to_memdev(cxled); - result->dpa = cxl_dpa_resource_start(cxled) + dpa_offset; + result->dpa = dpa; return 0; } diff --git a/tools/testing/cxl/test/cxl_translate.c b/tools/testing/cxl/test/cxl_translate.c index 2200ae21795c..16328b2112b2 100644 --- a/tools/testing/cxl/test/cxl_translate.c +++ b/tools/testing/cxl/test/cxl_translate.c @@ -68,6 +68,8 @@ static u64 to_hpa(u64 dpa_offset, int pos, u8 r_eiw, u16 r_eig, u8 hb_ways, /* Calculate base HPA offset from DPA and position */ hpa_offset = cxl_calculate_hpa_offset(dpa_offset, pos, r_eiw, r_eig); + if (hpa_offset == ULLONG_MAX) + return ULLONG_MAX; if (math == XOR_MATH) { cximsd->nr_maps = hbiw_to_nr_maps[hb_ways]; @@ -258,19 +260,23 @@ static int test_random_params(void) pos = get_random_u32() % ways; dpa = get_random_u64() >> 12; + reverse_dpa = ULLONG_MAX; + reverse_pos = -1; + hpa = cxl_calculate_hpa_offset(dpa, pos, eiw, eig); - reverse_dpa = cxl_calculate_dpa_offset(hpa, eiw, eig); - reverse_pos = cxl_calculate_position(hpa, eiw, eig); + if (hpa != ULLONG_MAX) { + reverse_dpa = cxl_calculate_dpa_offset(hpa, eiw, eig); + reverse_pos = cxl_calculate_position(hpa, eiw, eig); + if (reverse_dpa == dpa && reverse_pos == pos) + continue; + } - if (reverse_dpa != dpa || reverse_pos != pos) { - pr_err("test random iter %d FAIL hpa=%llu, dpa=%llu reverse_dpa=%llu, pos=%d reverse_pos=%d eiw=%u eig=%u\n", - i, hpa, dpa, reverse_dpa, pos, reverse_pos, eiw, - eig); + pr_err("test random iter %d FAIL hpa=%llu, dpa=%llu reverse_dpa=%llu, pos=%d reverse_pos=%d eiw=%u eig=%u\n", + i, hpa, dpa, reverse_dpa, pos, reverse_pos, eiw, eig); - if (failures++ > 10) { - pr_err("test random too many failures, stop\n"); - break; - } + if (failures++ > 10) { + pr_err("test random too many failures, stop\n"); + break; } } pr_info("..... test random: PASS %d FAIL %d\n", i - failures, failures); From 7517e899e1b87b4c22a92c7e40d8733c48e4ec3c Mon Sep 17 00:00:00 2001 From: Xiaochen Shen Date: Tue, 9 Dec 2025 14:26:50 +0800 Subject: [PATCH 207/443] x86/resctrl: Fix memory bandwidth counter width for Hygon The memory bandwidth calculation relies on reading the hardware counter and measuring the delta between samples. To ensure accurate measurement, the software reads the counter frequently enough to prevent it from rolling over twice between reads. The default Memory Bandwidth Monitoring (MBM) counter width is 24 bits. Hygon CPUs provide a 32-bit width counter, but they do not support the MBM capability CPUID leaf (0xF.[ECX=1]:EAX) to report the width offset (from 24 bits). Consequently, the kernel falls back to the 24-bit default counter width, which causes incorrect overflow handling on Hygon CPUs. Fix this by explicitly setting the counter width offset to 8 bits (resulting in a 32-bit total counter width) for Hygon CPUs. Fixes: d8df126349da ("x86/cpu/hygon: Add missing resctrl_cpu_detect() in bsp_init helper") Signed-off-by: Xiaochen Shen Signed-off-by: Borislav Petkov (AMD) Reviewed-by: Tony Luck Reviewed-by: Reinette Chatre Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251209062650.1536952-3-shenxiaochen@open-hieco.net --- arch/x86/kernel/cpu/resctrl/core.c | 15 +++++++++++++-- arch/x86/kernel/cpu/resctrl/internal.h | 3 +++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index 10de1594d328..6ebff44a3f75 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -1021,8 +1021,19 @@ void resctrl_cpu_detect(struct cpuinfo_x86 *c) c->x86_cache_occ_scale = ebx; c->x86_cache_mbm_width_offset = eax & 0xff; - if (c->x86_vendor == X86_VENDOR_AMD && !c->x86_cache_mbm_width_offset) - c->x86_cache_mbm_width_offset = MBM_CNTR_WIDTH_OFFSET_AMD; + if (!c->x86_cache_mbm_width_offset) { + switch (c->x86_vendor) { + case X86_VENDOR_AMD: + c->x86_cache_mbm_width_offset = MBM_CNTR_WIDTH_OFFSET_AMD; + break; + case X86_VENDOR_HYGON: + c->x86_cache_mbm_width_offset = MBM_CNTR_WIDTH_OFFSET_HYGON; + break; + default: + /* Leave c->x86_cache_mbm_width_offset as 0 */ + break; + } + } } } diff --git a/arch/x86/kernel/cpu/resctrl/internal.h b/arch/x86/kernel/cpu/resctrl/internal.h index 4a916c84a322..79c18657ede0 100644 --- a/arch/x86/kernel/cpu/resctrl/internal.h +++ b/arch/x86/kernel/cpu/resctrl/internal.h @@ -14,6 +14,9 @@ #define MBM_CNTR_WIDTH_OFFSET_AMD 20 +/* Hygon MBM counter width as an offset from MBM_CNTR_WIDTH_BASE */ +#define MBM_CNTR_WIDTH_OFFSET_HYGON 8 + #define RMID_VAL_ERROR BIT_ULL(63) #define RMID_VAL_UNAVAIL BIT_ULL(62) From e383f0961422f983451ac4dd6aed1a3d3311f2be Mon Sep 17 00:00:00 2001 From: Tommaso Merciai Date: Thu, 18 Dec 2025 16:10:21 +0100 Subject: [PATCH 208/443] i2c: riic: Move suspend handling to NOIRQ phase Commit 53326135d0e0 ("i2c: riic: Add suspend/resume support") added suspend support for the Renesas I2C driver and following this change on RZ/G3E the following WARNING is seen on entering suspend ... [ 134.275704] Freezing remaining freezable tasks completed (elapsed 0.001 seconds) [ 134.285536] ------------[ cut here ]------------ [ 134.290298] i2c i2c-2: Transfer while suspended [ 134.295174] WARNING: drivers/i2c/i2c-core.h:56 at __i2c_smbus_xfer+0x1e4/0x214, CPU#0: systemd-sleep/388 [ 134.365507] Tainted: [W]=WARN [ 134.368485] Hardware name: Renesas SMARC EVK version 2 based on r9a09g047e57 (DT) [ 134.375961] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 134.382935] pc : __i2c_smbus_xfer+0x1e4/0x214 [ 134.387329] lr : __i2c_smbus_xfer+0x1e4/0x214 [ 134.391717] sp : ffff800083f23860 [ 134.395040] x29: ffff800083f23860 x28: 0000000000000000 x27: ffff800082ed5d60 [ 134.402226] x26: 0000001f4395fd74 x25: 0000000000000007 x24: 0000000000000001 [ 134.409408] x23: 0000000000000000 x22: 000000000000006f x21: ffff800083f23936 [ 134.416589] x20: ffff0000c090e140 x19: ffff0000c090e0d0 x18: 0000000000000006 [ 134.423771] x17: 6f63657320313030 x16: 2e30206465737061 x15: ffff800083f23280 [ 134.430953] x14: 0000000000000000 x13: ffff800082b16ce8 x12: 0000000000000f09 [ 134.438134] x11: 0000000000000503 x10: ffff800082b6ece8 x9 : ffff800082b16ce8 [ 134.445315] x8 : 00000000ffffefff x7 : ffff800082b6ece8 x6 : 80000000fffff000 [ 134.452495] x5 : 0000000000000504 x4 : 0000000000000000 x3 : 0000000000000000 [ 134.459672] x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff0000c9ee9e80 [ 134.466851] Call trace: [ 134.469311] __i2c_smbus_xfer+0x1e4/0x214 (P) [ 134.473715] i2c_smbus_xfer+0xbc/0x120 [ 134.477507] i2c_smbus_read_byte_data+0x4c/0x84 [ 134.482077] isl1208_i2c_read_time+0x44/0x178 [rtc_isl1208] [ 134.487703] isl1208_rtc_read_time+0x14/0x20 [rtc_isl1208] [ 134.493226] __rtc_read_time+0x44/0x88 [ 134.497012] rtc_read_time+0x3c/0x68 [ 134.500622] rtc_suspend+0x9c/0x170 The warning is triggered because I2C transfers can still be attempted while the controller is already suspended, due to inappropriate ordering of the system sleep callbacks. If the controller is autosuspended, there is no way to wake it up once runtime PM disabled (in suspend_late()). During system resume, the I2C controller will be available only after runtime PM is re-enabled (in resume_early()). However, this may be too late for some devices. Wake up the controller in the suspend() callback while runtime PM is still enabled. The I2C controller will remain available until the suspend_noirq() callback (pm_runtime_force_suspend()) is called. During resume, the I2C controller can be restored by the resume_noirq() callback (pm_runtime_force_resume()). Finally, the resume() callback re-enables autosuspend. As a result, the I2C controller can remain available until the system enters suspend_noirq() and from resume_noirq(). Cc: stable@vger.kernel.org Fixes: 53326135d0e0 ("i2c: riic: Add suspend/resume support") Signed-off-by: Tommaso Merciai Reviewed-by: Biju Das Tested-by: Biju Das Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-riic.c | 46 +++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 3e8f126cb7f7..9e3595b3623e 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -670,12 +670,39 @@ static const struct riic_of_data riic_rz_t2h_info = { static int riic_i2c_suspend(struct device *dev) { - struct riic_dev *riic = dev_get_drvdata(dev); - int ret; + /* + * Some I2C devices may need the I2C controller to remain active + * during resume_noirq() or suspend_noirq(). If the controller is + * autosuspended, there is no way to wake it up once runtime PM is + * disabled (in suspend_late()). + * + * During system resume, the I2C controller will be available only + * after runtime PM is re-enabled (in resume_early()). However, this + * may be too late for some devices. + * + * Wake up the controller in the suspend() callback while runtime PM + * is still enabled. The I2C controller will remain available until + * the suspend_noirq() callback (pm_runtime_force_suspend()) is + * called. During resume, the I2C controller can be restored by the + * resume_noirq() callback (pm_runtime_force_resume()). + * + * Finally, the resume() callback re-enables autosuspend, ensuring + * the I2C controller remains available until the system enters + * suspend_noirq() and from resume_noirq(). + */ + return pm_runtime_resume_and_get(dev); +} - ret = pm_runtime_resume_and_get(dev); - if (ret) - return ret; +static int riic_i2c_resume(struct device *dev) +{ + pm_runtime_put_autosuspend(dev); + + return 0; +} + +static int riic_i2c_suspend_noirq(struct device *dev) +{ + struct riic_dev *riic = dev_get_drvdata(dev); i2c_mark_adapter_suspended(&riic->adapter); @@ -683,12 +710,12 @@ static int riic_i2c_suspend(struct device *dev) riic_clear_set_bit(riic, ICCR1_ICE, 0, RIIC_ICCR1); pm_runtime_mark_last_busy(dev); - pm_runtime_put_sync(dev); + pm_runtime_force_suspend(dev); return reset_control_assert(riic->rstc); } -static int riic_i2c_resume(struct device *dev) +static int riic_i2c_resume_noirq(struct device *dev) { struct riic_dev *riic = dev_get_drvdata(dev); int ret; @@ -697,6 +724,10 @@ static int riic_i2c_resume(struct device *dev) if (ret) return ret; + ret = pm_runtime_force_resume(dev); + if (ret) + return ret; + ret = riic_init_hw(riic); if (ret) { /* @@ -714,6 +745,7 @@ static int riic_i2c_resume(struct device *dev) } static const struct dev_pm_ops riic_i2c_pm_ops = { + NOIRQ_SYSTEM_SLEEP_PM_OPS(riic_i2c_suspend_noirq, riic_i2c_resume_noirq) SYSTEM_SLEEP_PM_OPS(riic_i2c_suspend, riic_i2c_resume) }; From 8439016c3b8b5ab687c2420317b1691585106611 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 20 Nov 2025 12:20:41 -0800 Subject: [PATCH 209/443] ice: initialize ring_stats->syncp The u64_stats_sync structure is empty on 64-bit systems. However, on 32-bit systems it contains a seqcount_t which needs to be initialized. While the memory is zero-initialized, a lack of u64_stats_init means that lockdep won't get initialized properly. Fix this by adding u64_stats_init() calls to the rings just after allocation. Fixes: 2b245cb29421 ("ice: Implement transmit and NAPI support") Reviewed-by: Aleksandr Loktionov Signed-off-by: Jacob Keller Reviewed-by: Simon Horman Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_lib.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 15621707fbf8..9ebbe1bff214 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -398,6 +398,8 @@ static int ice_vsi_alloc_ring_stats(struct ice_vsi *vsi) if (!ring_stats) goto err_out; + u64_stats_init(&ring_stats->syncp); + WRITE_ONCE(tx_ring_stats[i], ring_stats); } @@ -417,6 +419,8 @@ static int ice_vsi_alloc_ring_stats(struct ice_vsi *vsi) if (!ring_stats) goto err_out; + u64_stats_init(&ring_stats->syncp); + WRITE_ONCE(rx_ring_stats[i], ring_stats); } From a9d45c22ed120cdd15ff56d0a6e4700c46451901 Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Thu, 20 Nov 2025 09:58:26 -0800 Subject: [PATCH 210/443] ice: Avoid detrimental cleanup for bond during interface stop When the user issues an administrative down to an interface that is the primary for an aggregate bond, the prune lists are being purged. This breaks communication to the secondary interface, which shares a prune list on the main switch block while bonded together. For the primary interface of an aggregate, avoid deleting these prune lists during stop, and since they are hardcoded to specific values for the default vlan and QinQ vlans, the attempt to re-add them during the up phase will quietly fail without any additional problem. Fixes: 1e0f9881ef79 ("ice: Flesh out implementation of support for SRIOV on bonded interface") Reviewed-by: Jacob Keller Reviewed-by: Marcin Szycik Signed-off-by: Dave Ertman Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_lib.c | 25 ++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 9ebbe1bff214..98010354db15 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -3809,22 +3809,31 @@ int ice_vsi_add_vlan_zero(struct ice_vsi *vsi) int ice_vsi_del_vlan_zero(struct ice_vsi *vsi) { struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi); + struct ice_pf *pf = vsi->back; struct ice_vlan vlan; int err; - vlan = ICE_VLAN(0, 0, 0); - err = vlan_ops->del_vlan(vsi, &vlan); - if (err && err != -EEXIST) - return err; + if (pf->lag && pf->lag->primary) { + dev_dbg(ice_pf_to_dev(pf), "Interface is primary in aggregate - not deleting prune list\n"); + } else { + vlan = ICE_VLAN(0, 0, 0); + err = vlan_ops->del_vlan(vsi, &vlan); + if (err && err != -EEXIST) + return err; + } /* in SVM both VLAN 0 filters are identical */ if (!ice_is_dvm_ena(&vsi->back->hw)) return 0; - vlan = ICE_VLAN(ETH_P_8021Q, 0, 0); - err = vlan_ops->del_vlan(vsi, &vlan); - if (err && err != -EEXIST) - return err; + if (pf->lag && pf->lag->primary) { + dev_dbg(ice_pf_to_dev(pf), "Interface is primary in aggregate - not deleting QinQ prune list\n"); + } else { + vlan = ICE_VLAN(ETH_P_8021Q, 0, 0); + err = vlan_ops->del_vlan(vsi, &vlan); + if (err && err != -EEXIST) + return err; + } /* when deleting the last VLAN filter, make sure to disable the VLAN * promisc mode so the filter isn't left by accident From 01139a2ce532d77379e1593230127caa261a8036 Mon Sep 17 00:00:00 2001 From: Ding Hui Date: Sat, 6 Dec 2025 21:46:09 +0800 Subject: [PATCH 211/443] ice: Fix incorrect timeout ice_release_res() The commit 5f6df173f92e ("ice: implement and use rd32_poll_timeout for ice_sq_done timeout") converted ICE_CTL_Q_SQ_CMD_TIMEOUT from jiffies to microseconds. But the ice_release_res() function was missed, and its logic still treats ICE_CTL_Q_SQ_CMD_TIMEOUT as a jiffies value. So correct the issue by usecs_to_jiffies(). Found by inspection of the DDP downloading process. Compile and modprobe tested only. Fixes: 5f6df173f92e ("ice: implement and use rd32_poll_timeout for ice_sq_done timeout") Signed-off-by: Ding Hui Reviewed-by: Simon Horman Reviewed-by: Aleksandr Loktionov Reviewed-by: Jacob Keller Reviewed-by: Paul Menzel Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 046bc9c65c51..785bf5cc1b25 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -2251,7 +2251,7 @@ void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res) /* there are some rare cases when trying to release the resource * results in an admin queue timeout, so handle them correctly */ - timeout = jiffies + 10 * ICE_CTL_Q_SQ_CMD_TIMEOUT; + timeout = jiffies + 10 * usecs_to_jiffies(ICE_CTL_Q_SQ_CMD_TIMEOUT); do { status = ice_aq_release_res(hw, res, 0, NULL); if (status != -EIO) From 41a9a6826f20a524242a6c984845c4855f629841 Mon Sep 17 00:00:00 2001 From: Kurt Kanzenbach Date: Thu, 20 Nov 2025 09:18:29 +0100 Subject: [PATCH 212/443] igc: Restore default Qbv schedule when changing channels The Multi-queue Priority (MQPRIO) and Earliest TxTime First (ETF) offloads utilize the Time Sensitive Networking (TSN) Tx mode. This mode is always coupled to IEEE 802.1Qbv time aware shaper (Qbv). Therefore, the driver sets a default Qbv schedule of all gates opened and a cycle time of 1s. This schedule is set during probe. However, the following sequence of events lead to Tx issues: - Boot a dual core system igc_probe(): igc_tsn_clear_schedule(): -> Default Schedule is set Note: At this point the driver has allocated two Tx/Rx queues, because there are only two CPUs. - ethtool -L enp3s0 combined 4 igc_ethtool_set_channels(): igc_reinit_queues() -> Default schedule is gone, per Tx ring start and end time are zero - tc qdisc replace dev enp3s0 handle 100 parent root mqprio \ num_tc 4 map 3 3 2 2 0 1 1 1 3 3 3 3 3 3 3 3 \ queues 1@0 1@1 1@2 1@3 hw 1 igc_tsn_offload_apply(): igc_tsn_enable_offload(): -> Writes zeros to IGC_STQT(i) and IGC_ENDQT(i), causing Tx to stall/fail Therefore, restore the default Qbv schedule after changing the number of channels. Furthermore, add a restriction to not allow queue reconfiguration when TSN/Qbv is enabled, because it may lead to inconsistent states. Fixes: c814a2d2d48f ("igc: Use default cycle 'start' and 'end' values for queues") Signed-off-by: Kurt Kanzenbach Reviewed-by: Aleksandr Loktionov Tested-by: Avigail Dahan Acked-by: Vinicius Costa Gomes Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igc/igc_ethtool.c | 4 ++-- drivers/net/ethernet/intel/igc/igc_main.c | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index e94c1922b97a..3172cdbca9cc 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -1565,8 +1565,8 @@ static int igc_ethtool_set_channels(struct net_device *netdev, if (ch->other_count != NON_Q_VECTORS) return -EINVAL; - /* Do not allow channel reconfiguration when mqprio is enabled */ - if (adapter->strict_priority_enable) + /* Do not allow channel reconfiguration when any TSN qdisc is enabled */ + if (adapter->flags & IGC_FLAG_TSN_ANY_ENABLED) return -EINVAL; /* Verify the number of channels doesn't exceed hw limits */ diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 7aafa60ba0c8..89a321a344d2 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -7759,6 +7759,11 @@ int igc_reinit_queues(struct igc_adapter *adapter) if (netif_running(netdev)) err = igc_open(netdev); + if (!err) { + /* Restore default IEEE 802.1Qbv schedule after queue reinit */ + igc_tsn_clear_schedule(adapter); + } + return err; } From 6990dc392a9ab10e52af37e0bee8c7b753756dc4 Mon Sep 17 00:00:00 2001 From: Chwee-Lin Choong Date: Fri, 28 Nov 2025 18:53:04 +0800 Subject: [PATCH 213/443] igc: fix race condition in TX timestamp read for register 0 The current HW bug workaround checks the TXTT_0 ready bit first, then reads TXSTMPL_0 twice (before and after reading TXSTMPH_0) to detect whether a new timestamp was captured by timestamp register 0 during the workaround. This sequence has a race: if a new timestamp is captured after checking the TXTT_0 bit but before the first TXSTMPL_0 read, the detection fails because both the "old" and "new" values come from the same timestamp. Fix by reading TXSTMPL_0 first to establish a baseline, then checking the TXTT_0 bit. This ensures any timestamp captured during the race window will be detected. Old sequence: 1. Check TXTT_0 ready bit 2. Read TXSTMPL_0 (baseline) 3. Read TXSTMPH_0 (interrupt workaround) 4. Read TXSTMPL_0 (detect changes vs baseline) New sequence: 1. Read TXSTMPL_0 (baseline) 2. Check TXTT_0 ready bit 3. Read TXSTMPH_0 (interrupt workaround) 4. Read TXSTMPL_0 (detect changes vs baseline) Fixes: c789ad7cbebc ("igc: Work around HW bug causing missing timestamps") Suggested-by: Avi Shalev Reviewed-by: Aleksandr Loktionov Co-developed-by: Song Yoong Siang Signed-off-by: Song Yoong Siang Signed-off-by: Chwee-Lin Choong Tested-by: Avigail Dahan Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igc/igc_ptp.c | 43 ++++++++++++++---------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c index b7b46d863bee..7aae83c108fd 100644 --- a/drivers/net/ethernet/intel/igc/igc_ptp.c +++ b/drivers/net/ethernet/intel/igc/igc_ptp.c @@ -774,36 +774,43 @@ static void igc_ptp_tx_reg_to_stamp(struct igc_adapter *adapter, static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter) { struct igc_hw *hw = &adapter->hw; + u32 txstmpl_old; u64 regval; u32 mask; int i; + /* Establish baseline of TXSTMPL_0 before checking TXTT_0. + * This baseline is used to detect if a new timestamp arrives in + * register 0 during the hardware bug workaround below. + */ + txstmpl_old = rd32(IGC_TXSTMPL); + mask = rd32(IGC_TSYNCTXCTL) & IGC_TSYNCTXCTL_TXTT_ANY; if (mask & IGC_TSYNCTXCTL_TXTT_0) { regval = rd32(IGC_TXSTMPL); regval |= (u64)rd32(IGC_TXSTMPH) << 32; } else { - /* There's a bug in the hardware that could cause - * missing interrupts for TX timestamping. The issue - * is that for new interrupts to be triggered, the - * IGC_TXSTMPH_0 register must be read. + /* TXTT_0 not set - register 0 has no new timestamp initially. * - * To avoid discarding a valid timestamp that just - * happened at the "wrong" time, we need to confirm - * that there was no timestamp captured, we do that by - * assuming that no two timestamps in sequence have - * the same nanosecond value. + * Hardware bug: Future timestamp interrupts won't fire unless + * TXSTMPH_0 is read, even if the timestamp was captured in + * registers 1-3. * - * So, we read the "low" register, read the "high" - * register (to latch a new timestamp) and read the - * "low" register again, if "old" and "new" versions - * of the "low" register are different, a valid - * timestamp was captured, we can read the "high" - * register again. + * Workaround: Read TXSTMPH_0 here to enable future interrupts. + * However, this read clears TXTT_0. If a timestamp arrives in + * register 0 after checking TXTT_0 but before this read, it + * would be lost. + * + * To detect this race: We saved a baseline read of TXSTMPL_0 + * before TXTT_0 check. After performing the workaround read of + * TXSTMPH_0, we read TXSTMPL_0 again. Since consecutive + * timestamps never share the same nanosecond value, a change + * between the baseline and new TXSTMPL_0 indicates a timestamp + * arrived during the race window. If so, read the complete + * timestamp. */ - u32 txstmpl_old, txstmpl_new; + u32 txstmpl_new; - txstmpl_old = rd32(IGC_TXSTMPL); rd32(IGC_TXSTMPH); txstmpl_new = rd32(IGC_TXSTMPL); @@ -818,7 +825,7 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter) done: /* Now that the problematic first register was handled, we can - * use retrieve the timestamps from the other registers + * retrieve the timestamps from the other registers * (starting from '1') with less complications. */ for (i = 1; i < IGC_MAX_TX_TSTAMP_REGS; i++) { From 8ad1b6c1e63d25f5465b7a8aa403bdcee84b86f9 Mon Sep 17 00:00:00 2001 From: Chwee-Lin Choong Date: Thu, 4 Dec 2025 20:21:50 +0800 Subject: [PATCH 214/443] igc: Reduce TSN TX packet buffer from 7KB to 5KB per queue The previous 7 KB per queue caused TX unit hangs under heavy timestamping load. Reducing to 5 KB avoids these hangs and matches the TSN recommendation in I225/I226 SW User Manual Section 7.5.4. The 8 KB "freed" by this change is currently unused. This reduction is not expected to impact throughput, as the i226 is PCIe-limited for small TSN packets rather than TX-buffer-limited. Fixes: 0d58cdc902da ("igc: optimize TX packet buffer utilization for TSN mode") Reported-by: Zdenek Bouska Closes: https://lore.kernel.org/netdev/AS1PR10MB5675DBFE7CE5F2A9336ABFA4EBEAA@AS1PR10MB5675.EURPRD10.PROD.OUTLOOK.COM/ Reviewed-by: Paul Menzel Reviewed-by: Simon Horman Reviewed-by: Aleksandr Loktionov Signed-off-by: Chwee-Lin Choong Tested-by: Avigail Dahan Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/igc/igc_defines.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index 498ba1522ca4..9482ab11f050 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -443,9 +443,10 @@ #define IGC_TXPBSIZE_DEFAULT ( \ IGC_TXPB0SIZE(20) | IGC_TXPB1SIZE(0) | IGC_TXPB2SIZE(0) | \ IGC_TXPB3SIZE(0) | IGC_OS2BMCPBSIZE(4)) +/* TSN value following I225/I226 SW User Manual Section 7.5.4 */ #define IGC_TXPBSIZE_TSN ( \ - IGC_TXPB0SIZE(7) | IGC_TXPB1SIZE(7) | IGC_TXPB2SIZE(7) | \ - IGC_TXPB3SIZE(7) | IGC_OS2BMCPBSIZE(4)) + IGC_TXPB0SIZE(5) | IGC_TXPB1SIZE(5) | IGC_TXPB2SIZE(5) | \ + IGC_TXPB3SIZE(5) | IGC_OS2BMCPBSIZE(4)) #define IGC_DTXMXPKTSZ_TSN 0x19 /* 1600 bytes of max TX DMA packet size */ #define IGC_DTXMXPKTSZ_DEFAULT 0x98 /* 9728-byte Jumbo frames */ From 84164acba33158208c2b0e8e5607bdd43edc0dd4 Mon Sep 17 00:00:00 2001 From: Shin'ichiro Kawasaki Date: Sun, 21 Dec 2025 16:37:14 +0900 Subject: [PATCH 215/443] nvmet: do not copy beyond sybsysnqn string length Commit edd17206e363 ("nvmet: remove redundant subsysnqn field from ctrl") replaced ctrl->subsysnqn with ctrl->subsys->subsysnqn. This change works as expected because both point to strings with the same data. However, their memory allocation lengths differ. ctrl->subsysnqn had the fixed size defined as NVMF_NQN_FILED_LEN, while ctrl->subsys->subsysnqn has variable length determined by kstrndup(). Due to this difference, KASAN slab-out-of-bounds occurs at memcpy() in nvmet_passthru_override_id_ctrl() after the commit. The failure can be recreated by running the blktests test case nvme/033. To prevent such failures, replace memcpy() with strscpy(), which copies only the string length and avoids overruns. Fixes: edd17206e363 ("nvmet: remove redundant subsysnqn field from ctrl") Signed-off-by: Shin'ichiro Kawasaki Reviewed-by: Christoph Hellwig Reviewed-by: Sagi Grimberg Reviewed-by: Chaitanya Kulkarni Signed-off-by: Keith Busch --- drivers/nvme/target/passthru.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c index 96648ec2fadb..67c423a8b052 100644 --- a/drivers/nvme/target/passthru.c +++ b/drivers/nvme/target/passthru.c @@ -150,7 +150,7 @@ static u16 nvmet_passthru_override_id_ctrl(struct nvmet_req *req) * code path with duplicate ctrl subsysnqn. In order to prevent that we * mask the passthru-ctrl subsysnqn with the target ctrl subsysnqn. */ - memcpy(id->subnqn, ctrl->subsys->subsysnqn, sizeof(id->subnqn)); + strscpy(id->subnqn, ctrl->subsys->subsysnqn, sizeof(id->subnqn)); /* use fabric id-ctrl values */ id->ioccsz = cpu_to_le32((sizeof(struct nvme_command) + From 7edf6f7ef5345e1b4202912ca98aaa7c73e1e82c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 13 Jan 2026 14:36:54 +0100 Subject: [PATCH 216/443] ACPI: PM: s2idle: Add module parameter for LPS0 constraints checking Commit 32ece31db4df ("ACPI: PM: s2idle: Only retrieve constraints when needed") attempted to avoid useless evaluation of LPS0 _DSM Function 1 in lps0_device_attach() because pm_debug_messages_on might never be set (and that is the case on production systems most of the time), but it turns out that LPS0 _DSM Function 1 is generally problematic on some platforms and causes suspend issues to occur when pm_debug_messages_on is set now. In Linux, LPS0 _DSM Function 1 is only useful for diagnostics and only in the cases when the system does not reach the deepest platform idle state during suspend-to-idle for some reason. If such diagnostics is not necessary, evaluating it is a loss of time, so using it along with the other pm_debug_messages_on diagnostics is questionable because the latter is expected to be suitable for collecting debug information even during production use of system suspend. For this reason, add a module parameter called check_lps0_constraints to control whether or not the list of LPS0 constraints will be checked in acpi_s2idle_prepare_late_lps0() and so whether or not to evaluate LPS0 _DSM Function 1 (once) in acpi_s2idle_begin_lps0(). Fixes: 32ece31db4df ("ACPI: PM: s2idle: Only retrieve constraints when needed") Signed-off-by: Rafael J. Wysocki Reviewed-by: Mario Limonciello (AMD) Link: https://patch.msgid.link/2827214.mvXUDI8C0e@rafael.j.wysocki --- drivers/acpi/x86/s2idle.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c index 2a9edb53d5d4..cc3c83e4cc23 100644 --- a/drivers/acpi/x86/s2idle.c +++ b/drivers/acpi/x86/s2idle.c @@ -28,6 +28,10 @@ static bool sleep_no_lps0 __read_mostly; module_param(sleep_no_lps0, bool, 0644); MODULE_PARM_DESC(sleep_no_lps0, "Do not use the special LPS0 device interface"); +static bool check_lps0_constraints __read_mostly; +module_param(check_lps0_constraints, bool, 0644); +MODULE_PARM_DESC(check_lps0_constraints, "Check LPS0 device constraints"); + static const struct acpi_device_id lps0_device_ids[] = { {"PNP0D80", }, {"", }, @@ -515,7 +519,7 @@ static struct acpi_scan_handler lps0_handler = { static int acpi_s2idle_begin_lps0(void) { - if (lps0_device_handle && !sleep_no_lps0 && pm_debug_messages_on && + if (lps0_device_handle && !sleep_no_lps0 && check_lps0_constraints && !lpi_constraints_table) { if (acpi_s2idle_vendor_amd()) lpi_device_get_constraints_amd(); @@ -540,7 +544,7 @@ static int acpi_s2idle_prepare_late_lps0(void) if (!lps0_device_handle || sleep_no_lps0) return 0; - if (pm_debug_messages_on) + if (check_lps0_constraints) lpi_check_constraints(); /* Screen off */ From 9e9bc6be0fa0b6b6b73f4f831f3b77716d0a8d9e Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Fri, 19 Dec 2025 16:52:02 -0500 Subject: [PATCH 217/443] drm/nouveau/disp/nv50-: Set lock_core in curs507a_prepare For a while, I've been seeing a strange issue where some (usually not all) of the display DMA channels will suddenly hang, particularly when there is a visible cursor on the screen that is being frequently updated, and especially when said cursor happens to go between two screens. While this brings back lovely memories of fixing Intel Skylake bugs, I would quite like to fix it :). It turns out the problem that's happening here is that we're managing to reach nv50_head_flush_set() in our atomic commit path without actually holding nv50_disp->mutex. This means that cursor updates happening in parallel (along with any other atomic updates that need to use the core channel) will race with eachother, which eventually causes us to corrupt the pushbuffer - leading to a plethora of various GSP errors, usually: nouveau 0000:c1:00.0: gsp: Xid:56 CMDre 00000000 00000218 00102680 00000004 00800003 nouveau 0000:c1:00.0: gsp: Xid:56 CMDre 00000000 0000021c 00040509 00000004 00000001 nouveau 0000:c1:00.0: gsp: Xid:56 CMDre 00000000 00000000 00000000 00000001 00000001 The reason this is happening is because generally we check whether we need to set nv50_atom->lock_core at the end of nv50_head_atomic_check(). However, curs507a_prepare is called from the fb_prepare callback, which happens after the atomic check phase. As a result, this can lead to commits that both touch the core channel but also don't grab nv50_disp->mutex. So, fix this by making sure that we set nv50_atom->lock_core in cus507a_prepare(). Reviewed-by: Dave Airlie Signed-off-by: Lyude Paul Fixes: 1590700d94ac ("drm/nouveau/kms/nv50-: split each resource type into their own source files") Cc: # v4.18+ Link: https://patch.msgid.link/20251219215344.170852-2-lyude@redhat.com --- drivers/gpu/drm/nouveau/dispnv50/curs507a.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/dispnv50/curs507a.c b/drivers/gpu/drm/nouveau/dispnv50/curs507a.c index a95ee5dcc2e3..1a889139cb05 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/curs507a.c +++ b/drivers/gpu/drm/nouveau/dispnv50/curs507a.c @@ -84,6 +84,7 @@ curs507a_prepare(struct nv50_wndw *wndw, struct nv50_head_atom *asyh, asyh->curs.handle = handle; asyh->curs.offset = offset; asyh->set.curs = asyh->curs.visible; + nv50_atom(asyh->state.state)->lock_core = true; } } From 456c4f5ff0c886fd49daaa4dec13160df872bbc3 Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Fri, 19 Dec 2025 16:52:03 -0500 Subject: [PATCH 218/443] drm/nouveau/kms/nv50-: Assert we hold nv50_disp->lock in nv50_head_flush_* Now that we've had one bug that occurred in nouveau as the result of nv50_head_flush_* being called without the appropriate locks, let's add some lockdep asserts to make sure this doesn't happen in the future. Reviewed-by: Dave Airlie Signed-off-by: Lyude Paul Link: https://patch.msgid.link/20251219215344.170852-3-lyude@redhat.com --- drivers/gpu/drm/nouveau/dispnv50/head.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c index 3dd742b4f823..e32ed1db6c56 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head.c @@ -43,6 +43,9 @@ nv50_head_flush_clr(struct nv50_head *head, union nv50_head_atom_mask clr = { .mask = asyh->clr.mask & ~(flush ? 0 : asyh->set.mask), }; + + lockdep_assert_held(&head->disp->mutex); + if (clr.crc) nv50_crc_atomic_clr(head); if (clr.olut) head->func->olut_clr(head); if (clr.core) head->func->core_clr(head); @@ -65,6 +68,8 @@ nv50_head_flush_set_wndw(struct nv50_head *head, struct nv50_head_atom *asyh) void nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh) { + lockdep_assert_held(&head->disp->mutex); + if (asyh->set.view ) head->func->view (head, asyh); if (asyh->set.mode ) head->func->mode (head, asyh); if (asyh->set.core ) head->func->core_set(head, asyh); From b31ac41b59b6b6f1f6d426e2088e5c391bf89bf3 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 12 Jan 2026 15:46:36 +0000 Subject: [PATCH 219/443] dma/pool: Improve pool lookup If CONFIG_ZONE_DMA32 is enabled, but we have not allocated the corresponding atomic_pool_dma32, dma_guess_pool() may return the NULL value of that and fail a GFP_DMA32 allocation without trying to fall back to other pools which may exist. Furthermore, if no GFP_DMA pool exists, it is preferable to try GFP_DMA32 rather than immediately fall back to GFP_KERNEL with even less chance of success. Improve matters by encoding an explicit order of pool preference for each flag. Signed-off-by: Robin Murphy Tested-by: Vladimir Kondratiev Reviewed-by: Baoquan He Signed-off-by: Marek Szyprowski Link: https://lore.kernel.org/r/c846b1a2f43295cac926c7af2ce907f62baec518.1768230104.git.robin.murphy@arm.com --- kernel/dma/pool.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c index 26392badc36b..2645cfb5718b 100644 --- a/kernel/dma/pool.c +++ b/kernel/dma/pool.c @@ -224,10 +224,10 @@ postcore_initcall(dma_atomic_pool_init); static inline struct gen_pool *dma_guess_pool(struct gen_pool *prev, gfp_t gfp) { if (prev == NULL) { - if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp & GFP_DMA32)) - return atomic_pool_dma32; - if (atomic_pool_dma && (gfp & GFP_DMA)) - return atomic_pool_dma; + if (gfp & GFP_DMA) + return atomic_pool_dma ?: atomic_pool_dma32 ?: atomic_pool_kernel; + if (gfp & GFP_DMA32) + return atomic_pool_dma32 ?: atomic_pool_dma ?: atomic_pool_kernel; return atomic_pool_kernel; } if (prev == atomic_pool_kernel) From 6626734dd2b151753e134730e27d17e64784c345 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 12 Jan 2026 15:46:37 +0000 Subject: [PATCH 220/443] mm_zone: Generalise has_managed_dma() It would be useful to be able to check for potential DMA pages beyond just ZONE_DMA - generalise the existing has_managed_dma() function to allow checking other zones too. Signed-off-by: Robin Murphy Acked-by: David Hildenbrand (Red Hat) Acked-by: Mike Rapoport (Microsoft) Tested-by: Vladimir Kondratiev Reviewed-by: Baoquan He Signed-off-by: Marek Szyprowski Link: https://lore.kernel.org/r/bd002d2351074e57be1ca08f03f333debac658fb.1768230104.git.robin.murphy@arm.com --- include/linux/mmzone.h | 9 +++++---- mm/page_alloc.c | 8 ++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 75ef7c9f9307..fc5d6c88d2f0 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -1648,14 +1648,15 @@ static inline int is_highmem(const struct zone *zone) return is_highmem_idx(zone_idx(zone)); } -#ifdef CONFIG_ZONE_DMA -bool has_managed_dma(void); -#else +bool has_managed_zone(enum zone_type zone); static inline bool has_managed_dma(void) { +#ifdef CONFIG_ZONE_DMA + return has_managed_zone(ZONE_DMA); +#else return false; -} #endif +} #ifndef CONFIG_NUMA diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 822e05f1a964..36ccc85c5073 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -7418,20 +7418,16 @@ bool put_page_back_buddy(struct page *page) } #endif -#ifdef CONFIG_ZONE_DMA -bool has_managed_dma(void) +bool has_managed_zone(enum zone_type zone) { struct pglist_data *pgdat; for_each_online_pgdat(pgdat) { - struct zone *zone = &pgdat->node_zones[ZONE_DMA]; - - if (managed_zone(zone)) + if (managed_zone(&pgdat->node_zones[zone])) return true; } return false; } -#endif /* CONFIG_ZONE_DMA */ #ifdef CONFIG_UNACCEPTED_MEMORY From c6ccd098807483762ccd726e1498bac5a71d0005 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 12 Jan 2026 15:46:38 +0000 Subject: [PATCH 221/443] dma/pool: Avoid allocating redundant pools On smaller systems, e.g. embedded arm64, it is common for all memory to end up in ZONE_DMA32 or even ZONE_DMA. In such cases it is redundant to allocate a nominal pool for an empty higher zone that just ends up coming from a lower zone that should already have its own pool anyway. We already have logic to skip allocating a ZONE_DMA pool when that is empty, so generalise that to save memory in the case of other zones too. Signed-off-by: Robin Murphy Tested-by: Vladimir Kondratiev Reviewed-by: Baoquan He Signed-off-by: Marek Szyprowski Link: https://lore.kernel.org/r/8ab8d8a620dee0109f33f5cb63d6bfeed35aac37.1768230104.git.robin.murphy@arm.com --- kernel/dma/pool.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c index 2645cfb5718b..c5da29ad010c 100644 --- a/kernel/dma/pool.c +++ b/kernel/dma/pool.c @@ -184,6 +184,12 @@ static __init struct gen_pool *__dma_atomic_pool_init(size_t pool_size, return pool; } +#ifdef CONFIG_ZONE_DMA32 +#define has_managed_dma32 has_managed_zone(ZONE_DMA32) +#else +#define has_managed_dma32 false +#endif + static int __init dma_atomic_pool_init(void) { int ret = 0; @@ -199,17 +205,20 @@ static int __init dma_atomic_pool_init(void) } INIT_WORK(&atomic_pool_work, atomic_pool_work_fn); - atomic_pool_kernel = __dma_atomic_pool_init(atomic_pool_size, + /* All memory might be in the DMA zone(s) to begin with */ + if (has_managed_zone(ZONE_NORMAL)) { + atomic_pool_kernel = __dma_atomic_pool_init(atomic_pool_size, GFP_KERNEL); - if (!atomic_pool_kernel) - ret = -ENOMEM; + if (!atomic_pool_kernel) + ret = -ENOMEM; + } if (has_managed_dma()) { atomic_pool_dma = __dma_atomic_pool_init(atomic_pool_size, GFP_KERNEL | GFP_DMA); if (!atomic_pool_dma) ret = -ENOMEM; } - if (IS_ENABLED(CONFIG_ZONE_DMA32)) { + if (has_managed_dma32) { atomic_pool_dma32 = __dma_atomic_pool_init(atomic_pool_size, GFP_KERNEL | GFP_DMA32); if (!atomic_pool_dma32) @@ -228,7 +237,7 @@ static inline struct gen_pool *dma_guess_pool(struct gen_pool *prev, gfp_t gfp) return atomic_pool_dma ?: atomic_pool_dma32 ?: atomic_pool_kernel; if (gfp & GFP_DMA32) return atomic_pool_dma32 ?: atomic_pool_dma ?: atomic_pool_kernel; - return atomic_pool_kernel; + return atomic_pool_kernel ?: atomic_pool_dma32 ?: atomic_pool_dma; } if (prev == atomic_pool_kernel) return atomic_pool_dma32 ? atomic_pool_dma32 : atomic_pool_dma; From b91a565ed14fcf900b4d95e86882b4b763860986 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 8 Jan 2026 15:19:46 +0100 Subject: [PATCH 222/443] drm/sysfb: Remove duplicate declarations Commit 6046b49bafff ("drm/sysfb: Share helpers for integer validation") and commit e8c086880b2b ("drm/sysfb: Share helpers for screen_info validation") added duplicate function declarations. Remove the latter ones. Signed-off-by: Thomas Zimmermann Fixes: e8c086880b2b ("drm/sysfb: Share helpers for screen_info validation") Cc: Thomas Zimmermann Cc: Javier Martinez Canillas Cc: dri-devel@lists.freedesktop.org Cc: # v6.16+ Reviewed-by: Javier Martinez Canillas Link: https://patch.msgid.link/20260108145058.56943-7-tzimmermann@suse.de --- drivers/gpu/drm/sysfb/drm_sysfb_helper.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h index da670d7eeb2e..de96bfe7562c 100644 --- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h +++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h @@ -54,15 +54,6 @@ const struct drm_format_info *drm_sysfb_get_format_si(struct drm_device *dev, const struct screen_info *si); #endif -/* - * Input parsing - */ - -int drm_sysfb_get_validated_int(struct drm_device *dev, const char *name, - u64 value, u32 max); -int drm_sysfb_get_validated_int0(struct drm_device *dev, const char *name, - u64 value, u32 max); - /* * Display modes */ From d7f1b4bdc7108be1b178e1617b5f45c8918e88d7 Mon Sep 17 00:00:00 2001 From: Morduan Zang Date: Wed, 14 Jan 2026 13:30:33 +0800 Subject: [PATCH 223/443] efi/cper: Fix cper_bits_to_str buffer handling and return value The return value calculation was incorrect: `return len - buf_size;` Initially `len = buf_size`, then `len` decreases with each operation. This results in a negative return value on success. Fix by returning `buf_size - len` which correctly calculates the actual number of bytes written. Fixes: a976d790f494 ("efi/cper: Add a new helper function to print bitmasks") Signed-off-by: Morduan Zang Signed-off-by: Ard Biesheuvel --- drivers/firmware/efi/cper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index 0232bd040f61..bd99802cb0ca 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -162,7 +162,7 @@ int cper_bits_to_str(char *buf, int buf_size, unsigned long bits, len -= size; str += size; } - return len - buf_size; + return buf_size - len; } EXPORT_SYMBOL_GPL(cper_bits_to_str); From c0c50e3743e467ec4752c638e10e97f89c8644e2 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 29 Oct 2025 19:07:42 +0100 Subject: [PATCH 224/443] i2c: qcom-geni: make sure I2C hub controllers can't use SE DMA The I2C Hub controller is a simpler GENI I2C variant that doesn't support DMA at all, add a no_dma flag to make sure it nevers selects the SE DMA mode with mappable 32bytes long transfers. Fixes: cacd9643eca7 ("i2c: qcom-geni: add support for I2C Master Hub variant") Signed-off-by: Neil Armstrong Reviewed-by: Konrad Dybcio Reviewed-by: Mukesh Kumar Savaliya > Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qcom-geni.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 3a04016db2c3..ae609bdd2ec4 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -116,6 +116,7 @@ struct geni_i2c_dev { dma_addr_t dma_addr; struct dma_chan *tx_c; struct dma_chan *rx_c; + bool no_dma; bool gpi_mode; bool abort_done; bool is_tx_multi_desc_xfer; @@ -447,7 +448,7 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, size_t len = msg->len; struct i2c_msg *cur; - dma_buf = i2c_get_dma_safe_msg_buf(msg, 32); + dma_buf = gi2c->no_dma ? NULL : i2c_get_dma_safe_msg_buf(msg, 32); if (dma_buf) geni_se_select_mode(se, GENI_SE_DMA); else @@ -486,7 +487,7 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, size_t len = msg->len; struct i2c_msg *cur; - dma_buf = i2c_get_dma_safe_msg_buf(msg, 32); + dma_buf = gi2c->no_dma ? NULL : i2c_get_dma_safe_msg_buf(msg, 32); if (dma_buf) geni_se_select_mode(se, GENI_SE_DMA); else @@ -1080,10 +1081,12 @@ static int geni_i2c_probe(struct platform_device *pdev) goto err_resources; } - if (desc && desc->no_dma_support) + if (desc && desc->no_dma_support) { fifo_disable = false; - else + gi2c->no_dma = true; + } else { fifo_disable = readl_relaxed(gi2c->se.base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE; + } if (fifo_disable) { /* FIFO is disabled, so we can only use GPI DMA */ From f2a3f51365bf672dab4b58d1e8954926a9196b44 Mon Sep 17 00:00:00 2001 From: Carlos Song Date: Fri, 21 Nov 2025 11:00:30 +0800 Subject: [PATCH 225/443] i2c: imx-lpi2c: change to PIO mode in system-wide suspend/resume progress EDMA resumes early and suspends late in the system power transition sequence, while LPI2C enters the NOIRQ stage for both suspend and resume. This means LPI2C resources become available before EDMA is fully resumed. Once IRQs are enabled, a slave device may immediately trigger an LPI2C transfer. If the transfer length meets DMA requirements, the driver will attempt to use EDMA even though EDMA may still be unavailable. This timing gap can lead to transfer failures. To prevent this, force LPI2C to use PIO mode during system-wide suspend and resume transitions. This reduces dependency on EDMA and avoids using an unready DMA resource. Fixes: a09c8b3f9047 ("i2c: imx-lpi2c: add eDMA mode support for LPI2C") Signed-off-by: Carlos Song Reviewed-by: Frank Li Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx-lpi2c.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index 2a0962a0b441..d882126c1778 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -592,6 +592,13 @@ static bool is_use_dma(struct lpi2c_imx_struct *lpi2c_imx, struct i2c_msg *msg) if (!lpi2c_imx->can_use_dma) return false; + /* + * A system-wide suspend or resume transition is in progress. LPI2C should use PIO to + * transfer data to avoid issue caused by no ready DMA HW resource. + */ + if (pm_suspend_in_progress()) + return false; + /* * When the length of data is less than I2C_DMA_THRESHOLD, * cpu mode is used directly to avoid low performance. From 1ddbcb910a06f53fc2b14e1743c6ad4ccfd7107f Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 12 Jan 2026 14:07:56 +0000 Subject: [PATCH 226/443] soundwire: Add missing EXPORT for sdw_slave_type include/sdw_type.h provides the function is_sdw_slave() which requires sdw_slave_type. But sdw_slave_type was not exported. Signed-off-by: Richard Fitzgerald Acked-by: Vinod Koul Reviewed-by: Pierre-Louis Bossart Reviewed-by: Charles Keepax Link: https://patch.msgid.link/20260112140758.215799-2-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- drivers/soundwire/slave.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index 3d4d00188c26..d933cebad52b 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -23,6 +23,7 @@ const struct device_type sdw_slave_type = { .release = sdw_slave_release, .uevent = sdw_slave_uevent, }; +EXPORT_SYMBOL_GPL(sdw_slave_type); int sdw_slave_add(struct sdw_bus *bus, struct sdw_slave_id *id, struct fwnode_handle *fwnode) From 5b027c74f3ee8979193c50d31187edfa31acc0db Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 12 Jan 2026 14:07:57 +0000 Subject: [PATCH 227/443] ASoC: sdw_utils: Call init callbacks on the correct codec DAI asoc_sdw_rtd_init() needs to call the rtd_init() callbacks for each codec in a dailink. It was finding the codecs by looking for the matching DAI name in codec_info_list[] but this isn't correct, because the DAI name isn't guaranteed to be unique. Parts using the same codec driver (so the same DAI names) might require different machine driver setup. Instead, get the struct sdw_slave and extract the SoundWire part ID. Use this to lookup the entry in codec_info_list[]. This is the same identity info that was used to find the entry when the machine driver created the dailink. Signed-off-by: Richard Fitzgerald Fixes: e377c9477317 ("ASoC: intel/sdw_utils: move soundwire codec_info_list structure") Reviewed-by: Pierre-Louis Bossart Reviewed-by: Charles Keepax Link: https://patch.msgid.link/20260112140758.215799-3-rf@opensource.cirrus.com Signed-off-by: Mark Brown --- sound/soc/sdw_utils/soc_sdw_utils.c | 43 ++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index bf382aa07e92..ccf149f949e8 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -841,6 +841,19 @@ struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr) } EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_part, "SND_SOC_SDW_UTILS"); +static struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_sdw_id(const struct sdw_slave_id *id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) + if (id->part_id == codec_info_list[i].part_id && + (!codec_info_list[i].version_id || + id->sdw_version == codec_info_list[i].version_id)) + return &codec_info_list[i]; + + return NULL; +} + struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_acpi(const u8 *acpi_id) { int i; @@ -873,22 +886,46 @@ struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_dai(const char *dai_name, i } EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_dai, "SND_SOC_SDW_UTILS"); +static int asoc_sdw_find_codec_info_dai_index(const struct asoc_sdw_codec_info *codec_info, + const char *dai_name) +{ + int i; + + for (i = 0; i < codec_info->dai_num; i++) { + if (!strcmp(codec_info->dais[i].dai_name, dai_name)) + return i; + } + + return -ENOENT; +} + int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); struct asoc_sdw_codec_info *codec_info; struct snd_soc_dai *dai; + struct sdw_slave *sdw_peripheral; const char *spk_components=""; int dai_index; int ret; int i; for_each_rtd_codec_dais(rtd, i, dai) { - codec_info = asoc_sdw_find_codec_info_dai(dai->name, &dai_index); + if (is_sdw_slave(dai->component->dev)) + sdw_peripheral = dev_to_sdw_dev(dai->component->dev); + else if (dai->component->dev->parent && is_sdw_slave(dai->component->dev->parent)) + sdw_peripheral = dev_to_sdw_dev(dai->component->dev->parent); + else + continue; + + codec_info = asoc_sdw_find_codec_info_sdw_id(&sdw_peripheral->id); if (!codec_info) return -EINVAL; + dai_index = asoc_sdw_find_codec_info_dai_index(codec_info, dai->name); + WARN_ON(dai_index < 0); + /* * A codec dai can be connected to different dai links for capture and playback, * but we only need to call the rtd_init function once. @@ -898,6 +935,10 @@ int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) if (codec_info->dais[dai_index].rtd_init_done) continue; + dev_dbg(card->dev, "%#x/%s initializing for %s/%s\n", + codec_info->part_id, codec_info->dais[dai_index].dai_name, + dai->component->name, dai->name); + /* * Add card controls and dapm widgets for the first codec dai. * The controls and widgets will be used for all codec dais. From 390caeed0897fcac75f3c414dbdd85d593183d9c Mon Sep 17 00:00:00 2001 From: Cole Leavitt Date: Tue, 13 Jan 2026 19:55:18 -0700 Subject: [PATCH 228/443] ASoC: sdw_utils: cs42l43: Enable Headphone pin for LINEOUT jack type The CS42L43 codec's load detection can return different impedance values that map to either HEADPHONE or LINEOUT jack types. However, the soc_jack_pins array only maps SND_JACK_HEADPHONE to the "Headphone" DAPM pin, not SND_JACK_LINEOUT. When headphones are detected with an impedance that maps to LINEOUT (such as impedance value 0x2), the driver reports SND_JACK_LINEOUT. Since this doesn't match the jack pin mask, the "Headphone" DAPM pin is not activated, and no audio is routed to the headphone outputs. Fix by adding SND_JACK_LINEOUT to the Headphone pin mask, so that both headphone and line-out detection properly enable the headphone output path. This fixes no audio output on devices like the Lenovo ThinkPad P16 Gen 3 where headphones are detected with LINEOUT impedance. Fixes: d74bad3b7452 ("ASoC: intel: sof_sdw_cs42l43: Create separate jacks for hp and mic") Reviewed-by: Charles Keepax Signed-off-by: Cole Leavitt Link: https://patch.msgid.link/20260114025518.28519-1-cole@unwrap.rs Signed-off-by: Mark Brown --- sound/soc/sdw_utils/soc_sdw_cs42l43.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sdw_utils/soc_sdw_cs42l43.c b/sound/soc/sdw_utils/soc_sdw_cs42l43.c index 4c954501e500..2685ff4f0932 100644 --- a/sound/soc/sdw_utils/soc_sdw_cs42l43.c +++ b/sound/soc/sdw_utils/soc_sdw_cs42l43.c @@ -44,7 +44,7 @@ static const struct snd_soc_dapm_route cs42l43_dmic_map[] = { static struct snd_soc_jack_pin soc_jack_pins[] = { { .pin = "Headphone", - .mask = SND_JACK_HEADPHONE, + .mask = SND_JACK_HEADPHONE | SND_JACK_LINEOUT, }, { .pin = "Headset Mic", From 4130dc47ce8f60d289d91e2bdd18c4d863ca3237 Mon Sep 17 00:00:00 2001 From: Emil Svendsen Date: Tue, 13 Jan 2026 11:58:44 +0100 Subject: [PATCH 229/443] ASoC: tlv320adcx140: invert DRE_ENABLE Looking at section 8.6.1.1.69 in datasheets for both 5140 and 6140 (3140 doesn't support DRE). REG ADCX140_DSP_CFG1 BIT 3 field "DRE_AGC_SEL" it select either DRE or AGC. It states: * 0 = DRE * 1 = AGC The control is called "DRE_ENABLE" and for it to be true it has to be active low. This commit will invert the control so "DRE_ENABLE" is active low. Signed-off-by: Emil Svendsen Signed-off-by: Sascha Hauer Link: https://patch.msgid.link/20260113-sound-soc-codecs-tvl320adcx140-v4-1-8f7ecec525c8@pengutronix.de Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320adcx140.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index 443cf59cb71a..75e1007012a4 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -338,7 +338,7 @@ static const struct snd_kcontrol_new adcx140_dapm_ch4_dre_en_switch = SOC_DAPM_SINGLE("Switch", ADCX140_CH4_CFG0, 0, 1, 0); static const struct snd_kcontrol_new adcx140_dapm_dre_en_switch = - SOC_DAPM_SINGLE("Switch", ADCX140_DSP_CFG1, 3, 1, 0); + SOC_DAPM_SINGLE("Switch", ADCX140_DSP_CFG1, 3, 1, 1); /* Output Mixer */ static const struct snd_kcontrol_new adcx140_output_mixer_controls[] = { From be7664c81d3129fc313ef62ff275fd3d33cfecd4 Mon Sep 17 00:00:00 2001 From: Emil Svendsen Date: Tue, 13 Jan 2026 11:58:45 +0100 Subject: [PATCH 230/443] ASoC: tlv320adcx140: fix null pointer The "snd_soc_component" in "adcx140_priv" was only used once but never set. It was only used for reaching "dev" which is already present in "adcx140_priv". Fixes: 4e82971f7b55 ("ASoC: tlv320adcx140: Add a new kcontrol") Signed-off-by: Emil Svendsen Signed-off-by: Sascha Hauer Link: https://patch.msgid.link/20260113-sound-soc-codecs-tvl320adcx140-v4-2-8f7ecec525c8@pengutronix.de Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320adcx140.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index 75e1007012a4..3fb1b6251e6f 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -23,7 +23,6 @@ #include "tlv320adcx140.h" struct adcx140_priv { - struct snd_soc_component *component; struct regulator *supply_areg; struct gpio_desc *gpio_reset; struct regmap *regmap; @@ -699,7 +698,6 @@ static void adcx140_pwr_ctrl(struct adcx140_priv *adcx140, bool power_state) { int pwr_ctrl = 0; int ret = 0; - struct snd_soc_component *component = adcx140->component; if (power_state) pwr_ctrl = ADCX140_PWR_CFG_ADC_PDZ | ADCX140_PWR_CFG_PLL_PDZ; @@ -711,7 +709,7 @@ static void adcx140_pwr_ctrl(struct adcx140_priv *adcx140, bool power_state) ret = regmap_write(adcx140->regmap, ADCX140_PHASE_CALIB, adcx140->phase_calib_on ? 0x00 : 0x40); if (ret) - dev_err(component->dev, "%s: register write error %d\n", + dev_err(adcx140->dev, "%s: register write error %d\n", __func__, ret); } From d89aad92cfd15edbd704746f44c98fe687f9366f Mon Sep 17 00:00:00 2001 From: Dimitrios Katsaros Date: Tue, 13 Jan 2026 11:58:46 +0100 Subject: [PATCH 231/443] ASoC: tlv320adcx140: Propagate error codes during probe When scanning for the reset pin, we could get an -EPROBE_DEFER. The driver would assume that no reset pin had been defined, which would mean that the chip would never be powered. Now we both respect any error we get from devm_gpiod_get_optional. We also now properly report the missing GPIO definition when 'gpio_reset' is NULL. Signed-off-by: Dimitrios Katsaros Signed-off-by: Sascha Hauer Link: https://patch.msgid.link/20260113-sound-soc-codecs-tvl320adcx140-v4-3-8f7ecec525c8@pengutronix.de Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320adcx140.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index 3fb1b6251e6f..58a6dfa228cc 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -1154,6 +1154,9 @@ static int adcx140_i2c_probe(struct i2c_client *i2c) adcx140->gpio_reset = devm_gpiod_get_optional(adcx140->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(adcx140->gpio_reset)) + return dev_err_probe(&i2c->dev, PTR_ERR(adcx140->gpio_reset), + "Failed to get Reset GPIO\n"); + if (!adcx140->gpio_reset) dev_info(&i2c->dev, "Reset GPIO not defined\n"); adcx140->supply_areg = devm_regulator_get_optional(adcx140->dev, From 46378ab9fcb796dca46b51e10646f636e2c661f9 Mon Sep 17 00:00:00 2001 From: Emil Svendsen Date: Tue, 13 Jan 2026 11:58:47 +0100 Subject: [PATCH 232/443] ASoC: tlv320adcx140: fix word length The word length is the physical width of the channel slots. So the hw_params would misconfigure when format width and physical width doesn't match. Like S24_LE which has data width of 24 bits but physical width of 32 bits. So if using asymmetric formats you will get a lot of noise. Fixes: 689c7655b50c5 ("ASoC: tlv320adcx140: Add the tlv320adcx140 codec driver family") Signed-off-by: Emil Svendsen Signed-off-by: Sascha Hauer Link: https://patch.msgid.link/20260113-sound-soc-codecs-tvl320adcx140-v4-4-8f7ecec525c8@pengutronix.de Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320adcx140.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/tlv320adcx140.c b/sound/soc/codecs/tlv320adcx140.c index 58a6dfa228cc..fdf4a9add852 100644 --- a/sound/soc/codecs/tlv320adcx140.c +++ b/sound/soc/codecs/tlv320adcx140.c @@ -725,7 +725,7 @@ static int adcx140_hw_params(struct snd_pcm_substream *substream, struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component); u8 data = 0; - switch (params_width(params)) { + switch (params_physical_width(params)) { case 16: data = ADCX140_16_BIT_WORD; break; @@ -740,7 +740,7 @@ static int adcx140_hw_params(struct snd_pcm_substream *substream, break; default: dev_err(component->dev, "%s: Unsupported width %d\n", - __func__, params_width(params)); + __func__, params_physical_width(params)); return -EINVAL; } From e07dea3de508cd6950c937cec42de7603190e1ca Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Fri, 9 Jan 2026 15:46:26 +0000 Subject: [PATCH 233/443] phy: rockchip: inno-usb2: Fix a double free bug in rockchip_usb2phy_probe() The for_each_available_child_of_node() calls of_node_put() to release child_np in each success loop. After breaking from the loop with the child_np has been released, the code will jump to the put_child label and will call the of_node_put() again if the devm_request_threaded_irq() fails. These cause a double free bug. Fix by returning directly to avoid the duplicate of_node_put(). Fixes: ed2b5a8e6b98 ("phy: phy-rockchip-inno-usb2: support muxed interrupts") Cc: stable@vger.kernel.org Signed-off-by: Wentao Liang Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20260109154626.2452034-1-vulab@iscas.ac.cn Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index e5efae7b0135..8f4c08e599aa 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -1495,7 +1495,7 @@ next_child: rphy); if (ret) { dev_err_probe(rphy->dev, ret, "failed to request usb2phy irq handle\n"); - goto put_child; + return ret; } } From c4380ee3ccbf591d855317249f31c820b7b73a46 Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Fri, 9 Jan 2026 17:43:34 +0100 Subject: [PATCH 234/443] usb: dwc3: apple: Set USB2 PHY mode before dwc3 init Now that the upstream code has been getting broader test coverage by our users we occasionally see issues with USB2 devices plugged in during boot. Before Linux is running, the USB2 PHY has usually been running in device mode and it turns out that sometimes host->device or device->host transitions don't work. The root cause: If the role inside the USB2 PHY is re-configured when it has already been powered on or when dwc3 has already enabled the ULPI interface the new configuration sometimes doesn't take affect until dwc3 is reset again. Fix this rare issue by configuring the role much earlier. Note that the USB3 PHY does not suffer from this issue and actually requires dwc3 to be up before the correct role can be configured there. Reported-by: James Calligeros Reported-by: Janne Grunau Fixes: 0ec946d32ef7 ("usb: dwc3: Add Apple Silicon DWC3 glue layer driver") Cc: stable Tested-by: Janne Grunau Reviewed-by: Janne Grunau Acked-by: Thinh Nguyen Signed-off-by: Sven Peter Link: https://patch.msgid.link/20260109-dwc3-apple-usb2phy-fix-v2-1-ab6b041e3b26@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-apple.c | 48 ++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-apple.c b/drivers/usb/dwc3/dwc3-apple.c index cc47cad232e3..c2ae8eb21d51 100644 --- a/drivers/usb/dwc3/dwc3-apple.c +++ b/drivers/usb/dwc3/dwc3-apple.c @@ -218,25 +218,31 @@ static int dwc3_apple_core_init(struct dwc3_apple *appledwc) return ret; } -static void dwc3_apple_phy_set_mode(struct dwc3_apple *appledwc, enum phy_mode mode) -{ - lockdep_assert_held(&appledwc->lock); - - /* - * This platform requires SUSPHY to be enabled here already in order to properly configure - * the PHY and switch dwc3's PIPE interface to USB3 PHY. - */ - dwc3_enable_susphy(&appledwc->dwc, true); - phy_set_mode(appledwc->dwc.usb2_generic_phy[0], mode); - phy_set_mode(appledwc->dwc.usb3_generic_phy[0], mode); -} - static int dwc3_apple_init(struct dwc3_apple *appledwc, enum dwc3_apple_state state) { int ret, ret_reset; lockdep_assert_held(&appledwc->lock); + /* + * The USB2 PHY on this platform must be configured for host or device mode while it is + * still powered off and before dwc3 tries to access it. Otherwise, the new configuration + * will sometimes only take affect after the *next* time dwc3 is brought up which causes + * the connected device to just not work. + * The USB3 PHY must be configured later after dwc3 has already been initialized. + */ + switch (state) { + case DWC3_APPLE_HOST: + phy_set_mode(appledwc->dwc.usb2_generic_phy[0], PHY_MODE_USB_HOST); + break; + case DWC3_APPLE_DEVICE: + phy_set_mode(appledwc->dwc.usb2_generic_phy[0], PHY_MODE_USB_DEVICE); + break; + default: + /* Unreachable unless there's a bug in this driver */ + return -EINVAL; + } + ret = reset_control_deassert(appledwc->reset); if (ret) { dev_err(appledwc->dev, "Failed to deassert reset, err=%d\n", ret); @@ -257,7 +263,13 @@ static int dwc3_apple_init(struct dwc3_apple *appledwc, enum dwc3_apple_state st case DWC3_APPLE_HOST: appledwc->dwc.dr_mode = USB_DR_MODE_HOST; dwc3_apple_set_ptrcap(appledwc, DWC3_GCTL_PRTCAP_HOST); - dwc3_apple_phy_set_mode(appledwc, PHY_MODE_USB_HOST); + /* + * This platform requires SUSPHY to be enabled here already in order to properly + * configure the PHY and switch dwc3's PIPE interface to USB3 PHY. The USB2 PHY + * has already been configured to the correct mode earlier. + */ + dwc3_enable_susphy(&appledwc->dwc, true); + phy_set_mode(appledwc->dwc.usb3_generic_phy[0], PHY_MODE_USB_HOST); ret = dwc3_host_init(&appledwc->dwc); if (ret) { dev_err(appledwc->dev, "Failed to initialize host, ret=%d\n", ret); @@ -268,7 +280,13 @@ static int dwc3_apple_init(struct dwc3_apple *appledwc, enum dwc3_apple_state st case DWC3_APPLE_DEVICE: appledwc->dwc.dr_mode = USB_DR_MODE_PERIPHERAL; dwc3_apple_set_ptrcap(appledwc, DWC3_GCTL_PRTCAP_DEVICE); - dwc3_apple_phy_set_mode(appledwc, PHY_MODE_USB_DEVICE); + /* + * This platform requires SUSPHY to be enabled here already in order to properly + * configure the PHY and switch dwc3's PIPE interface to USB3 PHY. The USB2 PHY + * has already been configured to the correct mode earlier. + */ + dwc3_enable_susphy(&appledwc->dwc, true); + phy_set_mode(appledwc->dwc.usb3_generic_phy[0], PHY_MODE_USB_DEVICE); ret = dwc3_gadget_init(&appledwc->dwc); if (ret) { dev_err(appledwc->dev, "Failed to initialize gadget, ret=%d\n", ret); From 01ef7f1b8713a78ab1a9512cf8096d2474c70633 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Mon, 12 Jan 2026 16:48:02 +0800 Subject: [PATCH 235/443] USB: OHCI/UHCI: Add soft dependencies on ehci_platform Commit 9beeee6584b9aa4f ("USB: EHCI: log a warning if ehci-hcd is not loaded first") said that ehci-hcd should be loaded before ohci-hcd and uhci-hcd. However, commit 05c92da0c52494ca ("usb: ohci/uhci - add soft dependencies on ehci_pci") only makes ohci-pci/uhci-pci depend on ehci- pci, which is not enough and we may still see the warnings in boot log. To eliminate the warnings we should make ohci-hcd/uhci-hcd depend on ehci-hcd. But Alan said that the warning introduced by 9beeee6584b9aa4f is bogus, we only need the soft dependencies in the PCI level rather than the HCD level. However, there is really another neccessary soft dependencies between ohci-platform/uhci-platform and ehci-platform, which is added by this patch. The boot logs are below. 1. ohci-platform loaded before ehci-platform: ohci-platform 1f058000.usb: Generic Platform OHCI controller ohci-platform 1f058000.usb: new USB bus registered, assigned bus number 1 ohci-platform 1f058000.usb: irq 28, io mem 0x1f058000 hub 1-0:1.0: USB hub found hub 1-0:1.0: 4 ports detected Warning! ehci_hcd should always be loaded before uhci_hcd and ohci_hcd, not after usb 1-4: new low-speed USB device number 2 using ohci-platform ehci-platform 1f050000.usb: EHCI Host Controller ehci-platform 1f050000.usb: new USB bus registered, assigned bus number 2 ehci-platform 1f050000.usb: irq 29, io mem 0x1f050000 ehci-platform 1f050000.usb: USB 2.0 started, EHCI 1.00 usb 1-4: device descriptor read/all, error -62 hub 2-0:1.0: USB hub found hub 2-0:1.0: 4 ports detected usb 1-4: new low-speed USB device number 3 using ohci-platform input: YSPRINGTECH USB OPTICAL MOUSE as /devices/platform/bus@10000000/1f058000.usb/usb1/1-4/1-4:1.0/0003:10C4:8105.0001/input/input0 hid-generic 0003:10C4:8105.0001: input,hidraw0: USB HID v1.11 Mouse [YSPRINGTECH USB OPTICAL MOUSE] on usb-1f058000.usb-4/input0 2. ehci-platform loaded before ohci-platform: ehci-platform 1f050000.usb: EHCI Host Controller ehci-platform 1f050000.usb: new USB bus registered, assigned bus number 1 ehci-platform 1f050000.usb: irq 28, io mem 0x1f050000 ehci-platform 1f050000.usb: USB 2.0 started, EHCI 1.00 hub 1-0:1.0: USB hub found hub 1-0:1.0: 4 ports detected ohci-platform 1f058000.usb: Generic Platform OHCI controller ohci-platform 1f058000.usb: new USB bus registered, assigned bus number 2 ohci-platform 1f058000.usb: irq 29, io mem 0x1f058000 hub 2-0:1.0: USB hub found hub 2-0:1.0: 4 ports detected usb 2-4: new low-speed USB device number 2 using ohci-platform input: YSPRINGTECH USB OPTICAL MOUSE as /devices/platform/bus@10000000/1f058000.usb/usb2/2-4/2-4:1.0/0003:10C4:8105.0001/input/input0 hid-generic 0003:10C4:8105.0001: input,hidraw0: USB HID v1.11 Mouse [YSPRINGTECH USB OPTICAL MOUSE] on usb-1f058000.usb-4/input0 In the later case, there is no re-connection for USB-1.0/1.1 devices, which is expected. Cc: stable Reported-by: Shengwen Xiao Signed-off-by: Huacai Chen Reviewed-by: Alan Stern Link: https://patch.msgid.link/20260112084802.1995923-1-chenhuacai@loongson.cn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-platform.c | 1 + drivers/usb/host/uhci-platform.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index 2e4bb5cc2165..c801527d5bd2 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -392,3 +392,4 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Hauke Mehrtens"); MODULE_AUTHOR("Alan Stern"); MODULE_LICENSE("GPL"); +MODULE_SOFTDEP("pre: ehci_platform"); diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c index 5e02f2ceafb6..f4419d4526c4 100644 --- a/drivers/usb/host/uhci-platform.c +++ b/drivers/usb/host/uhci-platform.c @@ -211,3 +211,4 @@ static struct platform_driver uhci_platform_driver = { .of_match_table = platform_uhci_ids, }, }; +MODULE_SOFTDEP("pre: ehci_platform"); From d13b6a128a12e528bb18f971f2969feb286f45c7 Mon Sep 17 00:00:00 2001 From: Wayne Chang Date: Mon, 12 Jan 2026 22:56:53 +0800 Subject: [PATCH 236/443] usb: host: xhci-tegra: Use platform_get_irq_optional() for wake IRQs When some wake IRQs are disabled in the device tree, the corresponding interrupt entries are removed from DT. In such cases, the driver currently calls platform_get_irq(), which returns -ENXIO and logs an error like: tegra-xusb 3610000.usb: error -ENXIO: IRQ index 2 not found However, not all wake IRQs are mandatory. The hardware can operate normally even if some wake sources are not defined in DT. To avoid this false alarm and allow missing wake IRQs gracefully, use platform_get_irq_optional() instead of platform_get_irq(). Fixes: 5df186e2ef11 ("usb: xhci: tegra: Support USB wakeup function for Tegra234") Cc: stable Signed-off-by: Wayne Chang Signed-off-by: Wei-Cheng Chen Reviewed-by: Jon Hunter Tested-by: Jon Hunter Link: https://patch.msgid.link/20260112145653.95691-1-weichengc@nvidia.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 31ccced5125e..8b492871d21d 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1563,7 +1563,7 @@ static int tegra_xusb_setup_wakeup(struct platform_device *pdev, struct tegra_xu for (i = 0; i < tegra->soc->max_num_wakes; i++) { struct irq_data *data; - tegra->wake_irqs[i] = platform_get_irq(pdev, i + WAKE_IRQ_START_INDEX); + tegra->wake_irqs[i] = platform_get_irq_optional(pdev, i + WAKE_IRQ_START_INDEX); if (tegra->wake_irqs[i] < 0) break; From 42c85d89b8d677b51f6a75569c69299a46d9f03d Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 9 Jan 2026 11:13:48 +0100 Subject: [PATCH 237/443] usb: dwc3: apple: Ignore USB role switches to the active role Ignore USB role switches if dwc3-apple is already in the desired state. The USB-C port controller on M2 and M1/M2 Pro/Max/Ultra devices issues additional interrupts which result in USB role switches to the already active role. Ignore these USB role switches to ensure the USB-C port controller and dwc3-apple are always in a consistent state. This matches the behaviour in __dwc3_set_mode() in core.c. Fixes detecting USB 2.0 and 3.x devices on the affected systems. The reset caused by the additional role switch appears to leave the USB devices in a state which prevents detection when the phy and dwc3 is brought back up again. Fixes: 0ec946d32ef7 ("usb: dwc3: Add Apple Silicon DWC3 glue layer driver") Cc: stable Signed-off-by: Janne Grunau Acked-by: Thinh Nguyen Reviewed-by: Sven Peter Tested-by: Sven Peter # M1 mac mini and macbook air Link: https://patch.msgid.link/20260109-apple-dwc3-role-switch-v1-1-11623b0f6222@jannau.net Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-apple.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-apple.c b/drivers/usb/dwc3/dwc3-apple.c index c2ae8eb21d51..40c3ccfddb67 100644 --- a/drivers/usb/dwc3/dwc3-apple.c +++ b/drivers/usb/dwc3/dwc3-apple.c @@ -357,6 +357,22 @@ static int dwc3_usb_role_switch_set(struct usb_role_switch *sw, enum usb_role ro guard(mutex)(&appledwc->lock); + /* + * Skip role switches if appledwc is already in the desired state. The + * USB-C port controller on M2 and M1/M2 Pro/Max/Ultra devices issues + * additional interrupts which results in usb_role_switch_set_role() + * calls with the current role. + * Ignore those calls here to ensure the USB-C port controller and + * appledwc are in a consistent state. + * This matches the behaviour in __dwc3_set_mode(). + * Do no handle USB_ROLE_NONE for DWC3_APPLE_NO_CABLE and + * DWC3_APPLE_PROBE_PENDING since that is no-op anyway. + */ + if (appledwc->state == DWC3_APPLE_HOST && role == USB_ROLE_HOST) + return 0; + if (appledwc->state == DWC3_APPLE_DEVICE && role == USB_ROLE_DEVICE) + return 0; + /* * We need to tear all of dwc3 down and re-initialize it every time a cable is * connected or disconnected or when the mode changes. See the documentation for enum From 2edc1acb1a2512843425aa19d0c6060a0a924605 Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Tue, 13 Jan 2026 17:53:07 +0800 Subject: [PATCH 238/443] usb: gadget: uvc: fix req_payload_size calculation Current req_payload_size calculation has 2 issue: (1) When the first time calculate req_payload_size for all the buffers, reqs_per_frame = 0 will be the divisor of DIV_ROUND_UP(). So the result is undefined. This happens because VIDIOC_STREAMON is always executed after VIDIOC_QBUF. So video->reqs_per_frame will be 0 until VIDIOC_STREAMON is run. (2) The buf->req_payload_size may be bigger than max_req_size. Take YUYV pixel format as example: If bInterval = 1, video->interval = 666666, high-speed: video->reqs_per_frame = 666666 / 1250 = 534 720p: buf->req_payload_size = 1843200 / 534 = 3452 1080p: buf->req_payload_size = 4147200 / 534 = 7766 Based on such req_payload_size, the controller can't run normally. To fix above issue, assign max_req_size to buf->req_payload_size when video->reqs_per_frame = 0. And limit buf->req_payload_size to video->req_size if it's large than video->req_size. Since max_req_size is used at many place, add it to struct uvc_video and set the value once endpoint is enabled. Fixes: 98ad03291560 ("usb: gadget: uvc: set req_length based on payload by nreqs instead of req_size") Cc: stable@vger.kernel.org Reviewed-by: Frank Li Signed-off-by: Xu Yang Link: https://patch.msgid.link/20260113-uvc-gadget-fix-patch-v2-1-62950ef5bcb5@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_uvc.c | 4 ++++ drivers/usb/gadget/function/uvc.h | 1 + drivers/usb/gadget/function/uvc_queue.c | 15 +++++++++++---- drivers/usb/gadget/function/uvc_video.c | 4 +--- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index aa6ab666741a..a96476507d2f 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -362,6 +362,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) return ret; usb_ep_enable(uvc->video.ep); + uvc->video.max_req_size = uvc->video.ep->maxpacket + * max_t(unsigned int, uvc->video.ep->maxburst, 1) + * (uvc->video.ep->mult); + memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_STREAMON; v4l2_event_queue(&uvc->vdev, &v4l2_event); diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 9e79cbe50715..b3f88670bff8 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -117,6 +117,7 @@ struct uvc_video { /* Requests */ bool is_enabled; /* tracks whether video stream is enabled */ unsigned int req_size; + unsigned int max_req_size; struct list_head ureqs; /* all uvc_requests allocated by uvc_video */ /* USB requests that the video pump thread can encode into */ diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c index 9a1bbd79ff5a..21d80322cb61 100644 --- a/drivers/usb/gadget/function/uvc_queue.c +++ b/drivers/usb/gadget/function/uvc_queue.c @@ -86,10 +86,17 @@ static int uvc_buffer_prepare(struct vb2_buffer *vb) buf->bytesused = 0; } else { buf->bytesused = vb2_get_plane_payload(vb, 0); - buf->req_payload_size = - DIV_ROUND_UP(buf->bytesused + - (video->reqs_per_frame * UVCG_REQUEST_HEADER_LEN), - video->reqs_per_frame); + + if (video->reqs_per_frame != 0) { + buf->req_payload_size = + DIV_ROUND_UP(buf->bytesused + + (video->reqs_per_frame * UVCG_REQUEST_HEADER_LEN), + video->reqs_per_frame); + if (buf->req_payload_size > video->req_size) + buf->req_payload_size = video->req_size; + } else { + buf->req_payload_size = video->max_req_size; + } } return 0; diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index fb77b0b21790..1c0672f707e4 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -503,9 +503,7 @@ uvc_video_prep_requests(struct uvc_video *video) unsigned int max_req_size, req_size, header_size; unsigned int nreq; - max_req_size = video->ep->maxpacket - * max_t(unsigned int, video->ep->maxburst, 1) - * (video->ep->mult); + max_req_size = video->max_req_size; if (!usb_endpoint_xfer_isoc(video->ep->desc)) { video->req_size = max_req_size; From 010dc57cb5163e5f4a32430dd5091cc29efd0471 Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Tue, 13 Jan 2026 17:53:08 +0800 Subject: [PATCH 239/443] usb: gadget: uvc: fix interval_duration calculation According to USB specification: For full-/high-speed isochronous endpoints, the bInterval value is used as the exponent for a 2^(bInterval-1) value. To correctly convert bInterval as interval_duration: interval_duration = 2^(bInterval-1) * frame_interval Because the unit of video->interval is 100ns, add a comment info to make it clear. Fixes: 48dbe731171e ("usb: gadget: uvc: set req_size and n_requests based on the frame interval") Cc: stable@vger.kernel.org Reviewed-by: Frank Li Signed-off-by: Xu Yang Link: https://patch.msgid.link/20260113-uvc-gadget-fix-patch-v2-2-62950ef5bcb5@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/uvc.h | 2 +- drivers/usb/gadget/function/uvc_video.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index b3f88670bff8..676419a04976 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -107,7 +107,7 @@ struct uvc_video { unsigned int width; unsigned int height; unsigned int imagesize; - unsigned int interval; + unsigned int interval; /* in 100ns units */ struct mutex mutex; /* protects frame parameters */ unsigned int uvc_num_requests; diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index 1c0672f707e4..9dc3af16e2f3 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -499,7 +499,7 @@ uvc_video_prep_requests(struct uvc_video *video) { struct uvc_device *uvc = container_of(video, struct uvc_device, video); struct usb_composite_dev *cdev = uvc->func.config->cdev; - unsigned int interval_duration = video->ep->desc->bInterval * 1250; + unsigned int interval_duration; unsigned int max_req_size, req_size, header_size; unsigned int nreq; @@ -513,8 +513,11 @@ uvc_video_prep_requests(struct uvc_video *video) return; } + interval_duration = 2 << (video->ep->desc->bInterval - 1); if (cdev->gadget->speed < USB_SPEED_HIGH) - interval_duration = video->ep->desc->bInterval * 10000; + interval_duration *= 10000; + else + interval_duration *= 1250; nreq = DIV_ROUND_UP(video->interval, interval_duration); From 0bce8f19bba16277257a915e4fb94e1cfe99d760 Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Tue, 13 Jan 2026 17:53:09 +0800 Subject: [PATCH 240/443] usb: gadget: uvc: return error from uvcg_queue_init() uvcg_queue_init() may fail, but its return value is currently ignored. Propagate the error code from uvcg_queue_init() to correctly report initialization failures. Signed-off-by: Xu Yang Link: https://patch.msgid.link/20260113-uvc-gadget-fix-patch-v2-3-62950ef5bcb5@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/uvc_video.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index 9dc3af16e2f3..f568dee08b3b 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -838,7 +838,6 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc) video->interval = 666666; /* Initialize the video buffers queue. */ - uvcg_queue_init(&video->queue, uvc->v4l2_dev.dev->parent, + return uvcg_queue_init(&video->queue, uvc->v4l2_dev.dev->parent, V4L2_BUF_TYPE_VIDEO_OUTPUT, &video->mutex); - return 0; } From 9bcb4c4c330ca36ba7ab398c03d75c15b769d59d Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Tue, 13 Jan 2026 17:53:10 +0800 Subject: [PATCH 241/443] usb: gadget: uvc: retry vb2_reqbufs() with vb_vmalloc_memops if use_sg fail Based on the reality[1][2] that vb2_dma_sg_alloc() can't alloc buffer with device DMA limits, those device will always get below error: "swiotlb buffer is full (sz: 393216 bytes), total 65536 (slots), used 2358 (slots)" and the uvc gadget function can't work at all. The videobuf2-dma-sg.c driver doesn't has a formal improve about this issue till now. For UVC gadget, the videobuf2 subsystem doesn't do dma_map() on vmalloc returned big buffer when allocate the video buffers, however, it do it for dma_sg returned buffer. So the issue happens for vb2_dma_sg_alloc(). To workaround the issue, lets retry vb2_reqbufs() with vb_vmalloc_memops if it fails to allocate buffer with vb2_dma_sg_memops. If use vmalloced buffer, UVC gadget will allocate some small buffers for each usb_request to do dma transfer, then uvc driver will memcopy data from big buffer to small buffer. Link[1]: https://lore.kernel.org/linux-media/20230828075420.2009568-1-anle.pan@nxp.com/ Link[2]: https://lore.kernel.org/linux-media/20230914145812.12851-1-hui.fang@nxp.com/ Signed-off-by: Xu Yang Reviewed-by: Frank Li Link: https://patch.msgid.link/20260113-uvc-gadget-fix-patch-v2-4-62950ef5bcb5@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/uvc_queue.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c index 21d80322cb61..586e5524c171 100644 --- a/drivers/usb/gadget/function/uvc_queue.c +++ b/drivers/usb/gadget/function/uvc_queue.c @@ -182,7 +182,15 @@ int uvcg_alloc_buffers(struct uvc_video_queue *queue, { int ret; +retry: ret = vb2_reqbufs(&queue->queue, rb); + if (ret < 0 && queue->use_sg) { + uvc_trace(UVC_TRACE_IOCTL, + "failed to alloc buffer with sg enabled, try non-sg mode\n"); + queue->use_sg = 0; + queue->queue.mem_ops = &vb2_vmalloc_memops; + goto retry; + } return ret ? ret : rb->count; } From 0edb475ac0a7d153318a24d4dca175a270a5cc4f Mon Sep 17 00:00:00 2001 From: Nilay Shroff Date: Wed, 14 Jan 2026 12:54:13 +0530 Subject: [PATCH 242/443] nvme: fix PCIe subsystem reset controller state transition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit d2fe192348f9 (“nvme: only allow entering LIVE from CONNECTING state”) disallows controller state transitions directly from RESETTING to LIVE. However, the NVMe PCIe subsystem reset path relies on this transition to recover the controller on PowerPC (PPC) systems. On PPC systems, issuing a subsystem reset causes a temporary loss of communication with the NVMe adapter. A subsequent PCIe MMIO read then triggers EEH recovery, which restores the PCIe link and brings the controller back online. For EEH recovery to proceed correctly, the controller must transition back to the LIVE state. Due to the changes introduced by commit d2fe192348f9 (“nvme: only allow entering LIVE from CONNECTING state”), the controller can no longer transition directly from RESETTING to LIVE. As a result, EEH recovery exits prematurely, leaving the controller stuck in the RESETTING state. Fix this by explicitly transitioning the controller state from RESETTING to CONNECTING and then to LIVE. This satisfies the updated state transition rules and allows the controller to be successfully recovered on PPC systems following a PCIe subsystem reset. Cc: stable@vger.kernel.org Fixes: d2fe192348f9 ("nvme: only allow entering LIVE from CONNECTING state") Reviewed-by: Daniel Wagner Signed-off-by: Nilay Shroff Signed-off-by: Keith Busch --- drivers/nvme/host/pci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 29e715d5b8f3..58f3097888a7 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1532,7 +1532,10 @@ static int nvme_pci_subsystem_reset(struct nvme_ctrl *ctrl) } writel(NVME_SUBSYS_RESET, dev->bar + NVME_REG_NSSR); - nvme_change_ctrl_state(ctrl, NVME_CTRL_LIVE); + + if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_CONNECTING) || + !nvme_change_ctrl_state(ctrl, NVME_CTRL_LIVE)) + goto unlock; /* * Read controller status to flush the previous write and trigger a From f2ec4723defbc66a50e0abafa830ae9f8bceb0d7 Mon Sep 17 00:00:00 2001 From: Rafael Beims Date: Tue, 23 Dec 2025 12:02:54 -0300 Subject: [PATCH 243/443] phy: freescale: imx8m-pcie: assert phy reset during power on After U-Boot initializes PCIe with "pcie enum", Linux fails to detect an NVMe disk on some boot cycles with: phy phy-32f00000.pcie-phy.0: phy poweron failed --> -110 Discussion with NXP identified that the iMX8MP PCIe PHY PLL may fail to lock when re-initialized without a reset cycle [1]. The issue reproduces on 7% of tested hardware platforms, with a 30-40% failure rate per affected device across boot cycles. Insert a reset cycle in the power-on routine to ensure the PHY is initialized from a known state. [1] https://community.nxp.com/t5/i-MX-Processors/iMX8MP-PCIe-initialization-in-U-Boot/m-p/2248437#M242401 Signed-off-by: Rafael Beims Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20251223150254.1075221-1-rafael@beims.me Signed-off-by: Vinod Koul --- drivers/phy/freescale/phy-fsl-imx8m-pcie.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c index 68fcc8114d75..7f5600103a00 100644 --- a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c +++ b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c @@ -89,7 +89,8 @@ static int imx8_pcie_phy_power_on(struct phy *phy) writel(imx8_phy->tx_deemph_gen2, imx8_phy->base + PCIE_PHY_TRSV_REG6); break; - case IMX8MP: /* Do nothing. */ + case IMX8MP: + reset_control_assert(imx8_phy->reset); break; } From da579f05ef0faada3559e7faddf761c75cdf85e1 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 14 Jan 2026 16:54:05 +0800 Subject: [PATCH 244/443] io_uring: move local task_work in exit cancel loop With IORING_SETUP_DEFER_TASKRUN, task work is queued to ctx->work_llist (local work) rather than the fallback list. During io_ring_exit_work(), io_move_task_work_from_local() was called once before the cancel loop, moving work from work_llist to fallback_llist. However, task work can be added to work_llist during the cancel loop itself. There are two cases: 1) io_kill_timeouts() is called from io_uring_try_cancel_requests() to cancel pending timeouts, and it adds task work via io_req_queue_tw_complete() for each cancelled timeout: 2) URING_CMD requests like ublk can be completed via io_uring_cmd_complete_in_task() from ublk_queue_rq() during canceling, given ublk request queue is only quiesced when canceling the 1st uring_cmd. Since io_allowed_defer_tw_run() returns false in io_ring_exit_work() (kworker != submitter_task), io_run_local_work() is never invoked, and the work_llist entries are never processed. This causes io_uring_try_cancel_requests() to loop indefinitely, resulting in 100% CPU usage in kworker threads. Fix this by moving io_move_task_work_from_local() inside the cancel loop, ensuring any work on work_llist is moved to fallback before each cancel attempt. Cc: stable@vger.kernel.org Fixes: c0e0d6ba25f1 ("io_uring: add IORING_SETUP_DEFER_TASKRUN") Signed-off-by: Ming Lei Signed-off-by: Jens Axboe --- io_uring/io_uring.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index 87a87396e940..b7a077c11c21 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -3003,12 +3003,12 @@ static __cold void io_ring_exit_work(struct work_struct *work) mutex_unlock(&ctx->uring_lock); } - if (ctx->flags & IORING_SETUP_DEFER_TASKRUN) - io_move_task_work_from_local(ctx); - /* The SQPOLL thread never reaches this path */ - while (io_uring_try_cancel_requests(ctx, NULL, true, false)) + do { + if (ctx->flags & IORING_SETUP_DEFER_TASKRUN) + io_move_task_work_from_local(ctx); cond_resched(); + } while (io_uring_try_cancel_requests(ctx, NULL, true, false)); if (ctx->sq_data) { struct io_sq_data *sqd = ctx->sq_data; From 292e5757b2229c0c6f1d059123a85f8a28f4464d Mon Sep 17 00:00:00 2001 From: Philip Yang Date: Thu, 4 Dec 2025 12:13:05 -0500 Subject: [PATCH 245/443] drm/amdgpu: Fix gfx9 update PTE mtype flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix copy&paste error, that should have been an assignment instead of an or, otherwise MTYPE_UC 0x3 can not be updated to MTYPE_RW 0x1. Signed-off-by: Philip Yang Reviewed-by: Christian König Signed-off-by: Alex Deucher (cherry picked from commit fc1366016abe4103c0f0fac882811aea961ef213) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 8ad7519f7b58..f1ee3921d970 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -1235,16 +1235,16 @@ static void gmc_v9_0_get_vm_pte(struct amdgpu_device *adev, *flags = AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_NC); break; case AMDGPU_VM_MTYPE_WC: - *flags |= AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_WC); + *flags = AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_WC); break; case AMDGPU_VM_MTYPE_RW: - *flags |= AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_RW); + *flags = AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_RW); break; case AMDGPU_VM_MTYPE_CC: - *flags |= AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_CC); + *flags = AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_CC); break; case AMDGPU_VM_MTYPE_UC: - *flags |= AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_UC); + *flags = AMDGPU_PTE_MTYPE_VG10(*flags, MTYPE_UC); break; } From 9cb6278b44c38899961b36d303d7b18b38be2a6e Mon Sep 17 00:00:00 2001 From: Lu Yao Date: Tue, 6 Jan 2026 10:37:12 +0800 Subject: [PATCH 246/443] drm/amdgpu: fix drm panic null pointer when driver not support atomic When driver not support atomic, fb using plane->fb rather than plane->state->fb. Fixes: fe151ed7af54 ("drm/amdgpu: add generic display panic helper code") Signed-off-by: Lu Yao Signed-off-by: Alex Deucher (cherry picked from commit 2f2a72de673513247cd6fae14e53f6c40c5841ef) --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index b5d34797d606..52bc04452812 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -1880,7 +1880,12 @@ int amdgpu_display_get_scanout_buffer(struct drm_plane *plane, struct drm_scanout_buffer *sb) { struct amdgpu_bo *abo; - struct drm_framebuffer *fb = plane->state->fb; + struct drm_framebuffer *fb; + + if (drm_drv_uses_atomic_modeset(plane->dev)) + fb = plane->state->fb; + else + fb = plane->fb; if (!fb) return -EINVAL; From 28695ca09d326461f8078332aa01db516983e8a2 Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Wed, 7 Jan 2026 15:37:28 -0600 Subject: [PATCH 247/443] drm/amd: Clean up kfd node on surprise disconnect When an eGPU is unplugged the KFD topology should also be destroyed for that GPU. This never happens because the fini_sw callbacks never get to run. Run them manually before calling amdgpu_device_ip_fini_early() when a device has already been disconnected. This location is intentionally chosen to make sure that the kfd locking refcount doesn't get incremented unintentionally. Cc: kent.russell@amd.com Closes: https://community.frame.work/t/amd-egpu-on-linux/8691/33 Signed-off-by: Mario Limonciello (AMD) Reviewed-by: Kent Russell Signed-off-by: Alex Deucher (cherry picked from commit 6a23e7b4332c10f8b56c33a9c5431b52ecff9aab) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index d5c44bd34d45..d2c3885de711 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -5063,6 +5063,14 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) amdgpu_ttm_set_buffer_funcs_status(adev, false); + /* + * device went through surprise hotplug; we need to destroy topology + * before ip_fini_early to prevent kfd locking refcount issues by calling + * amdgpu_amdkfd_suspend() + */ + if (drm_dev_is_unplugged(adev_to_drm(adev))) + amdgpu_amdkfd_device_fini_sw(adev); + amdgpu_device_ip_fini_early(adev); amdgpu_irq_fini_hw(adev); From 9c8120015270d8a31c335c7137977749e5e8cd30 Mon Sep 17 00:00:00 2001 From: Peter Colberg Date: Mon, 22 Dec 2025 12:42:48 -0500 Subject: [PATCH 248/443] Revert duplicate "drm/amdgpu: disable peer-to-peer access for DCC-enabled GC12 VRAM surfaces" This reverts commit 22a36e660d014925114feb09a2680bb3c2d1e279 once, which was merged twice due to an incorrect backmerge resolution. Fixes: ce0478b02ed2 ("Merge tag 'v6.18-rc6' into drm-next") Signed-off-by: Peter Colberg Signed-off-by: Alex Deucher (cherry picked from commit 38a0f4cf8c6147fd10baa206ab349f8ff724e391) --- drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index e22cfa7c6d32..c1461317eb29 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -83,18 +83,6 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf, struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); int r; - /* - * Disable peer-to-peer access for DCC-enabled VRAM surfaces on GFX12+. - * Such buffers cannot be safely accessed over P2P due to device-local - * compression metadata. Fallback to system-memory path instead. - * Device supports GFX12 (GC 12.x or newer) - * BO was created with the AMDGPU_GEM_CREATE_GFX12_DCC flag - * - */ - if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(12, 0, 0) && - bo->flags & AMDGPU_GEM_CREATE_GFX12_DCC) - attach->peer2peer = false; - /* * Disable peer-to-peer access for DCC-enabled VRAM surfaces on GFX12+. * Such buffers cannot be safely accessed over P2P due to device-local From 122b15cdbcc2eaccd7c1e630bb79ff4c268dd3f4 Mon Sep 17 00:00:00 2001 From: Xiaogang Chen Date: Thu, 8 Jan 2026 09:50:36 -0600 Subject: [PATCH 249/443] drm/amdgpu: Use correct address to setup gart page table for vram access Use dst input parameter to setup gart page table entries instead of using fixed location. Fixes: 237d623ae659 ("drm/amdgpu/gart: Add helper to bind VRAM pages (v2)") Signed-off-by: Xiaogang Chen Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher (cherry picked from commit ca5d4db8db843be7ed35fc9334737490c2b58d32) --- drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index d2237ce9da70..1485f4789440 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -375,7 +375,7 @@ void amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset, * @start_page: first page to map in the GART aperture * @num_pages: number of pages to be mapped * @flags: page table entry flags - * @dst: CPU address of the GART table + * @dst: valid CPU address of GART table, cannot be null * * Binds a BO that is allocated in VRAM to the GART page table * (all ASICs). @@ -396,7 +396,7 @@ void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa, return; for (i = 0; i < num_pages; ++i) { - amdgpu_gmc_set_pte_pde(adev, adev->gart.ptr, + amdgpu_gmc_set_pte_pde(adev, dst, start_page + i, pa + AMDGPU_GPU_PAGE_SIZE * i, flags); } From b6dff005fcf32dd072f6f2d08ca461394a21bd4f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 9 Jan 2026 08:54:55 -0500 Subject: [PATCH 250/443] drm/amdgpu: make sure userqs are enabled in userq IOCTLs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These IOCTLs shouldn't be called when userqs are not enabled. Make sure they are enabled before executing the IOCTLs. Reviewed-by: Christian König Signed-off-by: Alex Deucher (cherry picked from commit d967509651601cddce7ff2a9f09479f3636f684d) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 16 ++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 6 ++++++ 3 files changed, 23 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 9a969175900e..58b26c78b642 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -885,12 +885,28 @@ static int amdgpu_userq_input_args_validate(struct drm_device *dev, return 0; } +bool amdgpu_userq_enabled(struct drm_device *dev) +{ + struct amdgpu_device *adev = drm_to_adev(dev); + int i; + + for (i = 0; i < AMDGPU_HW_IP_NUM; i++) { + if (adev->userq_funcs[i]) + return true; + } + + return false; +} + int amdgpu_userq_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { union drm_amdgpu_userq *args = data; int r; + if (!amdgpu_userq_enabled(dev)) + return -ENOTSUPP; + if (amdgpu_userq_input_args_validate(dev, args, filp) < 0) return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h index c37444427a14..b48b3bc293fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h @@ -141,6 +141,7 @@ uint64_t amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr, struct drm_file *filp); u32 amdgpu_userq_get_supported_ip_mask(struct amdgpu_device *adev); +bool amdgpu_userq_enabled(struct drm_device *dev); int amdgpu_userq_suspend(struct amdgpu_device *adev); int amdgpu_userq_resume(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c index eba9fb359047..53d8707f9881 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c @@ -471,6 +471,9 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data, struct drm_exec exec; u64 wptr; + if (!amdgpu_userq_enabled(dev)) + return -ENOTSUPP; + num_syncobj_handles = args->num_syncobj_handles; syncobj_handles = memdup_user(u64_to_user_ptr(args->syncobj_handles), size_mul(sizeof(u32), num_syncobj_handles)); @@ -653,6 +656,9 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, int r, i, rentry, wentry, cnt; struct drm_exec exec; + if (!amdgpu_userq_enabled(dev)) + return -ENOTSUPP; + num_read_bo_handles = wait_info->num_bo_read_handles; bo_handles_read = memdup_user(u64_to_user_ptr(wait_info->bo_read_handles), size_mul(sizeof(u32), num_read_bo_handles)); From 80614c509810fc051312d1a7ccac8d0012d6b8d0 Mon Sep 17 00:00:00 2001 From: Haoxiang Li Date: Thu, 8 Jan 2026 15:18:22 +0800 Subject: [PATCH 251/443] drm/amdkfd: fix a memory leak in device_queue_manager_init() If dqm->ops.initialize() fails, add deallocate_hiq_sdma_mqd() to release the memory allocated by allocate_hiq_sdma_mqd(). Move deallocate_hiq_sdma_mqd() up to ensure proper function visibility at the point of use. Fixes: 11614c36bc8f ("drm/amdkfd: Allocate MQD trunk for HIQ and SDMA") Signed-off-by: Haoxiang Li Signed-off-by: Felix Kuehling Reviewed-by: Oak Zeng Reviewed-by: Felix Kuehling Signed-off-by: Alex Deucher (cherry picked from commit b7cccc8286bb9919a0952c812872da1dcfe9d390) Cc: stable@vger.kernel.org --- .../drm/amd/amdkfd/kfd_device_queue_manager.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index d7a2e7178ea9..8af0929ca40a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -2919,6 +2919,14 @@ static int allocate_hiq_sdma_mqd(struct device_queue_manager *dqm) return retval; } +static void deallocate_hiq_sdma_mqd(struct kfd_node *dev, + struct kfd_mem_obj *mqd) +{ + WARN(!mqd, "No hiq sdma mqd trunk to free"); + + amdgpu_amdkfd_free_gtt_mem(dev->adev, &mqd->gtt_mem); +} + struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev) { struct device_queue_manager *dqm; @@ -3042,19 +3050,14 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev) return dqm; } + if (!dev->kfd->shared_resources.enable_mes) + deallocate_hiq_sdma_mqd(dev, &dqm->hiq_sdma_mqd); + out_free: kfree(dqm); return NULL; } -static void deallocate_hiq_sdma_mqd(struct kfd_node *dev, - struct kfd_mem_obj *mqd) -{ - WARN(!mqd, "No hiq sdma mqd trunk to free"); - - amdgpu_amdkfd_free_gtt_mem(dev->adev, &mqd->gtt_mem); -} - void device_queue_manager_uninit(struct device_queue_manager *dqm) { dqm->ops.stop(dqm); From 0a1253ba5096f531eaaef40caa4c069da6ad48ae Mon Sep 17 00:00:00 2001 From: "Mario Limonciello (AMD)" Date: Sun, 14 Dec 2025 08:59:16 -0600 Subject: [PATCH 252/443] drm/amd/display: Show link name in PSR status message [Why] The PSR message was moved in commit 4321742c394e ("drm/amd/display: Move PSR support message into amdgpu_dm"). This message however shows for every single link without showing which link is which. This can send a confusing message to the user. [How] Add link name into the message. Fixes: 4321742c394e ("drm/amd/display: Move PSR support message into amdgpu_dm") Reviewed-by: Alex Hung Signed-off-by: Mario Limonciello (AMD) Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher (cherry picked from commit 99f77f6229c0766b980ae05affcf9f742d97de6a) --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 740711ac1037..936c3bc3f2d6 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5626,7 +5626,8 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) if (psr_feature_enabled) { amdgpu_dm_set_psr_caps(link); - drm_info(adev_to_drm(adev), "PSR support %d, DC PSR ver %d, sink PSR ver %d DPCD caps 0x%x su_y_granularity %d\n", + drm_info(adev_to_drm(adev), "%s: PSR support %d, DC PSR ver %d, sink PSR ver %d DPCD caps 0x%x su_y_granularity %d\n", + aconnector->base.name, link->psr_settings.psr_feature_enabled, link->psr_settings.psr_version, link->dpcd_caps.psr_info.psr_version, From fee50077656d8a58011f13bca48f743d1b6d6015 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 15 Dec 2025 14:08:30 -0600 Subject: [PATCH 253/443] drm/amd/display: Bump the HDMI clock to 340MHz [Why] DP-HDMI dongles can execeed bandwidth requirements on high resolution monitors. This can lead to pruning the high resolution modes. HDMI 1.3 bumped the clock to 340MHz, but display code never matched it. [How] Set default to (DVI) 165MHz. Once HDMI display is identified update to 340MHz. Reported-by: Dianne Skoll Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4780 Reviewed-by: Chris Park Signed-off-by: Mario Limonciello Signed-off-by: Matthew Stewart Tested-by: Dan Wheeler Signed-off-by: Alex Deucher (cherry picked from commit ac1e65d8ade46c09fb184579b81acadf36dcb91e) Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h | 2 +- drivers/gpu/drm/amd/display/dc/link/link_detection.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h index b015e80672ec..fcd3ab4b0045 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hdmi_types.h @@ -41,7 +41,7 @@ /* kHZ*/ #define DP_ADAPTOR_DVI_MAX_TMDS_CLK 165000 /* kHZ*/ -#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 165000 +#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 340000 struct dp_hdmi_dongle_signature_data { int8_t id[15];/* "DP-HDMI ADAPTOR"*/ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index e1940b8e5bc3..7fa6bc97a919 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -336,7 +336,7 @@ static void query_dp_dual_mode_adaptor( /* Assume we have no valid DP passive dongle connected */ *dongle = DISPLAY_DONGLE_NONE; - sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK; + sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK; /* Read DP-HDMI dongle I2c (no response interpreted as DP-DVI dongle)*/ if (!i2c_read( @@ -392,6 +392,8 @@ static void query_dp_dual_mode_adaptor( } } + if (is_valid_hdmi_signature) + sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK; if (is_type2_dongle) { uint32_t max_tmds_clk = From 52d3d115e9cc975b90b1fc49abf6d36ad5e8847a Mon Sep 17 00:00:00 2001 From: Vivek Das Mohapatra Date: Mon, 12 Jan 2026 15:28:56 +0000 Subject: [PATCH 254/443] drm/amd/display: Initialise backlight level values from hw Internal backlight levels are initialised from ACPI but the values are sometimes out of sync with the levels in effect until there has been a read from hardware (eg triggered by reading from sysfs). This means that the first drm_commit can cause the levels to be set to a different value than the actual starting one, which results in a sudden change in brightness. This path shows the problem (when the values are out of sync): amdgpu_dm_atomic_commit_tail() -> amdgpu_dm_commit_streams() -> amdgpu_dm_backlight_set_level(..., dm->brightness[n]) This patch calls the backlight ops get_brightness explicitly at the end of backlight registration to make sure dm->brightness[n] is in sync with the actual hardware levels. Fixes: 2fe87f54abdc ("drm/amd/display: Set default brightness according to ACPI") Signed-off-by: Vivek Das Mohapatra Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Alex Deucher (cherry picked from commit 318b1c36d82a0cd2b06a4bb43272fa6f1bc8adc1) Cc: stable@vger.kernel.org --- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 936c3bc3f2d6..fae88ce8327f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -5266,6 +5266,8 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) struct amdgpu_dm_backlight_caps *caps; char bl_name[16]; int min, max; + int real_brightness; + int init_brightness; if (aconnector->bl_idx == -1) return; @@ -5290,6 +5292,8 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) } else props.brightness = props.max_brightness = MAX_BACKLIGHT_LEVEL; + init_brightness = props.brightness; + if (caps->data_points && !(amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE)) { drm_info(drm, "Using custom brightness curve\n"); props.scale = BACKLIGHT_SCALE_NON_LINEAR; @@ -5308,8 +5312,20 @@ amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) if (IS_ERR(dm->backlight_dev[aconnector->bl_idx])) { drm_err(drm, "DM: Backlight registration failed!\n"); dm->backlight_dev[aconnector->bl_idx] = NULL; - } else + } else { + /* + * dm->brightness[x] can be inconsistent just after startup until + * ops.get_brightness is called. + */ + real_brightness = + amdgpu_dm_backlight_ops.get_brightness(dm->backlight_dev[aconnector->bl_idx]); + + if (real_brightness != init_brightness) { + dm->actual_brightness[aconnector->bl_idx] = real_brightness; + dm->brightness[aconnector->bl_idx] = real_brightness; + } drm_dbg_driver(drm, "DM: Registered Backlight device: %s\n", bl_name); + } } static int initialize_plane(struct amdgpu_display_manager *dm, From 90dbc0bc2aa60021615969841fed06790c992bde Mon Sep 17 00:00:00 2001 From: Yang Wang Date: Tue, 6 Jan 2026 14:42:40 +0800 Subject: [PATCH 255/443] drm/amd/pm: fix smu overdrive data type wrong issue on smu 14.0.2 resolving the issue of incorrect type definitions potentially causing calculation errors. Fixes: 54f7f3ca982a ("drm/amdgpu/swm14: Update power limit logic") Signed-off-by: Yang Wang Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher (cherry picked from commit e3a03d0ae16d6b56e893cce8e52b44140e1ed985) --- drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index 33c3cd2e1e24..d7642d388bc3 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -1702,8 +1702,9 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu, table_context->power_play_table; PPTable_t *pptable = table_context->driver_pptable; CustomSkuTable_t *skutable = &pptable->CustomSkuTable; - uint32_t power_limit, od_percent_upper = 0, od_percent_lower = 0; + int16_t od_percent_upper = 0, od_percent_lower = 0; uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; + uint32_t power_limit; if (smu_v14_0_get_current_power_limit(smu, &power_limit)) power_limit = smu->adev->pm.ac_power ? From 0bea77b13b7649710108e6b67937ab4c7f8a9363 Mon Sep 17 00:00:00 2001 From: Prike Liang Date: Tue, 6 Jan 2026 17:00:57 +0800 Subject: [PATCH 256/443] drm/amdgpu: validate the flush_gpu_tlb_pasid() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Validate flush_gpu_tlb_pasid() availability before flushing tlb. Signed-off-by: Prike Liang Reviewed-by: Christian König Signed-off-by: Alex Deucher (cherry picked from commit f4db9913e4d3dabe9ff3ea6178f2c1bc286012b8) --- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 869bceb0fe2c..8924380086c8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -732,6 +732,10 @@ int amdgpu_gmc_flush_gpu_tlb_pasid(struct amdgpu_device *adev, uint16_t pasid, return 0; if (!adev->gmc.flush_pasid_uses_kiq || !ring->sched.ready) { + + if (!adev->gmc.gmc_funcs->flush_gpu_tlb_pasid) + return 0; + if (adev->gmc.flush_tlb_needs_extra_type_2) adev->gmc.gmc_funcs->flush_gpu_tlb_pasid(adev, pasid, 2, all_hub, From 808c2052f046d730a588f7b92b04a12f64970853 Mon Sep 17 00:00:00 2001 From: Prike Liang Date: Fri, 9 Jan 2026 16:15:11 +0800 Subject: [PATCH 257/443] Revert "drm/amdgpu: don't attach the tlb fence for SI" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 820b3d376e8a102c6aeab737ec6edebbbb710e04. It’s better to validate VM TLB flushes in the flush‑TLB backend rather than in the generic VM layer. Reverting this patch depends on commit fa7c231fc2b0 ("drm/amdgpu: validate the flush_gpu_tlb_pasid()") being present in the tree. Signed-off-by: Prike Liang Reviewed-by: Christian König Signed-off-by: Alex Deucher (cherry picked from commit 9163fe4d790fb4e16d6b0e23f55b43cddd3d4a65) --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index c362d4dfb5bb..a67285118c37 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1069,9 +1069,7 @@ amdgpu_vm_tlb_flush(struct amdgpu_vm_update_params *params, } /* Prepare a TLB flush fence to be attached to PTs */ - if (!params->unlocked && - /* SI doesn't support pasid or KIQ/MES */ - params->adev->family > AMDGPU_FAMILY_SI) { + if (!params->unlocked) { amdgpu_vm_tlb_fence_create(params->adev, vm, fence); /* Makes sure no PD/PT is freed before the flush */ From 18dbcfb46f692e665c3fe3eee804e56c4eae53d6 Mon Sep 17 00:00:00 2001 From: Harish Kasiviswanathan Date: Sun, 11 Jan 2026 16:53:18 -0500 Subject: [PATCH 258/443] drm/amdkfd: No need to suspend whole MES to evict process Each queue of the process is individually removed and there is not need to suspend whole mes. Suspending mes stops kernel mode queues also causing unnecessary timeouts when running mixed work loads Fixes: 079ae5118e1f ("drm/amdkfd: fix suspend/resume all calls in mes based eviction path") Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4765 Signed-off-by: Harish Kasiviswanathan Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher (cherry picked from commit 3fd20580b96a6e9da65b94ac3b58ee288239b731) --- .../gpu/drm/amd/amdkfd/kfd_device_queue_manager.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 8af0929ca40a..625ea8ab7a74 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -1209,14 +1209,8 @@ static int evict_process_queues_cpsch(struct device_queue_manager *dqm, pr_debug_ratelimited("Evicting process pid %d queues\n", pdd->process->lead_thread->pid); - if (dqm->dev->kfd->shared_resources.enable_mes) { + if (dqm->dev->kfd->shared_resources.enable_mes) pdd->last_evict_timestamp = get_jiffies_64(); - retval = suspend_all_queues_mes(dqm); - if (retval) { - dev_err(dev, "Suspending all queues failed"); - goto out; - } - } /* Mark all queues as evicted. Deactivate all active queues on * the qpd. @@ -1246,10 +1240,6 @@ static int evict_process_queues_cpsch(struct device_queue_manager *dqm, KFD_UNMAP_QUEUES_FILTER_ALL_QUEUES : KFD_UNMAP_QUEUES_FILTER_DYNAMIC_QUEUES, 0, USE_DEFAULT_GRACE_PERIOD); - } else { - retval = resume_all_queues_mes(dqm); - if (retval) - dev_err(dev, "Resuming all queues failed"); } out: From b2426a211dba6432e32a2e70e9183c6e134475c6 Mon Sep 17 00:00:00 2001 From: Srinivasan Shanmugam Date: Wed, 14 Jan 2026 16:14:53 +0530 Subject: [PATCH 259/443] drm/amdgpu/userq: Fix fence reference leak on queue teardown v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The user mode queue keeps a pointer to the most recent fence in userq->last_fence. This pointer holds an extra dma_fence reference. When the queue is destroyed, we free the fence driver and its xarray, but we forgot to drop the last_fence reference. Because of the missing dma_fence_put(), the last fence object can stay alive when the driver unloads. This leaves an allocated object in the amdgpu_userq_fence slab cache and triggers This is visible during driver unload as: BUG amdgpu_userq_fence: Objects remaining on __kmem_cache_shutdown() kmem_cache_destroy amdgpu_userq_fence: Slab cache still has objects Call Trace: kmem_cache_destroy amdgpu_userq_fence_slab_fini amdgpu_exit __do_sys_delete_module Fix this by putting userq->last_fence and clearing the pointer during amdgpu_userq_fence_driver_free(). This makes sure the fence reference is released and the slab cache is empty when the module exits. v2: Update to only release userq->last_fence with dma_fence_put() (Christian) Fixes: edc762a51c71 ("drm/amdgpu/userq: move some code around") Cc: Alex Deucher Cc: Christian König Signed-off-by: Srinivasan Shanmugam Reviewed-by: Christian König Signed-off-by: Alex Deucher (cherry picked from commit 8e051e38a8d45caf6a866d4ff842105b577953bb) --- drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c index 53d8707f9881..85e9edc1cb6f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c @@ -141,6 +141,8 @@ static void amdgpu_userq_walk_and_drop_fence_drv(struct xarray *xa) void amdgpu_userq_fence_driver_free(struct amdgpu_usermode_queue *userq) { + dma_fence_put(userq->last_fence); + amdgpu_userq_walk_and_drop_fence_drv(&userq->fence_drv_xa); xa_destroy(&userq->fence_drv_xa); /* Drop the fence_drv reference held by user queue */ From d04f73668bebbc5a44a2771ea92b6ec253148050 Mon Sep 17 00:00:00 2001 From: Ivan Lipski Date: Tue, 13 Jan 2026 17:29:59 -0500 Subject: [PATCH 260/443] drm/amd/display: Add an hdmi_hpd_debounce_delay_ms module [Why&How] Right now, the HDMI HPD filter is enabled by default at 1500ms. We want to disable it by default, as most modern displays with HDMI do not require it for DPMS mode. The HPD can instead be enabled as a driver parameter with a custom delay value in ms (up to 5000ms). Fixes: c918e75e1ed9 ("drm/amd/display: Add an HPD filter for HDMI") Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4859 Signed-off-by: Ivan Lipski Reviewed-by: Mario Limonciello (AMD) Signed-off-by: Alex Deucher (cherry picked from commit 6a681cd9034587fe3550868bacfbd639d1c6891f) --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 11 +++++++++++ drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 15 ++++++++++++--- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 5 ++++- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 9f9774f58ce1..b20a06abb65d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -274,6 +274,8 @@ extern int amdgpu_rebar; extern int amdgpu_wbrf; extern int amdgpu_user_queue; +extern uint amdgpu_hdmi_hpd_debounce_delay_ms; + #define AMDGPU_VM_MAX_NUM_CTX 4096 #define AMDGPU_SG_THRESHOLD (256*1024*1024) #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000 diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 848e6b7db482..6ccb80e2d7c9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -247,6 +247,7 @@ int amdgpu_damage_clips = -1; /* auto */ int amdgpu_umsch_mm_fwlog; int amdgpu_rebar = -1; /* auto */ int amdgpu_user_queue = -1; +uint amdgpu_hdmi_hpd_debounce_delay_ms; DECLARE_DYNDBG_CLASSMAP(drm_debug_classes, DD_CLASS_TYPE_DISJOINT_BITS, 0, "DRM_UT_CORE", @@ -1123,6 +1124,16 @@ module_param_named(rebar, amdgpu_rebar, int, 0444); MODULE_PARM_DESC(user_queue, "Enable user queues (-1 = auto (default), 0 = disable, 1 = enable, 2 = enable UQs and disable KQs)"); module_param_named(user_queue, amdgpu_user_queue, int, 0444); +/* + * DOC: hdmi_hpd_debounce_delay_ms (uint) + * HDMI HPD disconnect debounce delay in milliseconds. + * + * Used to filter short disconnect->reconnect HPD toggles some HDMI sinks + * generate while entering/leaving power save. Set to 0 to disable by default. + */ +MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)"); +module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644); + /* These devices are not supported by amdgpu. * They are supported by the mach64, r128, radeon drivers */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index fae88ce8327f..1ea5a250440f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -8947,9 +8947,18 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, mutex_init(&aconnector->hpd_lock); mutex_init(&aconnector->handle_mst_msg_ready); - aconnector->hdmi_hpd_debounce_delay_ms = AMDGPU_DM_HDMI_HPD_DEBOUNCE_MS; - INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, hdmi_hpd_debounce_work); - aconnector->hdmi_prev_sink = NULL; + /* + * If HDMI HPD debounce delay is set, use the minimum between selected + * value and AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS + */ + if (amdgpu_hdmi_hpd_debounce_delay_ms) { + aconnector->hdmi_hpd_debounce_delay_ms = min(amdgpu_hdmi_hpd_debounce_delay_ms, + AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS); + INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, hdmi_hpd_debounce_work); + aconnector->hdmi_prev_sink = NULL; + } else { + aconnector->hdmi_hpd_debounce_delay_ms = 0; + } /* * configure support HPD hot plug connector_>polled default value is 0 diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index bd0403005f37..beb0d04d3e68 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -59,7 +59,10 @@ #define AMDGPU_HDR_MULT_DEFAULT (0x100000000LL) -#define AMDGPU_DM_HDMI_HPD_DEBOUNCE_MS 1500 +/* + * Maximum HDMI HPD debounce delay in milliseconds + */ +#define AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS 5000 /* #include "include/amdgpu_dal_power_if.h" #include "amdgpu_dm_irq.h" From 437cc6057e01d98ee124496f045ede36224af326 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Wed, 17 Dec 2025 14:41:36 +0100 Subject: [PATCH 261/443] btrfs: remove zoned statistics from sysfs Remove the newly introduced zoned statistics from sysfs, as sysfs can only show a single page this will truncate the output on a busy filesystem. Reviewed-by: Filipe Manana Signed-off-by: Johannes Thumshirn Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/sysfs.c | 52 ------------------------------------------------ 1 file changed, 52 deletions(-) diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index 1f64c132b387..4b3c2acac51a 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c @@ -26,7 +26,6 @@ #include "misc.h" #include "fs.h" #include "accessors.h" -#include "zoned.h" /* * Structure name Path @@ -1189,56 +1188,6 @@ static ssize_t btrfs_commit_stats_store(struct kobject *kobj, } BTRFS_ATTR_RW(, commit_stats, btrfs_commit_stats_show, btrfs_commit_stats_store); -static ssize_t btrfs_zoned_stats_show(struct kobject *kobj, - struct kobj_attribute *a, char *buf) -{ - struct btrfs_fs_info *fs_info = to_fs_info(kobj); - struct btrfs_block_group *bg; - size_t ret = 0; - - - if (!btrfs_is_zoned(fs_info)) - return ret; - - spin_lock(&fs_info->zone_active_bgs_lock); - ret += sysfs_emit_at(buf, ret, "active block-groups: %zu\n", - list_count_nodes(&fs_info->zone_active_bgs)); - spin_unlock(&fs_info->zone_active_bgs_lock); - - mutex_lock(&fs_info->reclaim_bgs_lock); - spin_lock(&fs_info->unused_bgs_lock); - ret += sysfs_emit_at(buf, ret, "\treclaimable: %zu\n", - list_count_nodes(&fs_info->reclaim_bgs)); - ret += sysfs_emit_at(buf, ret, "\tunused: %zu\n", - list_count_nodes(&fs_info->unused_bgs)); - spin_unlock(&fs_info->unused_bgs_lock); - mutex_unlock(&fs_info->reclaim_bgs_lock); - - ret += sysfs_emit_at(buf, ret, "\tneed reclaim: %s\n", - str_true_false(btrfs_zoned_should_reclaim(fs_info))); - - if (fs_info->data_reloc_bg) - ret += sysfs_emit_at(buf, ret, - "data relocation block-group: %llu\n", - fs_info->data_reloc_bg); - if (fs_info->treelog_bg) - ret += sysfs_emit_at(buf, ret, - "tree-log block-group: %llu\n", - fs_info->treelog_bg); - - spin_lock(&fs_info->zone_active_bgs_lock); - ret += sysfs_emit_at(buf, ret, "active zones:\n"); - list_for_each_entry(bg, &fs_info->zone_active_bgs, active_bg_list) { - ret += sysfs_emit_at(buf, ret, - "\tstart: %llu, wp: %llu used: %llu, reserved: %llu, unusable: %llu\n", - bg->start, bg->alloc_offset, bg->used, - bg->reserved, bg->zone_unusable); - } - spin_unlock(&fs_info->zone_active_bgs_lock); - return ret; -} -BTRFS_ATTR(, zoned_stats, btrfs_zoned_stats_show); - static ssize_t btrfs_clone_alignment_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { @@ -1651,7 +1600,6 @@ static const struct attribute *btrfs_attrs[] = { BTRFS_ATTR_PTR(, bg_reclaim_threshold), BTRFS_ATTR_PTR(, commit_stats), BTRFS_ATTR_PTR(, temp_fsid), - BTRFS_ATTR_PTR(, zoned_stats), #ifdef CONFIG_BTRFS_EXPERIMENTAL BTRFS_ATTR_PTR(, offload_csum), #endif From e2fb7836b01747815f8bb94981c35f2688afb120 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Fri, 19 Dec 2025 08:40:04 +0700 Subject: [PATCH 262/443] mm: describe @flags parameter in memalloc_flags_save() Patch series "mm kernel-doc fixes". Here are kernel-doc fixes for mm subsystem. I'm also including textsearch fix since there's currently no maintainer for include/linux/textsearch.h (get_maintainer.pl only shows LKML). This patch (of 4): Sphinx reports kernel-doc warning: WARNING: ./include/linux/sched/mm.h:332 function parameter 'flags' not described in 'memalloc_flags_save' Describe @flags to fix it. Link: https://lkml.kernel.org/r/20251219014006.16328-2-bagasdotme@gmail.com Link: https://lkml.kernel.org/r/20251219014006.16328-3-bagasdotme@gmail.com Signed-off-by: Bagas Sanjaya Fixes: 3f6d5e6a468d ("mm: introduce memalloc_flags_{save,restore}") Acked-by: David Hildenbrand (Red Hat) Acked-by: Harry Yoo Signed-off-by: Andrew Morton --- include/linux/sched/mm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/sched/mm.h b/include/linux/sched/mm.h index 0e1d73955fa5..95d0040df584 100644 --- a/include/linux/sched/mm.h +++ b/include/linux/sched/mm.h @@ -325,6 +325,7 @@ static inline void might_alloc(gfp_t gfp_mask) /** * memalloc_flags_save - Add a PF_* flag to current->flags, save old value + * @flags: Flags to add. * * This allows PF_* flags to be conveniently added, irrespective of current * value, and then the old version restored with memalloc_flags_restore(). From f26528478bb102c28e7ac0cbfc8ec8185afdafc7 Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Fri, 19 Dec 2025 08:40:05 +0700 Subject: [PATCH 263/443] textsearch: describe @list member in ts_ops search Sphinx reports kernel-doc warning: WARNING: ./include/linux/textsearch.h:49 struct member 'list' not described in 'ts_ops' Describe @list member to fix it. Link: https://lkml.kernel.org/r/20251219014006.16328-4-bagasdotme@gmail.com Fixes: 2de4ff7bd658 ("[LIB]: Textsearch infrastructure.") Signed-off-by: Bagas Sanjaya Cc: Thomas Graf Cc: "David S. Miller" Signed-off-by: Andrew Morton --- include/linux/textsearch.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/textsearch.h b/include/linux/textsearch.h index 6673e4d4ac2e..4933777404d6 100644 --- a/include/linux/textsearch.h +++ b/include/linux/textsearch.h @@ -35,6 +35,7 @@ struct ts_state * @get_pattern: return head of pattern * @get_pattern_len: return length of pattern * @owner: module reference to algorithm + * @list: list to search */ struct ts_ops { From eb3f781ab73e7ed970070a0b9a7d951f980e717a Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Fri, 19 Dec 2025 08:40:06 +0700 Subject: [PATCH 264/443] mm: vmalloc: fix up vrealloc_node_align() kernel-doc macro name Sphinx reports kernel-doc warning: WARNING: ./mm/vmalloc.c:4284 expecting prototype for vrealloc_node_align_noprof(). Prototype was for vrealloc_node_align() instead Fix the macro name in vrealloc_node_align_noprof() kernel-doc comment. Link: https://lkml.kernel.org/r/20251219014006.16328-5-bagasdotme@gmail.com Fixes: 4c5d3365882d ("mm/vmalloc: allow to set node and align in vrealloc") Signed-off-by: Bagas Sanjaya Reviewed-by: Vishal Moola (Oracle) Signed-off-by: Andrew Morton --- mm/vmalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 41dd01e8430c..628f96e83b11 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -4248,7 +4248,7 @@ void *vzalloc_node_noprof(unsigned long size, int node) EXPORT_SYMBOL(vzalloc_node_noprof); /** - * vrealloc_node_align_noprof - reallocate virtually contiguous memory; contents + * vrealloc_node_align - reallocate virtually contiguous memory; contents * remain unchanged * @p: object to reallocate memory for * @size: the size to reallocate From 6cfab50e1440fde19af7c614aacd85e11aa4dcea Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Fri, 19 Dec 2025 08:40:07 +0700 Subject: [PATCH 265/443] mm, kfence: describe @slab parameter in __kfence_obj_info() Sphinx reports kernel-doc warning: WARNING: ./include/linux/kfence.h:220 function parameter 'slab' not described in '__kfence_obj_info' Fix it by describing @slab parameter. Link: https://lkml.kernel.org/r/20251219014006.16328-6-bagasdotme@gmail.com Fixes: 2dfe63e61cc3 ("mm, kfence: support kmem_dump_obj() for KFENCE objects") Signed-off-by: Bagas Sanjaya Acked-by: Marco Elver Acked-by: David Hildenbrand (Red Hat) Acked-by: Harry Yoo Signed-off-by: Andrew Morton --- include/linux/kfence.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/kfence.h b/include/linux/kfence.h index 0ad1ddbb8b99..e5822f6e7f27 100644 --- a/include/linux/kfence.h +++ b/include/linux/kfence.h @@ -211,6 +211,7 @@ struct kmem_obj_info; * __kfence_obj_info() - fill kmem_obj_info struct * @kpp: kmem_obj_info to be filled * @object: the object + * @slab: the slab * * Return: * * false - not a KFENCE object From aba744a2e4b23c2040e335db35c141b95915efbd Mon Sep 17 00:00:00 2001 From: Szymon Wilczek Date: Sun, 21 Dec 2025 16:17:10 +0100 Subject: [PATCH 266/443] mailmap: update email address for Szymon Wilczek Map my old address to my new address . The old account is no longer accessible due to provider blocking access. Link: https://lkml.kernel.org/r/20251221151710.13747-1-swilczek.lx@gmail.com Signed-off-by: Szymon Wilczek Signed-off-by: Andrew Morton --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index fa018b5bd533..bc94004bc4c2 100644 --- a/.mailmap +++ b/.mailmap @@ -794,6 +794,7 @@ Sven Eckelmann Sven Eckelmann Sven Eckelmann Sven Peter +Szymon Wilczek Takashi YOSHII Tamizh Chelvam Raja Taniya Das From 6ac166a0c8b8aca2a2d796aec1e3c110f4e3300d Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Mon, 22 Dec 2025 16:00:06 +0100 Subject: [PATCH 267/443] docs: kernel-parameters: add kfence parameters Add a brief summary for KFENCE's kernel command-line parameters in admin-guide/kernel-parameters. Link: https://lkml.kernel.org/r/20251222150018.1349672-1-elver@google.com Signed-off-by: Marco Elver Cc: Alexander Potapenko Cc: Dmitriy Vyukov Cc: Jonathan Corbet Signed-off-by: Andrew Morton --- .../admin-guide/kernel-parameters.txt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index a8d0afde7f85..1058f2a6d6a8 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2917,6 +2917,41 @@ Kernel parameters for Movable pages. "nn[KMGTPE]", "nn%", and "mirror" are exclusive, so you cannot specify multiple forms. + kfence.burst= [MM,KFENCE] The number of additional successive + allocations to be attempted through KFENCE for each + sample interval. + Format: + Default: 0 + + kfence.check_on_panic= + [MM,KFENCE] Whether to check all KFENCE-managed objects' + canaries on panic. + Format: + Default: false + + kfence.deferrable= + [MM,KFENCE] Whether to use a deferrable timer to trigger + allocations. This avoids forcing CPU wake-ups if the + system is idle, at the risk of a less predictable + sample interval. + Format: + Default: CONFIG_KFENCE_DEFERRABLE + + kfence.sample_interval= + [MM,KFENCE] KFENCE's sample interval in milliseconds. + Format: + 0 - Disable KFENCE. + >0 - Enabled KFENCE with given sample interval. + Default: CONFIG_KFENCE_SAMPLE_INTERVAL + + kfence.skip_covered_thresh= + [MM,KFENCE] If pool utilization reaches this threshold + (pool usage%), KFENCE limits currently covered + allocations of the same source from further filling + up the pool. + Format: + Default: 75 + kgdbdbgp= [KGDB,HW,EARLY] kgdb over EHCI usb debug port. Format: [,poll interval] The controller # is the number of the ehci usb debug From 777a8560fd29738350c5094d4166fe5499452409 Mon Sep 17 00:00:00 2001 From: Shakeel Butt Date: Mon, 22 Dec 2025 12:58:59 -0800 Subject: [PATCH 268/443] lib/buildid: use __kernel_read() for sleepable context Prevent a "BUG: unable to handle kernel NULL pointer dereference in filemap_read_folio". For the sleepable context, convert freader to use __kernel_read() instead of direct page cache access via read_cache_folio(). This simplifies the faultable code path by using the standard kernel file reading interface which handles all the complexity of reading file data. At the moment we are not changing the code for non-sleepable context which uses filemap_get_folio() and only succeeds if the target folios are already in memory and up-to-date. The reason is to keep the patch simple and easier to backport to stable kernels. Syzbot repro does not crash the kernel anymore and the selftests run successfully. In the follow up we will make __kernel_read() with IOCB_NOWAIT work for non-sleepable contexts. In addition, I would like to replace the secretmem check with a more generic approach and will add fstest for the buildid code. Link: https://lkml.kernel.org/r/20251222205859.3968077-1-shakeel.butt@linux.dev Fixes: ad41251c290d ("lib/buildid: implement sleepable build_id_parse() API") Reported-by: syzbot+09b7d050e4806540153d@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=09b7d050e4806540153d Signed-off-by: Shakeel Butt Reviewed-by: Christoph Hellwig Tested-by: Jinchao Wang Link: https://lkml.kernel.org/r/aUteBPWPYzVWIZFH@ndev Reviewed-by: Christian Brauner Cc: Alexei Starovoitov Cc: Andrii Nakryiko Cc: Daniel Borkman Cc: "Darrick J. Wong" Cc: Matthew Wilcox (Oracle) Cc: Signed-off-by: Andrew Morton --- lib/buildid.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/lib/buildid.c b/lib/buildid.c index aaf61dfc0919..818331051afe 100644 --- a/lib/buildid.c +++ b/lib/buildid.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #define BUILD_ID 3 @@ -46,20 +47,9 @@ static int freader_get_folio(struct freader *r, loff_t file_off) freader_put_folio(r); - /* reject secretmem folios created with memfd_secret() */ - if (secretmem_mapping(r->file->f_mapping)) - return -EFAULT; - + /* only use page cache lookup - fail if not already cached */ r->folio = filemap_get_folio(r->file->f_mapping, file_off >> PAGE_SHIFT); - /* if sleeping is allowed, wait for the page, if necessary */ - if (r->may_fault && (IS_ERR(r->folio) || !folio_test_uptodate(r->folio))) { - filemap_invalidate_lock_shared(r->file->f_mapping); - r->folio = read_cache_folio(r->file->f_mapping, file_off >> PAGE_SHIFT, - NULL, r->file); - filemap_invalidate_unlock_shared(r->file->f_mapping); - } - if (IS_ERR(r->folio) || !folio_test_uptodate(r->folio)) { if (!IS_ERR(r->folio)) folio_put(r->folio); @@ -97,6 +87,24 @@ const void *freader_fetch(struct freader *r, loff_t file_off, size_t sz) return r->data + file_off; } + /* reject secretmem folios created with memfd_secret() */ + if (secretmem_mapping(r->file->f_mapping)) { + r->err = -EFAULT; + return NULL; + } + + /* use __kernel_read() for sleepable context */ + if (r->may_fault) { + ssize_t ret; + + ret = __kernel_read(r->file, r->buf, sz, &file_off); + if (ret != sz) { + r->err = (ret < 0) ? ret : -EIO; + return NULL; + } + return r->buf; + } + /* fetch or reuse folio for given file offset */ r->err = freader_get_folio(r, file_off); if (r->err) From 582f0f3864110e1c6e4af3af768e1c2453ba2306 Mon Sep 17 00:00:00 2001 From: Pasha Tatashin Date: Tue, 23 Dec 2025 09:01:40 -0500 Subject: [PATCH 269/443] kho: validate preserved memory map during population If the previous kernel enabled KHO but did not call kho_finalize() (e.g., CONFIG_LIVEUPDATE=n or userspace skipped the finalization step), the 'preserved-memory-map' property in the FDT remains empty/zero. Previously, kho_populate() would succeed regardless of the memory map's state, reserving the incoming scratch regions in memblock. However, kho_memory_init() would later fail to deserialize the empty map. By that time, the scratch regions were already registered, leading to partial initialization and subsequent list corruption (freeing scratch area twice) during kho_init(). Move the validation of the preserved memory map earlier into kho_populate(). If the memory map is empty/NULL: 1. Abort kho_populate() immediately with -ENOENT. 2. Do not register or reserve the incoming scratch memory, allowing the new kernel to reclaim those pages as standard free memory. 3. Leave the global 'kho_in' state uninitialized. Consequently, kho_memory_init() sees no active KHO context (kho_in.mem_chunks_phys is 0) and falls back to kho_reserve_scratch(), allocating fresh scratch memory as if it were a standard cold boot. Link: https://lkml.kernel.org/r/20251223140140.2090337-1-pasha.tatashin@soleen.com Fixes: de51999e687c ("kho: allow memory preservation state updates after finalization") Signed-off-by: Pasha Tatashin Reported-by: Ricardo Neri Closes: https://lore.kernel.org/all/20251218215613.GA17304@ranerica-svr.sc.intel.com Reviewed-by: Mike Rapoport (Microsoft) Tested-by: Ricardo Neri Reviewed-by: Pratyush Yadav Cc: Alexander Graf Signed-off-by: Andrew Morton --- kernel/liveupdate/kexec_handover.c | 37 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c index 9dc51fab604f..d4482b6e3cae 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -460,27 +460,23 @@ static void __init deserialize_bitmap(unsigned int order, } } -/* Return true if memory was deserizlied */ -static bool __init kho_mem_deserialize(const void *fdt) +/* Returns physical address of the preserved memory map from FDT */ +static phys_addr_t __init kho_get_mem_map_phys(const void *fdt) { - struct khoser_mem_chunk *chunk; const void *mem_ptr; - u64 mem; int len; mem_ptr = fdt_getprop(fdt, 0, PROP_PRESERVED_MEMORY_MAP, &len); if (!mem_ptr || len != sizeof(u64)) { pr_err("failed to get preserved memory bitmaps\n"); - return false; + return 0; } - mem = get_unaligned((const u64 *)mem_ptr); - chunk = mem ? phys_to_virt(mem) : NULL; - - /* No preserved physical pages were passed, no deserialization */ - if (!chunk) - return false; + return get_unaligned((const u64 *)mem_ptr); +} +static void __init kho_mem_deserialize(struct khoser_mem_chunk *chunk) +{ while (chunk) { unsigned int i; @@ -489,8 +485,6 @@ static bool __init kho_mem_deserialize(const void *fdt) &chunk->bitmaps[i]); chunk = KHOSER_LOAD_PTR(chunk->hdr.next); } - - return true; } /* @@ -1253,6 +1247,7 @@ bool kho_finalized(void) struct kho_in { phys_addr_t fdt_phys; phys_addr_t scratch_phys; + phys_addr_t mem_map_phys; struct kho_debugfs dbg; }; @@ -1434,12 +1429,10 @@ static void __init kho_release_scratch(void) void __init kho_memory_init(void) { - if (kho_in.scratch_phys) { + if (kho_in.mem_map_phys) { kho_scratch = phys_to_virt(kho_in.scratch_phys); kho_release_scratch(); - - if (!kho_mem_deserialize(kho_get_fdt())) - kho_in.fdt_phys = 0; + kho_mem_deserialize(phys_to_virt(kho_in.mem_map_phys)); } else { kho_reserve_scratch(); } @@ -1448,8 +1441,9 @@ void __init kho_memory_init(void) void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t scratch_phys, u64 scratch_len) { - void *fdt = NULL; struct kho_scratch *scratch = NULL; + phys_addr_t mem_map_phys; + void *fdt = NULL; int err = 0; unsigned int scratch_cnt = scratch_len / sizeof(*kho_scratch); @@ -1475,6 +1469,12 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len, goto out; } + mem_map_phys = kho_get_mem_map_phys(fdt); + if (!mem_map_phys) { + err = -ENOENT; + goto out; + } + scratch = early_memremap(scratch_phys, scratch_len); if (!scratch) { pr_warn("setup: failed to memremap scratch (phys=0x%llx, len=%lld)\n", @@ -1515,6 +1515,7 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len, kho_in.fdt_phys = fdt_phys; kho_in.scratch_phys = scratch_phys; + kho_in.mem_map_phys = mem_map_phys; kho_scratch_cnt = scratch_cnt; pr_info("found kexec handover data.\n"); From a38be546269073bf8edc3c49eaf18cdfce905777 Mon Sep 17 00:00:00 2001 From: Shakeel Butt Date: Wed, 24 Dec 2025 16:29:04 -0800 Subject: [PATCH 270/443] mm/damon/core: get memcg reference before access The commit b74a120bcf507 ("mm/damon/core: implement DAMOS_QUOTA_NODE_MEMCG_USED_BP") added accesses to memcg structure without getting reference to it. This is unsafe. Let's get the reference before accessing the memcg. Link: https://lkml.kernel.org/r/20251225002904.139543-1-shakeel.butt@linux.dev Fixes: b74a120bcf507 ("mm/damon/core: implement DAMOS_QUOTA_NODE_MEMCG_USED_BP") Signed-off-by: Shakeel Butt Reviewed-by: SeongJae Park Signed-off-by: Andrew Morton --- mm/damon/core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mm/damon/core.c b/mm/damon/core.c index f9fc0375890a..fd09bd106ad5 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -2051,13 +2051,15 @@ static unsigned long damos_get_node_memcg_used_bp( rcu_read_lock(); memcg = mem_cgroup_from_id(goal->memcg_id); - rcu_read_unlock(); - if (!memcg) { + if (!memcg || !mem_cgroup_tryget(memcg)) { + rcu_read_unlock(); if (goal->metric == DAMOS_QUOTA_NODE_MEMCG_USED_BP) return 0; else /* DAMOS_QUOTA_NODE_MEMCG_FREE_BP */ return 10000; } + rcu_read_unlock(); + mem_cgroup_flush_stats(memcg); lruvec = mem_cgroup_lruvec(memcg, NODE_DATA(goal->nid)); used_pages = lruvec_page_state(lruvec, NR_ACTIVE_ANON); @@ -2065,6 +2067,8 @@ static unsigned long damos_get_node_memcg_used_bp( used_pages += lruvec_page_state(lruvec, NR_ACTIVE_FILE); used_pages += lruvec_page_state(lruvec, NR_INACTIVE_FILE); + mem_cgroup_put(memcg); + si_meminfo_node(&i, goal->nid); if (goal->metric == DAMOS_QUOTA_NODE_MEMCG_USED_BP) numerator = used_pages; From b9efe36b5e3eb2e91aa3d706066428648af034fc Mon Sep 17 00:00:00 2001 From: Aboorva Devarajan Date: Mon, 1 Dec 2025 11:30:09 +0530 Subject: [PATCH 271/443] mm/page_alloc: make percpu_pagelist_high_fraction reads lock-free When page isolation loops indefinitely during memory offline, reading /proc/sys/vm/percpu_pagelist_high_fraction blocks on pcp_batch_high_lock, causing hung task warnings. Make procfs reads lock-free since percpu_pagelist_high_fraction is a simple integer with naturally atomic reads, writers still serialize via the mutex. This prevents hung task warnings when reading the procfs file during long-running memory offline operations. [akpm@linux-foundation.org: add comment, per Michal] Link: https://lkml.kernel.org/r/aS_y9AuJQFydLEXo@tiehlicka Link: https://lkml.kernel.org/r/20251201060009.1420792-1-aboorvad@linux.ibm.com Signed-off-by: Aboorva Devarajan Acked-by: Michal Hocko Cc: Brendan Jackman Cc: Johannes Weiner Cc: Suren Baghdasaryan Cc: Vlastimil Babka Cc: Zi Yan Cc: Signed-off-by: Andrew Morton --- mm/page_alloc.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index c380f063e8b7..3dce96f3be49 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -6667,11 +6667,19 @@ static int percpu_pagelist_high_fraction_sysctl_handler(const struct ctl_table * int old_percpu_pagelist_high_fraction; int ret; + /* + * Avoid using pcp_batch_high_lock for reads as the value is read + * atomically and a race with offlining is harmless. + */ + + if (!write) + return proc_dointvec_minmax(table, write, buffer, length, ppos); + mutex_lock(&pcp_batch_high_lock); old_percpu_pagelist_high_fraction = percpu_pagelist_high_fraction; ret = proc_dointvec_minmax(table, write, buffer, length, ppos); - if (!write || ret < 0) + if (ret < 0) goto out; /* Sanity checking to avoid pcp imbalance */ From b02019169284df8f4ce972a60da31d28bd5b5979 Mon Sep 17 00:00:00 2001 From: Sourabh Jain Date: Wed, 24 Dec 2025 17:25:24 +0530 Subject: [PATCH 272/443] mm/hugetlb: ignore hugepage kernel args if hugepages are unsupported Skip processing hugepage kernel arguments (hugepagesz, hugepages, and default_hugepagesz) when hugepages are not supported by the architecture. Some architectures may need to disable hugepages based on conditions discovered during kernel boot. The hugepages_supported() helper allows architecture code to advertise whether hugepages are supported. Currently, normal hugepage allocation is guarded by hugepages_supported(), but gigantic hugepages are allocated regardless of this check. This causes problems on powerpc for fadump (firmware- assisted dump). In the fadump (firmware-assisted dump) scenario, a production kernel crash causes the system to boot into a special kernel whose sole purpose is to collect the memory dump and reboot. Features such as hugepages are not required in this environment and should be disabled. For example, when the fadump kernel boots with the following kernel arguments: default_hugepagesz=1GB hugepagesz=1GB hugepages=200 Before this patch, the kernel prints the following logs: HugeTLB: allocating 200 of page size 1.00 GiB failed. Only allocated 58 hugepages. HugeTLB support is disabled! HugeTLB: huge pages not supported, ignoring associated command-line parameters hugetlbfs: disabling because there are no supported hugepage sizes Even though the logs state that HugeTLB support is disabled, gigantic hugepages are still allocated. This causes the fadump kernel to run out of memory during boot. After this patch is applied, the kernel prints the following logs for the same command line: HugeTLB: hugepages unsupported, ignoring default_hugepagesz=1GB cmdline HugeTLB: hugepages unsupported, ignoring hugepagesz=1GB cmdline HugeTLB: hugepages unsupported, ignoring hugepages=200 cmdline HugeTLB support is disabled! hugetlbfs: disabling because there are no supported hugepage sizes To fix the issue, gigantic hugepage allocation should be guarded by hugepages_supported(). Previously, two approaches were proposed to bring gigantic hugepage allocation under hugepages_supported(): [1] Check hugepages_supported() in the generic code before allocating gigantic hugepages [2] Make arch_hugetlb_valid_size() return false for all hugetlb sizes Approach [2] has two minor issues: 1. It prints misleading logs about invalid hugepage sizes 2. The kernel still processes hugepage kernel arguments unnecessarily To control gigantic hugepage allocation, skip processing hugepage kernel arguments (default_hugepagesz, hugepagesz and hugepages) when hugepages_supported() returns false. Note for backporting: This fix is a partial reversion of the commit mentioned in the Fixes tag and is only valid once the change referenced by the Depends-on tag is present. When backporting this patch, the commit mentioned in the Depends-on tag must be included first. Link: https://lore.kernel.org/all/20250121150419.1342794-1-sourabhjain@linux.ibm.com/ [1] Link: https://lore.kernel.org/all/20250128043358.163372-1-sourabhjain@linux.ibm.com/ [2] Link: https://lkml.kernel.org/r/20251224115524.1272010-1-sourabhjain@linux.ibm.com Fixes: c2833a5bf75b ("hugetlbfs: fix changes to command line processing") Signed-off-by: Sourabh Jain Depends-on: 2354ad252b66 ("powerpc/mm: Update default hugetlb size early") Acked-by: David Hildenbrand (Red Hat) Reviewed-by: Ritesh Harjani (IBM) Cc: Borislav Petkov Cc: Christophe Leroy Cc: Heiko Carstens Cc: Ingo Molnar Cc: Madhavan Srinivasan Cc: Michael Ellerman Cc: Muchun Song Cc: Oscar Salvador Cc: Thomas Gleixner Cc: Vasily Gorbik Signed-off-by: Andrew Morton --- mm/hugetlb.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 51273baec9e5..e0ab14020513 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -4286,6 +4286,11 @@ static int __init hugepages_setup(char *s) unsigned long tmp; char *p = s; + if (!hugepages_supported()) { + pr_warn("HugeTLB: hugepages unsupported, ignoring hugepages=%s cmdline\n", s); + return 0; + } + if (!parsed_valid_hugepagesz) { pr_warn("HugeTLB: hugepages=%s does not follow a valid hugepagesz, ignoring\n", s); parsed_valid_hugepagesz = true; @@ -4366,6 +4371,11 @@ static int __init hugepagesz_setup(char *s) unsigned long size; struct hstate *h; + if (!hugepages_supported()) { + pr_warn("HugeTLB: hugepages unsupported, ignoring hugepagesz=%s cmdline\n", s); + return 0; + } + parsed_valid_hugepagesz = false; size = (unsigned long)memparse(s, NULL); @@ -4414,6 +4424,12 @@ static int __init default_hugepagesz_setup(char *s) unsigned long size; int i; + if (!hugepages_supported()) { + pr_warn("HugeTLB: hugepages unsupported, ignoring default_hugepagesz=%s cmdline\n", + s); + return 0; + } + parsed_valid_hugepagesz = false; if (parsed_default_hugepagesz) { pr_err("HugeTLB: default_hugepagesz previously specified, ignoring %s\n", s); From f171b55f1441294344b86edfeaa575ea9673fd23 Mon Sep 17 00:00:00 2001 From: "Mike Rapoport (Microsoft)" Date: Wed, 31 Dec 2025 12:57:01 +0200 Subject: [PATCH 273/443] mips: fix HIGHMEM initialization Commit 6faea3422e3b ("arch, mm: streamline HIGHMEM freeing") overzealously removed mem_init_free_highmem() function that beside freeing high memory pages checked for CPU support for high memory as a prerequisite. Partially restore mem_init_free_highmem() with a new highmem_init() name and make it discard high memory in case there is no CPU support for it. Link: https://lkml.kernel.org/r/20251231105701.519711-1-rppt@kernel.org Fixes: 6faea3422e3b ("arch, mm: streamline HIGHMEM freeing") Signed-off-by: Mike Rapoport (Microsoft) Reported-by: Markus Stockhausen Cc: Chris Packham Cc: Hauke Mehrtens Cc: Jonas Jelonek Cc: Thomas Bogendoerfer Cc: Thomas Gleinxer Signed-off-by: Andrew Morton --- arch/mips/mm/init.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index a673d3d68254..8986048f9b11 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -425,6 +425,28 @@ void __init paging_init(void) static struct kcore_list kcore_kseg0; #endif +static inline void __init highmem_init(void) +{ +#ifdef CONFIG_HIGHMEM + unsigned long tmp; + + /* + * If CPU cannot support HIGHMEM discard the memory above highstart_pfn + */ + if (cpu_has_dc_aliases) { + memblock_remove(PFN_PHYS(highstart_pfn), -1); + return; + } + + for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) { + struct page *page = pfn_to_page(tmp); + + if (!memblock_is_memory(PFN_PHYS(tmp))) + SetPageReserved(page); + } +#endif +} + void __init arch_mm_preinit(void) { /* @@ -435,6 +457,7 @@ void __init arch_mm_preinit(void) maar_init(); setup_zero_pages(); /* Setup zeroed pages. */ + highmem_init(); #ifdef CONFIG_64BIT if ((unsigned long) &_text > (unsigned long) CKSEG0) From e561383a39ed6e5c85a0b2369720743b694327ae Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Wed, 31 Dec 2025 16:03:09 +0800 Subject: [PATCH 274/443] powerpc/watchdog: add support for hardlockup_sys_info sysctl Commit a9af76a78760 ("watchdog: add sys_info sysctls to dump sys info on system lockup") adds 'hardlock_sys_info' systcl knob for general kernel watchdog to control what kinds of system debug info to be dumped on hardlockup. Add similar support in powerpc watchdog code to make the sysctl knob more general, which also fixes a compiling warning in general watchdog code reported by 0day bot. Link: https://lkml.kernel.org/r/20251231080309.39642-1-feng.tang@linux.alibaba.com Fixes: a9af76a78760 ("watchdog: add sys_info sysctls to dump sys info on system lockup") Signed-off-by: Feng Tang Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202512030920.NFKtekA7-lkp@intel.com/ Suggested-by: Petr Mladek Reviewed-by: Petr Mladek Cc: Madhavan Srinivasan Cc: Michael Ellerman Cc: Nicholas Piggin Signed-off-by: Andrew Morton --- arch/powerpc/kernel/watchdog.c | 15 ++++++++++----- include/linux/nmi.h | 1 + kernel/watchdog.c | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/kernel/watchdog.c b/arch/powerpc/kernel/watchdog.c index 2429cb1c7baa..764001deb060 100644 --- a/arch/powerpc/kernel/watchdog.c +++ b/arch/powerpc/kernel/watchdog.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -235,7 +236,11 @@ static void watchdog_smp_panic(int cpu) pr_emerg("CPU %d TB:%lld, last SMP heartbeat TB:%lld (%lldms ago)\n", cpu, tb, last_reset, tb_to_ns(tb - last_reset) / 1000000); - if (!sysctl_hardlockup_all_cpu_backtrace) { + if (sysctl_hardlockup_all_cpu_backtrace || + (hardlockup_si_mask & SYS_INFO_ALL_BT)) { + trigger_allbutcpu_cpu_backtrace(cpu); + cpumask_clear(&wd_smp_cpus_ipi); + } else { /* * Try to trigger the stuck CPUs, unless we are going to * get a backtrace on all of them anyway. @@ -244,11 +249,9 @@ static void watchdog_smp_panic(int cpu) smp_send_nmi_ipi(c, wd_lockup_ipi, 1000000); __cpumask_clear_cpu(c, &wd_smp_cpus_ipi); } - } else { - trigger_allbutcpu_cpu_backtrace(cpu); - cpumask_clear(&wd_smp_cpus_ipi); } + sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT); if (hardlockup_panic) nmi_panic(NULL, "Hard LOCKUP"); @@ -415,9 +418,11 @@ DEFINE_INTERRUPT_HANDLER_NMI(soft_nmi_interrupt) xchg(&__wd_nmi_output, 1); // see wd_lockup_ipi - if (sysctl_hardlockup_all_cpu_backtrace) + if (sysctl_hardlockup_all_cpu_backtrace || + (hardlockup_si_mask & SYS_INFO_ALL_BT)) trigger_allbutcpu_cpu_backtrace(cpu); + sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT); if (hardlockup_panic) nmi_panic(regs, "Hard LOCKUP"); diff --git a/include/linux/nmi.h b/include/linux/nmi.h index cf3c6ab408aa..207156f2143c 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -83,6 +83,7 @@ static inline void reset_hung_task_detector(void) { } #if defined(CONFIG_HARDLOCKUP_DETECTOR) extern void hardlockup_detector_disable(void); extern unsigned int hardlockup_panic; +extern unsigned long hardlockup_si_mask; #else static inline void hardlockup_detector_disable(void) {} #endif diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 0685e3a8aa0a..366122f4a0f8 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -71,7 +71,7 @@ unsigned int __read_mostly hardlockup_panic = * hard lockup is detected, it could be task, memory, lock etc. * Refer include/linux/sys_info.h for detailed bit definition. */ -static unsigned long hardlockup_si_mask; +unsigned long hardlockup_si_mask; #ifdef CONFIG_SYSFS From f9132fbc2e83baf2c45a77043672a63a675c9394 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Tue, 30 Dec 2025 17:23:13 -0800 Subject: [PATCH 275/443] mm/damon/core: remove call_control in inactive contexts If damon_call() is executed against a DAMON context that is not running, the function returns error while keeping the damon_call_control object linked to the context's call_controls list. Let's suppose the object is deallocated after the damon_call(), and yet another damon_call() is executed against the same context. The function tries to add the new damon_call_control object to the call_controls list, which still has the pointer to the previous damon_call_control object, which is deallocated. As a result, use-after-free happens. This can actually be triggered using the DAMON sysfs interface. It is not easily exploitable since it requires the sysfs write permission and making a definitely weird file writes, though. Please refer to the report for more details about the issue reproduction steps. Fix the issue by making two changes. Firstly, move the final kdamond_call() for cancelling all existing damon_call() requests from terminating DAMON context to be done before the ctx->kdamond reset. This makes any code that sees NULL ctx->kdamond can safely assume the context may not access damon_call() requests anymore. Secondly, let damon_call() to cleanup the damon_call_control objects that were added to the already-terminated DAMON context, before returning the error. Link: https://lkml.kernel.org/r/20251231012315.75835-1-sj@kernel.org Fixes: 004ded6bee11 ("mm/damon: accept parallel damon_call() requests") Signed-off-by: SeongJae Park Reported-by: JaeJoon Jung Closes: https://lore.kernel.org/20251224094401.20384-1-rgbi3307@gmail.com Cc: # 6.17.x Signed-off-by: Andrew Morton --- mm/damon/core.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/mm/damon/core.c b/mm/damon/core.c index fd09bd106ad5..84f80a20f233 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -1431,6 +1431,35 @@ bool damon_is_running(struct damon_ctx *ctx) return running; } +/* + * damon_call_handle_inactive_ctx() - handle DAMON call request that added to + * an inactive context. + * @ctx: The inactive DAMON context. + * @control: Control variable of the call request. + * + * This function is called in a case that @control is added to @ctx but @ctx is + * not running (inactive). See if @ctx handled @control or not, and cleanup + * @control if it was not handled. + * + * Returns 0 if @control was handled by @ctx, negative error code otherwise. + */ +static int damon_call_handle_inactive_ctx( + struct damon_ctx *ctx, struct damon_call_control *control) +{ + struct damon_call_control *c; + + mutex_lock(&ctx->call_controls_lock); + list_for_each_entry(c, &ctx->call_controls, list) { + if (c == control) { + list_del(&control->list); + mutex_unlock(&ctx->call_controls_lock); + return -EINVAL; + } + } + mutex_unlock(&ctx->call_controls_lock); + return 0; +} + /** * damon_call() - Invoke a given function on DAMON worker thread (kdamond). * @ctx: DAMON context to call the function for. @@ -1461,7 +1490,7 @@ int damon_call(struct damon_ctx *ctx, struct damon_call_control *control) list_add_tail(&control->list, &ctx->call_controls); mutex_unlock(&ctx->call_controls_lock); if (!damon_is_running(ctx)) - return -EINVAL; + return damon_call_handle_inactive_ctx(ctx, control); if (control->repeat) return 0; wait_for_completion(&control->completion); @@ -2755,13 +2784,13 @@ done: if (ctx->ops.cleanup) ctx->ops.cleanup(ctx); kfree(ctx->regions_score_histogram); + kdamond_call(ctx, true); pr_debug("kdamond (%d) finishes\n", current->pid); mutex_lock(&ctx->kdamond_lock); ctx->kdamond = NULL; mutex_unlock(&ctx->kdamond_lock); - kdamond_call(ctx, true); damos_walk_cancel(ctx); mutex_lock(&damon_lock); From a24ca8ebb0cd5ea07a1462b77be0f0823c40f319 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Wed, 24 Dec 2025 18:30:34 -0800 Subject: [PATCH 276/443] mm/damon/sysfs: cleanup intervals subdirs on attrs dir setup failure Patch series "mm/damon/sysfs: free setup failures generated zombie sub-sub dirs". Some DAMON sysfs directory setup functions generates its sub and sub-sub directories. For example, 'monitoring_attrs/' directory setup creates 'intervals/' and 'intervals/intervals_goal/' directories under 'monitoring_attrs/' directory. When such sub-sub directories are successfully made but followup setup is failed, the setup function should recursively clean up the subdirectories. However, such setup functions are only dereferencing sub directory reference counters. As a result, under certain setup failures, the sub-sub directories keep having non-zero reference counters. It means the directories cannot be removed like zombies, and the memory for the directories cannot be freed. The user impact of this issue is limited due to the following reasons. When the issue happens, the zombie directories are still taking the path. Hence attempts to generate the directories again will fail, without additional memory leak. This means the upper bound memory leak is limited. Nonetheless this also implies controlling DAMON with a feature that requires the setup-failed sysfs files will be impossible until the system reboots. Also, the setup operations are quite simple. The certain failures would hence only rarely happen, and are difficult to artificially trigger. This patch (of 4): When attrs/ DAMON sysfs directory setup is failed after setup of intervals/ directory, intervals/intervals_goal/ directory is not cleaned up. As a result, DAMON sysfs interface is nearly broken until the system reboots, and the memory for the unremoved directory is leaked. Cleanup the directory under such failures. Link: https://lkml.kernel.org/r/20251225023043.18579-1-sj@kernel.org Link: https://lkml.kernel.org/r/20251225023043.18579-2-sj@kernel.org Fixes: 8fbbcbeaafeb ("mm/damon/sysfs: implement intervals tuning goal directory") Signed-off-by: SeongJae Park Cc: chongjiapeng Cc: # 6.15.x Signed-off-by: Andrew Morton --- mm/damon/sysfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c index e2bd2d7becdd..a669de068770 100644 --- a/mm/damon/sysfs.c +++ b/mm/damon/sysfs.c @@ -792,7 +792,7 @@ static int damon_sysfs_attrs_add_dirs(struct damon_sysfs_attrs *attrs) nr_regions_range = damon_sysfs_ul_range_alloc(10, 1000); if (!nr_regions_range) { err = -ENOMEM; - goto put_intervals_out; + goto rmdir_put_intervals_out; } err = kobject_init_and_add(&nr_regions_range->kobj, @@ -806,6 +806,8 @@ static int damon_sysfs_attrs_add_dirs(struct damon_sysfs_attrs *attrs) put_nr_regions_intervals_out: kobject_put(&nr_regions_range->kobj); attrs->nr_regions_range = NULL; +rmdir_put_intervals_out: + damon_sysfs_intervals_rm_dirs(intervals); put_intervals_out: kobject_put(&intervals->kobj); attrs->intervals = NULL; From 9814cc832b88bd040fc2a1817c2b5469d0f7e862 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Wed, 24 Dec 2025 18:30:35 -0800 Subject: [PATCH 277/443] mm/damon/sysfs: cleanup attrs subdirs on context dir setup failure When a context DAMON sysfs directory setup is failed after setup of attrs/ directory, subdirectories of attrs/ directory are not cleaned up. As a result, DAMON sysfs interface is nearly broken until the system reboots, and the memory for the unremoved directory is leaked. Cleanup the directories under such failures. Link: https://lkml.kernel.org/r/20251225023043.18579-3-sj@kernel.org Fixes: c951cd3b8901 ("mm/damon: implement a minimal stub for sysfs-based DAMON interface") Signed-off-by: SeongJae Park Cc: chongjiapeng Cc: # 5.18.x Signed-off-by: Andrew Morton --- mm/damon/sysfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c index a669de068770..95fd9375a7d8 100644 --- a/mm/damon/sysfs.c +++ b/mm/damon/sysfs.c @@ -950,7 +950,7 @@ static int damon_sysfs_context_add_dirs(struct damon_sysfs_context *context) err = damon_sysfs_context_set_targets(context); if (err) - goto put_attrs_out; + goto rmdir_put_attrs_out; err = damon_sysfs_context_set_schemes(context); if (err) @@ -960,7 +960,8 @@ static int damon_sysfs_context_add_dirs(struct damon_sysfs_context *context) put_targets_attrs_out: kobject_put(&context->targets->kobj); context->targets = NULL; -put_attrs_out: +rmdir_put_attrs_out: + damon_sysfs_attrs_rm_dirs(context->attrs); kobject_put(&context->attrs->kobj); context->attrs = NULL; return err; From dc7e1d75fd8c505096d0cddeca9e2efb2b55aaf9 Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Wed, 24 Dec 2025 18:30:36 -0800 Subject: [PATCH 278/443] mm/damon/sysfs-scheme: cleanup quotas subdirs on scheme dir setup failure When a DAMOS-scheme DAMON sysfs directory setup fails after setup of quotas/ directory, subdirectories of quotas/ directory are not cleaned up. As a result, DAMON sysfs interface is nearly broken until the system reboots, and the memory for the unremoved directory is leaked. Cleanup the directories under such failures. Link: https://lkml.kernel.org/r/20251225023043.18579-4-sj@kernel.org Fixes: 1b32234ab087 ("mm/damon/sysfs: support DAMOS watermarks") Signed-off-by: SeongJae Park Cc: chongjiapeng Cc: # 5.18.x Signed-off-by: Andrew Morton --- mm/damon/sysfs-schemes.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c index 30d20f5b3192..2c7a2b54be57 100644 --- a/mm/damon/sysfs-schemes.c +++ b/mm/damon/sysfs-schemes.c @@ -2158,7 +2158,7 @@ static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme) goto put_dests_out; err = damon_sysfs_scheme_set_watermarks(scheme); if (err) - goto put_quotas_access_pattern_out; + goto rmdir_put_quotas_access_pattern_out; err = damos_sysfs_set_filter_dirs(scheme); if (err) goto put_watermarks_quotas_access_pattern_out; @@ -2183,7 +2183,8 @@ put_filters_watermarks_quotas_access_pattern_out: put_watermarks_quotas_access_pattern_out: kobject_put(&scheme->watermarks->kobj); scheme->watermarks = NULL; -put_quotas_access_pattern_out: +rmdir_put_quotas_access_pattern_out: + damon_sysfs_quotas_rm_dirs(scheme->quotas); kobject_put(&scheme->quotas->kobj); scheme->quotas = NULL; put_dests_out: From 392b3d9d595f34877dd745b470c711e8ebcd225c Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Wed, 24 Dec 2025 18:30:37 -0800 Subject: [PATCH 279/443] mm/damon/sysfs-scheme: cleanup access_pattern subdirs on scheme dir setup failure When a DAMOS-scheme DAMON sysfs directory setup fails after setup of access_pattern/ directory, subdirectories of access_pattern/ directory are not cleaned up. As a result, DAMON sysfs interface is nearly broken until the system reboots, and the memory for the unremoved directory is leaked. Cleanup the directories under such failures. Link: https://lkml.kernel.org/r/20251225023043.18579-5-sj@kernel.org Fixes: 9bbb820a5bd5 ("mm/damon/sysfs: support DAMOS quotas") Signed-off-by: SeongJae Park Cc: chongjiapeng Cc: # 5.18.x Signed-off-by: Andrew Morton --- mm/damon/sysfs-schemes.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c index 2c7a2b54be57..3a699dcd5a7f 100644 --- a/mm/damon/sysfs-schemes.c +++ b/mm/damon/sysfs-schemes.c @@ -2152,7 +2152,7 @@ static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme) return err; err = damos_sysfs_set_dests(scheme); if (err) - goto put_access_pattern_out; + goto rmdir_put_access_pattern_out; err = damon_sysfs_scheme_set_quotas(scheme); if (err) goto put_dests_out; @@ -2190,7 +2190,8 @@ rmdir_put_quotas_access_pattern_out: put_dests_out: kobject_put(&scheme->dests->kobj); scheme->dests = NULL; -put_access_pattern_out: +rmdir_put_access_pattern_out: + damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern); kobject_put(&scheme->access_pattern->kobj); scheme->access_pattern = NULL; return err; From 590b13669b813d55844fecd9142c56abd567914d Mon Sep 17 00:00:00 2001 From: Pavel Butsykin Date: Wed, 31 Dec 2025 11:46:38 +0400 Subject: [PATCH 280/443] mm/zswap: fix error pointer free in zswap_cpu_comp_prepare() crypto_alloc_acomp_node() may return ERR_PTR(), but the fail path checks only for NULL and can pass an error pointer to crypto_free_acomp(). Use IS_ERR_OR_NULL() to only free valid acomp instances. Link: https://lkml.kernel.org/r/20251231074638.2564302-1-pbutsykin@cloudlinux.com Fixes: 779b9955f643 ("mm: zswap: move allocations during CPU init outside the lock") Signed-off-by: Pavel Butsykin Reviewed-by: SeongJae Park Acked-by: Yosry Ahmed Acked-by: Nhat Pham Cc: Johannes Weiner Cc: Chengming Zhou Cc: Signed-off-by: Andrew Morton --- mm/zswap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/zswap.c b/mm/zswap.c index 5d0f8b13a958..ac9b7a60736b 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -787,7 +787,7 @@ static int zswap_cpu_comp_prepare(unsigned int cpu, struct hlist_node *node) return 0; fail: - if (acomp) + if (!IS_ERR_OR_NULL(acomp)) crypto_free_acomp(acomp); kfree(buffer); return ret; From 61f67c230a5e7c741c352349ea80147fbe65bfae Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Mon, 5 Jan 2026 20:11:47 +0000 Subject: [PATCH 281/443] mm/vma: fix anon_vma UAF on mremap() faulted, unfaulted merge Patch series "mm/vma: fix anon_vma UAF on mremap() faulted, unfaulted merge", v2. Commit 879bca0a2c4f ("mm/vma: fix incorrectly disallowed anonymous VMA merges") introduced the ability to merge previously unavailable VMA merge scenarios. However, it is handling merges incorrectly when it comes to mremap() of a faulted VMA adjacent to an unfaulted VMA. The issues arise in three cases: 1. Previous VMA unfaulted: copied -----| v |-----------|.............| | unfaulted |(faulted VMA)| |-----------|.............| prev 2. Next VMA unfaulted: copied -----| v |.............|-----------| |(faulted VMA)| unfaulted | |.............|-----------| next 3. Both adjacent VMAs unfaulted: copied -----| v |-----------|.............|-----------| | unfaulted |(faulted VMA)| unfaulted | |-----------|.............|-----------| prev next This series fixes each of these cases, and introduces self tests to assert that the issues are corrected. I also test a further case which was already handled, to assert that my changes continues to correctly handle it: 4. prev unfaulted, next faulted: copied -----| v |-----------|.............|-----------| | unfaulted |(faulted VMA)| faulted | |-----------|.............|-----------| prev next This bug was discovered via a syzbot report, linked to in the first patch in the series, I confirmed that this series fixes the bug. I also discovered that we are failing to check that the faulted VMA was not forked when merging a copied VMA in cases 1-3 above, an issue this series also addresses. I also added self tests to assert that this is resolved (and confirmed that the tests failed prior to this). I also cleaned up vma_expand() as part of this work, renamed vma_had_uncowed_parents() to vma_is_fork_child() as the previous name was unduly confusing, and simplified the comments around this function. This patch (of 4): Commit 879bca0a2c4f ("mm/vma: fix incorrectly disallowed anonymous VMA merges") introduced the ability to merge previously unavailable VMA merge scenarios. The key piece of logic introduced was the ability to merge a faulted VMA immediately next to an unfaulted VMA, which relies upon dup_anon_vma() to correctly handle anon_vma state. In the case of the merge of an existing VMA (that is changing properties of a VMA and then merging if those properties are shared by adjacent VMAs), dup_anon_vma() is invoked correctly. However in the case of the merge of a new VMA, a corner case peculiar to mremap() was missed. The issue is that vma_expand() only performs dup_anon_vma() if the target (the VMA that will ultimately become the merged VMA): is not the next VMA, i.e. the one that appears after the range in which the new VMA is to be established. A key insight here is that in all other cases other than mremap(), a new VMA merge either expands an existing VMA, meaning that the target VMA will be that VMA, or would have anon_vma be NULL. Specifically: * __mmap_region() - no anon_vma in place, initial mapping. * do_brk_flags() - expanding an existing VMA. * vma_merge_extend() - expanding an existing VMA. * relocate_vma_down() - no anon_vma in place, initial mapping. In addition, we are in the unique situation of needing to duplicate anon_vma state from a VMA that is neither the previous or next VMA being merged with. dup_anon_vma() deals exclusively with the target=unfaulted, src=faulted case. This leaves four possibilities, in each case where the copied VMA is faulted: 1. Previous VMA unfaulted: copied -----| v |-----------|.............| | unfaulted |(faulted VMA)| |-----------|.............| prev target = prev, expand prev to cover. 2. Next VMA unfaulted: copied -----| v |.............|-----------| |(faulted VMA)| unfaulted | |.............|-----------| next target = next, expand next to cover. 3. Both adjacent VMAs unfaulted: copied -----| v |-----------|.............|-----------| | unfaulted |(faulted VMA)| unfaulted | |-----------|.............|-----------| prev next target = prev, expand prev to cover. 4. prev unfaulted, next faulted: copied -----| v |-----------|.............|-----------| | unfaulted |(faulted VMA)| faulted | |-----------|.............|-----------| prev next target = prev, expand prev to cover. Essentially equivalent to 3, but with additional requirement that next's anon_vma is the same as the copied VMA's. This is covered by the existing logic. To account for this very explicitly, we introduce vma_merge_copied_range(), which sets a newly introduced vmg->copied_from field, then invokes vma_merge_new_range() which handles the rest of the logic. We then update the key vma_expand() function to clean up the logic and make what's going on clearer, making the 'remove next' case less special, before invoking dup_anon_vma() unconditionally should we be copying from a VMA. Note that in case 3, the if (remove_next) ... branch will be a no-op, as next=src in this instance and src is unfaulted. In case 4, it won't be, but since in this instance next=src and it is faulted, this will have required tgt=faulted, src=faulted to be compatible, meaning that next->anon_vma == vmg->copied_from->anon_vma, and thus a single dup_anon_vma() of next suffices to copy anon_vma state for the copied-from VMA also. If we are copying from a VMA in a successful merge we must _always_ propagate anon_vma state. This issue can be observed most directly by invoked mremap() to move around a VMA and cause this kind of merge with the MREMAP_DONTUNMAP flag specified. This will result in unlink_anon_vmas() being called after failing to duplicate anon_vma state to the target VMA, which results in the anon_vma itself being freed with folios still possessing dangling pointers to the anon_vma and thus a use-after-free bug. This bug was discovered via a syzbot report, which this patch resolves. We further make a change to update the mergeable anon_vma check to assert the copied-from anon_vma did not have CoW parents, as otherwise dup_anon_vma() might incorrectly propagate CoW ancestors from the next VMA in case 4 despite the anon_vma's being identical for both VMAs. Link: https://lkml.kernel.org/r/cover.1767638272.git.lorenzo.stoakes@oracle.com Link: https://lkml.kernel.org/r/b7930ad2b1503a657e29fe928eb33061d7eadf5b.1767638272.git.lorenzo.stoakes@oracle.com Signed-off-by: Lorenzo Stoakes Fixes: 879bca0a2c4f ("mm/vma: fix incorrectly disallowed anonymous VMA merges") Reported-by: syzbot+b165fc2e11771c66d8ba@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/694a2745.050a0220.19928e.0017.GAE@google.com/ Reported-by: syzbot+5272541ccbbb14e2ec30@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/694e3dc6.050a0220.35954c.0066.GAE@google.com/ Reviewed-by: Harry Yoo Reviewed-by: Jeongjun Park Acked-by: Vlastimil Babka Cc: David Hildenbrand (Red Hat) Cc: Jann Horn Cc: Yeoreum Yun Cc: Liam Howlett Cc: "Liam R. Howlett" Cc: Pedro Falcato Cc: Rik van Riel Cc: Signed-off-by: Andrew Morton --- mm/vma.c | 84 +++++++++++++++++++++++++++++++++++++++----------------- mm/vma.h | 3 ++ 2 files changed, 62 insertions(+), 25 deletions(-) diff --git a/mm/vma.c b/mm/vma.c index fc90befd162f..9df9e3b78604 100644 --- a/mm/vma.c +++ b/mm/vma.c @@ -829,6 +829,8 @@ static __must_check struct vm_area_struct *vma_merge_existing_range( VM_WARN_ON_VMG(middle && !(vma_iter_addr(vmg->vmi) >= middle->vm_start && vma_iter_addr(vmg->vmi) < middle->vm_end), vmg); + /* An existing merge can never be used by the mremap() logic. */ + VM_WARN_ON_VMG(vmg->copied_from, vmg); vmg->state = VMA_MERGE_NOMERGE; @@ -1098,6 +1100,33 @@ struct vm_area_struct *vma_merge_new_range(struct vma_merge_struct *vmg) return NULL; } +/* + * vma_merge_copied_range - Attempt to merge a VMA that is being copied by + * mremap() + * + * @vmg: Describes the VMA we are adding, in the copied-to range @vmg->start to + * @vmg->end (exclusive), which we try to merge with any adjacent VMAs if + * possible. + * + * vmg->prev, next, start, end, pgoff should all be relative to the COPIED TO + * range, i.e. the target range for the VMA. + * + * Returns: In instances where no merge was possible, NULL. Otherwise, a pointer + * to the VMA we expanded. + * + * ASSUMPTIONS: Same as vma_merge_new_range(), except vmg->middle must contain + * the copied-from VMA. + */ +static struct vm_area_struct *vma_merge_copied_range(struct vma_merge_struct *vmg) +{ + /* We must have a copied-from VMA. */ + VM_WARN_ON_VMG(!vmg->middle, vmg); + + vmg->copied_from = vmg->middle; + vmg->middle = NULL; + return vma_merge_new_range(vmg); +} + /* * vma_expand - Expand an existing VMA * @@ -1117,46 +1146,52 @@ struct vm_area_struct *vma_merge_new_range(struct vma_merge_struct *vmg) int vma_expand(struct vma_merge_struct *vmg) { struct vm_area_struct *anon_dup = NULL; - bool remove_next = false; struct vm_area_struct *target = vmg->target; struct vm_area_struct *next = vmg->next; + bool remove_next = false; vm_flags_t sticky_flags; - - sticky_flags = vmg->vm_flags & VM_STICKY; - sticky_flags |= target->vm_flags & VM_STICKY; - - VM_WARN_ON_VMG(!target, vmg); + int ret = 0; mmap_assert_write_locked(vmg->mm); - vma_start_write(target); - if (next && (target != next) && (vmg->end == next->vm_end)) { - int ret; - sticky_flags |= next->vm_flags & VM_STICKY; + if (next && target != next && vmg->end == next->vm_end) remove_next = true; - /* This should already have been checked by this point. */ - VM_WARN_ON_VMG(!can_merge_remove_vma(next), vmg); - vma_start_write(next); - /* - * In this case we don't report OOM, so vmg->give_up_on_mm is - * safe. - */ - ret = dup_anon_vma(target, next, &anon_dup); - if (ret) - return ret; - } + /* We must have a target. */ + VM_WARN_ON_VMG(!target, vmg); + /* This should have already been checked by this point. */ + VM_WARN_ON_VMG(remove_next && !can_merge_remove_vma(next), vmg); /* Not merging but overwriting any part of next is not handled. */ VM_WARN_ON_VMG(next && !remove_next && next != target && vmg->end > next->vm_start, vmg); - /* Only handles expanding */ + /* Only handles expanding. */ VM_WARN_ON_VMG(target->vm_start < vmg->start || target->vm_end > vmg->end, vmg); + sticky_flags = vmg->vm_flags & VM_STICKY; + sticky_flags |= target->vm_flags & VM_STICKY; if (remove_next) - vmg->__remove_next = true; + sticky_flags |= next->vm_flags & VM_STICKY; + /* + * If we are removing the next VMA or copying from a VMA + * (e.g. mremap()'ing), we must propagate anon_vma state. + * + * Note that, by convention, callers ignore OOM for this case, so + * we don't need to account for vmg->give_up_on_mm here. + */ + if (remove_next) + ret = dup_anon_vma(target, next, &anon_dup); + if (!ret && vmg->copied_from) + ret = dup_anon_vma(target, vmg->copied_from, &anon_dup); + if (ret) + return ret; + + if (remove_next) { + vma_start_write(next); + vmg->__remove_next = true; + } if (commit_merge(vmg)) goto nomem; @@ -1828,10 +1863,9 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, if (new_vma && new_vma->vm_start < addr + len) return NULL; /* should never get here */ - vmg.middle = NULL; /* New VMA range. */ vmg.pgoff = pgoff; vmg.next = vma_iter_next_rewind(&vmi, NULL); - new_vma = vma_merge_new_range(&vmg); + new_vma = vma_merge_copied_range(&vmg); if (new_vma) { /* diff --git a/mm/vma.h b/mm/vma.h index abada6a64c4e..9d5ee6ac913a 100644 --- a/mm/vma.h +++ b/mm/vma.h @@ -106,6 +106,9 @@ struct vma_merge_struct { struct anon_vma_name *anon_name; enum vma_merge_state state; + /* If copied from (i.e. mremap()'d) the VMA from which we are copying. */ + struct vm_area_struct *copied_from; + /* Flags which callers can use to modify merge behaviour: */ /* From 0ace8f2db6b3b4b0677e559d1a7ab7fd625d61ec Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Mon, 5 Jan 2026 20:11:48 +0000 Subject: [PATCH 282/443] tools/testing/selftests: add tests for !tgt, src mremap() merges Test that mremap()'ing a VMA into a position such that the target VMA on merge is unfaulted and the source faulted is correctly performed. We cover 4 cases: 1. Previous VMA unfaulted: copied -----| v |-----------|.............| | unfaulted |(faulted VMA)| |-----------|.............| prev target = prev, expand prev to cover. 2. Next VMA unfaulted: copied -----| v |.............|-----------| |(faulted VMA)| unfaulted | |.............|-----------| next target = next, expand next to cover. 3. Both adjacent VMAs unfaulted: copied -----| v |-----------|.............|-----------| | unfaulted |(faulted VMA)| unfaulted | |-----------|.............|-----------| prev next target = prev, expand prev to cover. 4. prev unfaulted, next faulted: copied -----| v |-----------|.............|-----------| | unfaulted |(faulted VMA)| faulted | |-----------|.............|-----------| prev next target = prev, expand prev to cover. Essentially equivalent to 3, but with additional requirement that next's anon_vma is the same as the copied VMA's. Each of these are performed with MREMAP_DONTUNMAP set, which will cause a KASAN assert for UAF or an assert on zero refcount anon_vma if a bug exists with correctly propagating anon_vma state in each scenario. Link: https://lkml.kernel.org/r/f903af2930c7c2c6e0948c886b58d0f42d8e8ba3.1767638272.git.lorenzo.stoakes@oracle.com Fixes: 879bca0a2c4f ("mm/vma: fix incorrectly disallowed anonymous VMA merges") Signed-off-by: Lorenzo Stoakes Cc: David Hildenbrand (Red Hat) Cc: Jann Horn Cc: Jeongjun Park Cc: Liam Howlett Cc: Pedro Falcato Cc: Rik van Riel Cc: Vlastimil Babka Cc: Yeoreum Yun Cc: Harry Yoo Cc: Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/merge.c | 232 +++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) diff --git a/tools/testing/selftests/mm/merge.c b/tools/testing/selftests/mm/merge.c index 363c1033cc7d..22be149f7109 100644 --- a/tools/testing/selftests/mm/merge.c +++ b/tools/testing/selftests/mm/merge.c @@ -1171,4 +1171,236 @@ TEST_F(merge, mremap_correct_placed_faulted) ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 15 * page_size); } +TEST_F(merge, mremap_faulted_to_unfaulted_prev) +{ + struct procmap_fd *procmap = &self->procmap; + unsigned int page_size = self->page_size; + char *ptr_a, *ptr_b; + + /* + * mremap() such that A and B merge: + * + * |------------| + * | \ | + * |-----------| | / |---------| + * | unfaulted | v \ | faulted | + * |-----------| / |---------| + * B \ A + */ + + /* Map VMA A into place. */ + ptr_a = mmap(&self->carveout[page_size + 3 * page_size], + 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_a, MAP_FAILED); + /* Fault it in. */ + ptr_a[0] = 'x'; + + /* + * Now move it out of the way so we can place VMA B in position, + * unfaulted. + */ + ptr_a = mremap(ptr_a, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE, &self->carveout[20 * page_size]); + ASSERT_NE(ptr_a, MAP_FAILED); + + /* Map VMA B into place. */ + ptr_b = mmap(&self->carveout[page_size], 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_b, MAP_FAILED); + + /* + * Now move VMA A into position with MREMAP_DONTUNMAP to catch incorrect + * anon_vma propagation. + */ + ptr_a = mremap(ptr_a, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP, + &self->carveout[page_size + 3 * page_size]); + ASSERT_NE(ptr_a, MAP_FAILED); + + /* The VMAs should have merged. */ + ASSERT_TRUE(find_vma_procmap(procmap, ptr_b)); + ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_b); + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_b + 6 * page_size); +} + +TEST_F(merge, mremap_faulted_to_unfaulted_next) +{ + struct procmap_fd *procmap = &self->procmap; + unsigned int page_size = self->page_size; + char *ptr_a, *ptr_b; + + /* + * mremap() such that A and B merge: + * + * |---------------------------| + * | \ | + * | |-----------| / |---------| + * v | unfaulted | \ | faulted | + * |-----------| / |---------| + * B \ A + * + * Then unmap VMA A to trigger the bug. + */ + + /* Map VMA A into place. */ + ptr_a = mmap(&self->carveout[page_size], 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_a, MAP_FAILED); + /* Fault it in. */ + ptr_a[0] = 'x'; + + /* + * Now move it out of the way so we can place VMA B in position, + * unfaulted. + */ + ptr_a = mremap(ptr_a, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE, &self->carveout[20 * page_size]); + ASSERT_NE(ptr_a, MAP_FAILED); + + /* Map VMA B into place. */ + ptr_b = mmap(&self->carveout[page_size + 3 * page_size], 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_b, MAP_FAILED); + + /* + * Now move VMA A into position with MREMAP_DONTUNMAP to catch incorrect + * anon_vma propagation. + */ + ptr_a = mremap(ptr_a, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP, + &self->carveout[page_size]); + ASSERT_NE(ptr_a, MAP_FAILED); + + /* The VMAs should have merged. */ + ASSERT_TRUE(find_vma_procmap(procmap, ptr_a)); + ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a); + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + 6 * page_size); +} + +TEST_F(merge, mremap_faulted_to_unfaulted_prev_unfaulted_next) +{ + struct procmap_fd *procmap = &self->procmap; + unsigned int page_size = self->page_size; + char *ptr_a, *ptr_b, *ptr_c; + + /* + * mremap() with MREMAP_DONTUNMAP such that A, B and C merge: + * + * |---------------------------| + * | \ | + * |-----------| | |-----------| / |---------| + * | unfaulted | v | unfaulted | \ | faulted | + * |-----------| |-----------| / |---------| + * A C \ B + */ + + /* Map VMA B into place. */ + ptr_b = mmap(&self->carveout[page_size + 3 * page_size], 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_b, MAP_FAILED); + /* Fault it in. */ + ptr_b[0] = 'x'; + + /* + * Now move it out of the way so we can place VMAs A, C in position, + * unfaulted. + */ + ptr_b = mremap(ptr_b, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE, &self->carveout[20 * page_size]); + ASSERT_NE(ptr_b, MAP_FAILED); + + /* Map VMA A into place. */ + + ptr_a = mmap(&self->carveout[page_size], 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_a, MAP_FAILED); + + /* Map VMA C into place. */ + ptr_c = mmap(&self->carveout[page_size + 3 * page_size + 3 * page_size], + 3 * page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_c, MAP_FAILED); + + /* + * Now move VMA B into position with MREMAP_DONTUNMAP to catch incorrect + * anon_vma propagation. + */ + ptr_b = mremap(ptr_b, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP, + &self->carveout[page_size + 3 * page_size]); + ASSERT_NE(ptr_b, MAP_FAILED); + + /* The VMAs should have merged. */ + ASSERT_TRUE(find_vma_procmap(procmap, ptr_a)); + ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a); + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + 9 * page_size); +} + +TEST_F(merge, mremap_faulted_to_unfaulted_prev_faulted_next) +{ + struct procmap_fd *procmap = &self->procmap; + unsigned int page_size = self->page_size; + char *ptr_a, *ptr_b, *ptr_bc; + + /* + * mremap() with MREMAP_DONTUNMAP such that A, B and C merge: + * + * |---------------------------| + * | \ | + * |-----------| | |-----------| / |---------| + * | unfaulted | v | faulted | \ | faulted | + * |-----------| |-----------| / |---------| + * A C \ B + */ + + /* + * Map VMA B and C into place. We have to map them together so their + * anon_vma is the same and the vma->vm_pgoff's are correctly aligned. + */ + ptr_bc = mmap(&self->carveout[page_size + 3 * page_size], + 3 * page_size + 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_bc, MAP_FAILED); + + /* Fault it in. */ + ptr_bc[0] = 'x'; + + /* + * Now move VMA B out the way (splitting VMA BC) so we can place VMA A + * in position, unfaulted, and leave the remainder of the VMA we just + * moved in place, faulted, as VMA C. + */ + ptr_b = mremap(ptr_bc, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE, &self->carveout[20 * page_size]); + ASSERT_NE(ptr_b, MAP_FAILED); + + /* Map VMA A into place. */ + ptr_a = mmap(&self->carveout[page_size], 3 * page_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); + ASSERT_NE(ptr_a, MAP_FAILED); + + /* + * Now move VMA B into position with MREMAP_DONTUNMAP to catch incorrect + * anon_vma propagation. + */ + ptr_b = mremap(ptr_b, 3 * page_size, 3 * page_size, + MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP, + &self->carveout[page_size + 3 * page_size]); + ASSERT_NE(ptr_b, MAP_FAILED); + + /* The VMAs should have merged. */ + ASSERT_TRUE(find_vma_procmap(procmap, ptr_a)); + ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a); + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + 9 * page_size); +} + TEST_HARNESS_MAIN From 3b617fd3d317bf9dd7e2c233e56eafef05734c9d Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Mon, 5 Jan 2026 20:11:49 +0000 Subject: [PATCH 283/443] mm/vma: enforce VMA fork limit on unfaulted,faulted mremap merge too The is_mergeable_anon_vma() function uses vmg->middle as the source VMA. However when merging a new VMA, this field is NULL. In all cases except mremap(), the new VMA will either be newly established and thus lack an anon_vma, or will be an expansion of an existing VMA thus we do not care about whether VMA is CoW'd or not. In the case of an mremap(), we can end up in a situation where we can accidentally allow an unfaulted/faulted merge with a VMA that has been forked, violating the general rule that we do not permit this for reasons of anon_vma lock scalability. Now we have the ability to be aware of the fact we are copying a VMA and also know which VMA that is, we can explicitly check for this, so do so. This is pertinent since commit 879bca0a2c4f ("mm/vma: fix incorrectly disallowed anonymous VMA merges"), as this patch permits unfaulted/faulted merges that were previously disallowed running afoul of this issue. While we are here, vma_had_uncowed_parents() is a confusing name, so make it simple and rename it to vma_is_fork_child(). Link: https://lkml.kernel.org/r/6e2b9b3024ae1220961c8b81d74296d4720eaf2b.1767638272.git.lorenzo.stoakes@oracle.com Fixes: 879bca0a2c4f ("mm/vma: fix incorrectly disallowed anonymous VMA merges") Signed-off-by: Lorenzo Stoakes Reviewed-by: Harry Yoo Reviewed-by: Jeongjun Park Acked-by: Vlastimil Babka Cc: David Hildenbrand (Red Hat) Cc: Jann Horn Cc: Liam Howlett Cc: Pedro Falcato Cc: Rik van Riel Cc: Yeoreum Yun Cc: Signed-off-by: Andrew Morton --- mm/vma.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/mm/vma.c b/mm/vma.c index 9df9e3b78604..dc92f3dd8514 100644 --- a/mm/vma.c +++ b/mm/vma.c @@ -67,18 +67,13 @@ struct mmap_state { .state = VMA_MERGE_START, \ } -/* - * If, at any point, the VMA had unCoW'd mappings from parents, it will maintain - * more than one anon_vma_chain connecting it to more than one anon_vma. A merge - * would mean a wider range of folios sharing the root anon_vma lock, and thus - * potential lock contention, we do not wish to encourage merging such that this - * scales to a problem. - */ -static bool vma_had_uncowed_parents(struct vm_area_struct *vma) +/* Was this VMA ever forked from a parent, i.e. maybe contains CoW mappings? */ +static bool vma_is_fork_child(struct vm_area_struct *vma) { /* * The list_is_singular() test is to avoid merging VMA cloned from - * parents. This can improve scalability caused by anon_vma lock. + * parents. This can improve scalability caused by the anon_vma root + * lock. */ return vma && vma->anon_vma && !list_is_singular(&vma->anon_vma_chain); } @@ -115,11 +110,19 @@ static bool is_mergeable_anon_vma(struct vma_merge_struct *vmg, bool merge_next) VM_WARN_ON(src && src_anon != src->anon_vma); /* Case 1 - we will dup_anon_vma() from src into tgt. */ - if (!tgt_anon && src_anon) - return !vma_had_uncowed_parents(src); + if (!tgt_anon && src_anon) { + struct vm_area_struct *copied_from = vmg->copied_from; + + if (vma_is_fork_child(src)) + return false; + if (vma_is_fork_child(copied_from)) + return false; + + return true; + } /* Case 2 - we will simply use tgt's anon_vma. */ if (tgt_anon && !src_anon) - return !vma_had_uncowed_parents(tgt); + return !vma_is_fork_child(tgt); /* Case 3 - the anon_vma's are already shared. */ return src_anon == tgt_anon; } From fb39444732f02c32a8312c168d97e33d872c14d3 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Mon, 5 Jan 2026 20:11:50 +0000 Subject: [PATCH 284/443] tools/testing/selftests: add forked (un)/faulted VMA merge tests Now we correctly handle forked faulted/unfaulted merge on mremap(), exhaustively assert that we handle this correctly. Do this in the less duplicative way by adding a new merge_with_fork fixture and forked/unforked variants, and abstract the forking logic as necessary to avoid code duplication with this also. Link: https://lkml.kernel.org/r/1daf76d89fdb9d96f38a6a0152d8f3c2e9e30ac7.1767638272.git.lorenzo.stoakes@oracle.com Fixes: 879bca0a2c4f ("mm/vma: fix incorrectly disallowed anonymous VMA merges") Signed-off-by: Lorenzo Stoakes Cc: David Hildenbrand (Red Hat) Cc: Jann Horn Cc: Jeongjun Park Cc: Liam Howlett Cc: Pedro Falcato Cc: Rik van Riel Cc: Vlastimil Babka Cc: Yeoreum Yun Cc: Harry Yoo Cc: Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/merge.c | 180 ++++++++++++++++++++++------- 1 file changed, 139 insertions(+), 41 deletions(-) diff --git a/tools/testing/selftests/mm/merge.c b/tools/testing/selftests/mm/merge.c index 22be149f7109..10b686102b79 100644 --- a/tools/testing/selftests/mm/merge.c +++ b/tools/testing/selftests/mm/merge.c @@ -22,12 +22,37 @@ FIXTURE(merge) struct procmap_fd procmap; }; +static char *map_carveout(unsigned int page_size) +{ + return mmap(NULL, 30 * page_size, PROT_NONE, + MAP_ANON | MAP_PRIVATE, -1, 0); +} + +static pid_t do_fork(struct procmap_fd *procmap) +{ + pid_t pid = fork(); + + if (pid == -1) + return -1; + if (pid != 0) { + wait(NULL); + return pid; + } + + /* Reopen for child. */ + if (close_procmap(procmap)) + return -1; + if (open_self_procmap(procmap)) + return -1; + + return 0; +} + FIXTURE_SETUP(merge) { self->page_size = psize(); /* Carve out PROT_NONE region to map over. */ - self->carveout = mmap(NULL, 30 * self->page_size, PROT_NONE, - MAP_ANON | MAP_PRIVATE, -1, 0); + self->carveout = map_carveout(self->page_size); ASSERT_NE(self->carveout, MAP_FAILED); /* Setup PROCMAP_QUERY interface. */ ASSERT_EQ(open_self_procmap(&self->procmap), 0); @@ -36,7 +61,8 @@ FIXTURE_SETUP(merge) FIXTURE_TEARDOWN(merge) { ASSERT_EQ(munmap(self->carveout, 30 * self->page_size), 0); - ASSERT_EQ(close_procmap(&self->procmap), 0); + /* May fail for parent of forked process. */ + close_procmap(&self->procmap); /* * Clear unconditionally, as some tests set this. It is no issue if this * fails (KSM may be disabled for instance). @@ -44,6 +70,44 @@ FIXTURE_TEARDOWN(merge) prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0); } +FIXTURE(merge_with_fork) +{ + unsigned int page_size; + char *carveout; + struct procmap_fd procmap; +}; + +FIXTURE_VARIANT(merge_with_fork) +{ + bool forked; +}; + +FIXTURE_VARIANT_ADD(merge_with_fork, forked) +{ + .forked = true, +}; + +FIXTURE_VARIANT_ADD(merge_with_fork, unforked) +{ + .forked = false, +}; + +FIXTURE_SETUP(merge_with_fork) +{ + self->page_size = psize(); + self->carveout = map_carveout(self->page_size); + ASSERT_NE(self->carveout, MAP_FAILED); + ASSERT_EQ(open_self_procmap(&self->procmap), 0); +} + +FIXTURE_TEARDOWN(merge_with_fork) +{ + ASSERT_EQ(munmap(self->carveout, 30 * self->page_size), 0); + ASSERT_EQ(close_procmap(&self->procmap), 0); + /* See above. */ + prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0); +} + TEST_F(merge, mprotect_unfaulted_left) { unsigned int page_size = self->page_size; @@ -322,8 +386,8 @@ TEST_F(merge, forked_target_vma) unsigned int page_size = self->page_size; char *carveout = self->carveout; struct procmap_fd *procmap = &self->procmap; - pid_t pid; char *ptr, *ptr2; + pid_t pid; int i; /* @@ -344,19 +408,10 @@ TEST_F(merge, forked_target_vma) */ ptr[0] = 'x'; - pid = fork(); + pid = do_fork(&self->procmap); ASSERT_NE(pid, -1); - - if (pid != 0) { - wait(NULL); + if (pid != 0) return; - } - - /* Child process below: */ - - /* Reopen for child. */ - ASSERT_EQ(close_procmap(&self->procmap), 0); - ASSERT_EQ(open_self_procmap(&self->procmap), 0); /* unCOWing everything does not cause the AVC to go away. */ for (i = 0; i < 5 * page_size; i += page_size) @@ -386,8 +441,8 @@ TEST_F(merge, forked_source_vma) unsigned int page_size = self->page_size; char *carveout = self->carveout; struct procmap_fd *procmap = &self->procmap; - pid_t pid; char *ptr, *ptr2; + pid_t pid; int i; /* @@ -408,19 +463,10 @@ TEST_F(merge, forked_source_vma) */ ptr[0] = 'x'; - pid = fork(); + pid = do_fork(&self->procmap); ASSERT_NE(pid, -1); - - if (pid != 0) { - wait(NULL); + if (pid != 0) return; - } - - /* Child process below: */ - - /* Reopen for child. */ - ASSERT_EQ(close_procmap(&self->procmap), 0); - ASSERT_EQ(open_self_procmap(&self->procmap), 0); /* unCOWing everything does not cause the AVC to go away. */ for (i = 0; i < 5 * page_size; i += page_size) @@ -1171,10 +1217,11 @@ TEST_F(merge, mremap_correct_placed_faulted) ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 15 * page_size); } -TEST_F(merge, mremap_faulted_to_unfaulted_prev) +TEST_F(merge_with_fork, mremap_faulted_to_unfaulted_prev) { struct procmap_fd *procmap = &self->procmap; unsigned int page_size = self->page_size; + unsigned long offset; char *ptr_a, *ptr_b; /* @@ -1197,6 +1244,14 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev) /* Fault it in. */ ptr_a[0] = 'x'; + if (variant->forked) { + pid_t pid = do_fork(&self->procmap); + + ASSERT_NE(pid, -1); + if (pid != 0) + return; + } + /* * Now move it out of the way so we can place VMA B in position, * unfaulted. @@ -1220,16 +1275,19 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev) &self->carveout[page_size + 3 * page_size]); ASSERT_NE(ptr_a, MAP_FAILED); - /* The VMAs should have merged. */ + /* The VMAs should have merged, if not forked. */ ASSERT_TRUE(find_vma_procmap(procmap, ptr_b)); ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_b); - ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_b + 6 * page_size); + + offset = variant->forked ? 3 * page_size : 6 * page_size; + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_b + offset); } -TEST_F(merge, mremap_faulted_to_unfaulted_next) +TEST_F(merge_with_fork, mremap_faulted_to_unfaulted_next) { struct procmap_fd *procmap = &self->procmap; unsigned int page_size = self->page_size; + unsigned long offset; char *ptr_a, *ptr_b; /* @@ -1253,6 +1311,14 @@ TEST_F(merge, mremap_faulted_to_unfaulted_next) /* Fault it in. */ ptr_a[0] = 'x'; + if (variant->forked) { + pid_t pid = do_fork(&self->procmap); + + ASSERT_NE(pid, -1); + if (pid != 0) + return; + } + /* * Now move it out of the way so we can place VMA B in position, * unfaulted. @@ -1276,16 +1342,18 @@ TEST_F(merge, mremap_faulted_to_unfaulted_next) &self->carveout[page_size]); ASSERT_NE(ptr_a, MAP_FAILED); - /* The VMAs should have merged. */ + /* The VMAs should have merged, if not forked. */ ASSERT_TRUE(find_vma_procmap(procmap, ptr_a)); ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a); - ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + 6 * page_size); + offset = variant->forked ? 3 * page_size : 6 * page_size; + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + offset); } -TEST_F(merge, mremap_faulted_to_unfaulted_prev_unfaulted_next) +TEST_F(merge_with_fork, mremap_faulted_to_unfaulted_prev_unfaulted_next) { struct procmap_fd *procmap = &self->procmap; unsigned int page_size = self->page_size; + unsigned long offset; char *ptr_a, *ptr_b, *ptr_c; /* @@ -1307,6 +1375,14 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev_unfaulted_next) /* Fault it in. */ ptr_b[0] = 'x'; + if (variant->forked) { + pid_t pid = do_fork(&self->procmap); + + ASSERT_NE(pid, -1); + if (pid != 0) + return; + } + /* * Now move it out of the way so we can place VMAs A, C in position, * unfaulted. @@ -1337,13 +1413,21 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev_unfaulted_next) &self->carveout[page_size + 3 * page_size]); ASSERT_NE(ptr_b, MAP_FAILED); - /* The VMAs should have merged. */ + /* The VMAs should have merged, if not forked. */ ASSERT_TRUE(find_vma_procmap(procmap, ptr_a)); ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a); - ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + 9 * page_size); + offset = variant->forked ? 3 * page_size : 9 * page_size; + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + offset); + + /* If forked, B and C should also not have merged. */ + if (variant->forked) { + ASSERT_TRUE(find_vma_procmap(procmap, ptr_b)); + ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_b); + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_b + 3 * page_size); + } } -TEST_F(merge, mremap_faulted_to_unfaulted_prev_faulted_next) +TEST_F(merge_with_fork, mremap_faulted_to_unfaulted_prev_faulted_next) { struct procmap_fd *procmap = &self->procmap; unsigned int page_size = self->page_size; @@ -1373,6 +1457,14 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev_faulted_next) /* Fault it in. */ ptr_bc[0] = 'x'; + if (variant->forked) { + pid_t pid = do_fork(&self->procmap); + + ASSERT_NE(pid, -1); + if (pid != 0) + return; + } + /* * Now move VMA B out the way (splitting VMA BC) so we can place VMA A * in position, unfaulted, and leave the remainder of the VMA we just @@ -1397,10 +1489,16 @@ TEST_F(merge, mremap_faulted_to_unfaulted_prev_faulted_next) &self->carveout[page_size + 3 * page_size]); ASSERT_NE(ptr_b, MAP_FAILED); - /* The VMAs should have merged. */ - ASSERT_TRUE(find_vma_procmap(procmap, ptr_a)); - ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a); - ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + 9 * page_size); + /* The VMAs should have merged. A,B,C if unforked, B, C if forked. */ + if (variant->forked) { + ASSERT_TRUE(find_vma_procmap(procmap, ptr_b)); + ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_b); + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_b + 6 * page_size); + } else { + ASSERT_TRUE(find_vma_procmap(procmap, ptr_a)); + ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a); + ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + 9 * page_size); + } } TEST_HARNESS_MAIN From 4795d205d78690a46b60164f44b8bb7b3e800865 Mon Sep 17 00:00:00 2001 From: Ryan Roberts Date: Sun, 4 Jan 2026 13:43:47 +0000 Subject: [PATCH 285/443] mm: kmsan: fix poisoning of high-order non-compound pages kmsan_free_page() is called by the page allocator's free_pages_prepare() during page freeing. Its job is to poison all the memory covered by the page. It can be called with an order-0 page, a compound high-order page or a non-compound high-order page. But page_size() only works for order-0 and compound pages. For a non-compound high-order page it will incorrectly return PAGE_SIZE. The implication is that the tail pages of a high-order non-compound page do not get poisoned at free, so any invalid access while they are free could go unnoticed. It looks like the pages will be poisoned again at allocation time, so that would bookend the window. Fix this by using the order parameter to calculate the size. Link: https://lkml.kernel.org/r/20260104134348.3544298-1-ryan.roberts@arm.com Fixes: b073d7f8aee4 ("mm: kmsan: maintain KMSAN metadata for page operations") Signed-off-by: Ryan Roberts Reviewed-by: Alexander Potapenko Tested-by: Alexander Potapenko Cc: Dmitriy Vyukov Cc: Dmitry Vyukov Cc: Marco Elver Cc: Ryan Roberts Cc: Signed-off-by: Andrew Morton --- mm/kmsan/shadow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/kmsan/shadow.c b/mm/kmsan/shadow.c index e7f554a31bb4..9e1c5f2b7a41 100644 --- a/mm/kmsan/shadow.c +++ b/mm/kmsan/shadow.c @@ -207,7 +207,7 @@ void kmsan_free_page(struct page *page, unsigned int order) if (!kmsan_enabled || kmsan_in_runtime()) return; kmsan_enter_runtime(); - kmsan_internal_poison_memory(page_address(page), page_size(page), + kmsan_internal_poison_memory(page_address(page), PAGE_SIZE << order, GFP_KERNEL & ~(__GFP_RECLAIM), KMSAN_POISON_CHECK | KMSAN_POISON_FREE); kmsan_leave_runtime(); From 4b5c493ff762bb0433529ca6870b284f0a2a5ca8 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Mon, 5 Jan 2026 19:07:46 +0000 Subject: [PATCH 286/443] iommu/sva: include mmu_notifier.h header A call to mmu_notifier_arch_invalidate_secondary_tlbs() was introduced in commit e37d5a2d60a3 ("iommu/sva: invalidate stale IOTLB entries for kernel address space") but without explicitly adding its corresponding header file . This was evidenced while trying to enable compile testing support for IOMMU_SVA: config IOMMU_SVA select IOMMU_MM_DATA - bool + bool "Shared Virtual Addressing" if COMPILE_TEST The thing is for certain architectures this header file is indirectly included via . However, for others such as 32-bit arm the header is missing and it results in a build failure: $ make ARCH=arm allmodconfig [...] drivers/iommu/iommu-sva.c:340:3: error: call to undeclared function 'mmu_notifier_arch_invalidate_secondary_tlbs' [...] 340 | mmu_notifier_arch_invalidate_secondary_tlbs(iommu_mm->mm, start, end); | ^ Fix this by including the appropriate header file. Link: https://lkml.kernel.org/r/20260105190747.625082-1-cmllamas@google.com Fixes: e37d5a2d60a3 ("iommu/sva: invalidate stale IOTLB entries for kernel address space") Signed-off-by: Carlos Llamas Cc: Baolu Lu Cc: Jason Gunthorpe Cc: Joerg Roedel Cc: Kevin Tian Cc: Robin Murphy Cc: Vasant Hegde Cc: Will Deacon Signed-off-by: Andrew Morton --- drivers/iommu/iommu-sva.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c index d236aef80a8d..e1e63c2be82b 100644 --- a/drivers/iommu/iommu-sva.c +++ b/drivers/iommu/iommu-sva.c @@ -3,6 +3,7 @@ * Helpers for IOMMU drivers implementing SVA */ #include +#include #include #include #include From 038a102535eb49e10e93eafac54352fcc5d78847 Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Mon, 5 Jan 2026 16:08:56 +0100 Subject: [PATCH 287/443] mm/page_alloc: prevent pcp corruption with SMP=n The kernel test robot has reported: BUG: spinlock trylock failure on UP on CPU#0, kcompactd0/28 lock: 0xffff888807e35ef0, .magic: dead4ead, .owner: kcompactd0/28, .owner_cpu: 0 CPU: 0 UID: 0 PID: 28 Comm: kcompactd0 Not tainted 6.18.0-rc5-00127-ga06157804399 #1 PREEMPT 8cc09ef94dcec767faa911515ce9e609c45db470 Call Trace: __dump_stack (lib/dump_stack.c:95) dump_stack_lvl (lib/dump_stack.c:123) dump_stack (lib/dump_stack.c:130) spin_dump (kernel/locking/spinlock_debug.c:71) do_raw_spin_trylock (kernel/locking/spinlock_debug.c:?) _raw_spin_trylock (include/linux/spinlock_api_smp.h:89 kernel/locking/spinlock.c:138) __free_frozen_pages (mm/page_alloc.c:2973) ___free_pages (mm/page_alloc.c:5295) __free_pages (mm/page_alloc.c:5334) tlb_remove_table_rcu (include/linux/mm.h:? include/linux/mm.h:3122 include/asm-generic/tlb.h:220 mm/mmu_gather.c:227 mm/mmu_gather.c:290) ? __cfi_tlb_remove_table_rcu (mm/mmu_gather.c:289) ? rcu_core (kernel/rcu/tree.c:?) rcu_core (include/linux/rcupdate.h:341 kernel/rcu/tree.c:2607 kernel/rcu/tree.c:2861) rcu_core_si (kernel/rcu/tree.c:2879) handle_softirqs (arch/x86/include/asm/jump_label.h:36 include/trace/events/irq.h:142 kernel/softirq.c:623) __irq_exit_rcu (arch/x86/include/asm/jump_label.h:36 kernel/softirq.c:725) irq_exit_rcu (kernel/softirq.c:741) sysvec_apic_timer_interrupt (arch/x86/kernel/apic/apic.c:1052) RIP: 0010:_raw_spin_unlock_irqrestore (arch/x86/include/asm/preempt.h:95 include/linux/spinlock_api_smp.h:152 kernel/locking/spinlock.c:194) free_pcppages_bulk (mm/page_alloc.c:1494) drain_pages_zone (include/linux/spinlock.h:391 mm/page_alloc.c:2632) __drain_all_pages (mm/page_alloc.c:2731) drain_all_pages (mm/page_alloc.c:2747) kcompactd (mm/compaction.c:3115) kthread (kernel/kthread.c:465) ? __cfi_kcompactd (mm/compaction.c:3166) ? __cfi_kthread (kernel/kthread.c:412) ret_from_fork (arch/x86/kernel/process.c:164) ? __cfi_kthread (kernel/kthread.c:412) ret_from_fork_asm (arch/x86/entry/entry_64.S:255) Matthew has analyzed the report and identified that in drain_page_zone() we are in a section protected by spin_lock(&pcp->lock) and then get an interrupt that attempts spin_trylock() on the same lock. The code is designed to work this way without disabling IRQs and occasionally fail the trylock with a fallback. However, the SMP=n spinlock implementation assumes spin_trylock() will always succeed, and thus it's normally a no-op. Here the enabled lock debugging catches the problem, but otherwise it could cause a corruption of the pcp structure. The problem has been introduced by commit 574907741599 ("mm/page_alloc: leave IRQs enabled for per-cpu page allocations"). The pcp locking scheme recognizes the need for disabling IRQs to prevent nesting spin_trylock() sections on SMP=n, but the need to prevent the nesting in spin_lock() has not been recognized. Fix it by introducing local wrappers that change the spin_lock() to spin_lock_iqsave() with SMP=n and use them in all places that do spin_lock(&pcp->lock). [vbabka@suse.cz: add pcp_ prefix to the spin_lock_irqsave wrappers, per Steven] Link: https://lkml.kernel.org/r/20260105-fix-pcp-up-v1-1-5579662d2071@suse.cz Fixes: 574907741599 ("mm/page_alloc: leave IRQs enabled for per-cpu page allocations") Signed-off-by: Vlastimil Babka Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-lkp/202512101320.e2f2dd6f-lkp@intel.com Analyzed-by: Matthew Wilcox Link: https://lore.kernel.org/all/aUW05pyc9nZkvY-1@casper.infradead.org/ Acked-by: Mel Gorman Cc: Brendan Jackman Cc: Johannes Weiner Cc: Michal Hocko Cc: Sebastian Andrzej Siewior Cc: Steven Rostedt Cc: Suren Baghdasaryan Cc: Zi Yan Cc: Signed-off-by: Andrew Morton --- mm/page_alloc.c | 47 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 3dce96f3be49..f65c4edf199d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -167,6 +167,33 @@ static inline void __pcp_trylock_noop(unsigned long *flags) { } pcp_trylock_finish(UP_flags); \ }) +/* + * With the UP spinlock implementation, when we spin_lock(&pcp->lock) (for i.e. + * a potentially remote cpu drain) and get interrupted by an operation that + * attempts pcp_spin_trylock(), we can't rely on the trylock failure due to UP + * spinlock assumptions making the trylock a no-op. So we have to turn that + * spin_lock() to a spin_lock_irqsave(). This works because on UP there are no + * remote cpu's so we can only be locking the only existing local one. + */ +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT) +static inline void __flags_noop(unsigned long *flags) { } +#define pcp_spin_lock_maybe_irqsave(ptr, flags) \ +({ \ + __flags_noop(&(flags)); \ + spin_lock(&(ptr)->lock); \ +}) +#define pcp_spin_unlock_maybe_irqrestore(ptr, flags) \ +({ \ + spin_unlock(&(ptr)->lock); \ + __flags_noop(&(flags)); \ +}) +#else +#define pcp_spin_lock_maybe_irqsave(ptr, flags) \ + spin_lock_irqsave(&(ptr)->lock, flags) +#define pcp_spin_unlock_maybe_irqrestore(ptr, flags) \ + spin_unlock_irqrestore(&(ptr)->lock, flags) +#endif + #ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID DEFINE_PER_CPU(int, numa_node); EXPORT_PER_CPU_SYMBOL(numa_node); @@ -2556,6 +2583,7 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, bool decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp) { int high_min, to_drain, to_drain_batched, batch; + unsigned long UP_flags; bool todo = false; high_min = READ_ONCE(pcp->high_min); @@ -2575,9 +2603,9 @@ bool decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp) to_drain = pcp->count - pcp->high; while (to_drain > 0) { to_drain_batched = min(to_drain, batch); - spin_lock(&pcp->lock); + pcp_spin_lock_maybe_irqsave(pcp, UP_flags); free_pcppages_bulk(zone, to_drain_batched, pcp, 0); - spin_unlock(&pcp->lock); + pcp_spin_unlock_maybe_irqrestore(pcp, UP_flags); todo = true; to_drain -= to_drain_batched; @@ -2594,14 +2622,15 @@ bool decay_pcp_high(struct zone *zone, struct per_cpu_pages *pcp) */ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp) { + unsigned long UP_flags; int to_drain, batch; batch = READ_ONCE(pcp->batch); to_drain = min(pcp->count, batch); if (to_drain > 0) { - spin_lock(&pcp->lock); + pcp_spin_lock_maybe_irqsave(pcp, UP_flags); free_pcppages_bulk(zone, to_drain, pcp, 0); - spin_unlock(&pcp->lock); + pcp_spin_unlock_maybe_irqrestore(pcp, UP_flags); } } #endif @@ -2612,10 +2641,11 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp) static void drain_pages_zone(unsigned int cpu, struct zone *zone) { struct per_cpu_pages *pcp = per_cpu_ptr(zone->per_cpu_pageset, cpu); + unsigned long UP_flags; int count; do { - spin_lock(&pcp->lock); + pcp_spin_lock_maybe_irqsave(pcp, UP_flags); count = pcp->count; if (count) { int to_drain = min(count, @@ -2624,7 +2654,7 @@ static void drain_pages_zone(unsigned int cpu, struct zone *zone) free_pcppages_bulk(zone, to_drain, pcp, 0); count -= to_drain; } - spin_unlock(&pcp->lock); + pcp_spin_unlock_maybe_irqrestore(pcp, UP_flags); } while (count); } @@ -6109,6 +6139,7 @@ static void zone_pcp_update_cacheinfo(struct zone *zone, unsigned int cpu) { struct per_cpu_pages *pcp; struct cpu_cacheinfo *cci; + unsigned long UP_flags; pcp = per_cpu_ptr(zone->per_cpu_pageset, cpu); cci = get_cpu_cacheinfo(cpu); @@ -6119,12 +6150,12 @@ static void zone_pcp_update_cacheinfo(struct zone *zone, unsigned int cpu) * This can reduce zone lock contention without hurting * cache-hot pages sharing. */ - spin_lock(&pcp->lock); + pcp_spin_lock_maybe_irqsave(pcp, UP_flags); if ((cci->per_cpu_data_slice_size >> PAGE_SHIFT) > 3 * pcp->batch) pcp->flags |= PCPF_FREE_HIGH_BATCH; else pcp->flags &= ~PCPF_FREE_HIGH_BATCH; - spin_unlock(&pcp->lock); + pcp_spin_unlock_maybe_irqrestore(pcp, UP_flags); } void setup_pcp_cacheinfo(unsigned int cpu) From 21c68ad1d9771d331198cc73cbf6e908d7915f35 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Tue, 6 Jan 2026 15:45:47 +0000 Subject: [PATCH 288/443] tools/testing/selftests: fix gup_longterm for unknown fs Commit 66bce7afbaca ("selftests/mm: fix test result reporting in gup_longterm") introduced a small bug causing unknown filesystems to always result in a test failure. This is because do_test() was updated to use a common reporting path, but this case appears to have been missed. This is problematic for e.g. virtme-ng which uses an overlayfs file system, causing gup_longterm to appear to fail each time due to a test count mismatch: # Planned tests != run tests (50 != 46) # Totals: pass:24 fail:0 xfail:0 xpass:0 skip:22 error:0 The fix is to simply change the return into a break. Link: https://lkml.kernel.org/r/20260106154547.214907-1-lorenzo.stoakes@oracle.com Fixes: 66bce7afbaca ("selftests/mm: fix test result reporting in gup_longterm") Signed-off-by: Lorenzo Stoakes Reviewed-by: David Hildenbrand (Red Hat) Cc: Jason Gunthorpe Cc: John Hubbard Cc: Liam Howlett Cc: "Liam R. Howlett" Cc: Mark Brown Cc: Michal Hocko Cc: Mike Rapoport Cc: Peter Xu Cc: Shuah Khan Cc: Suren Baghdasaryan Cc: Vlastimil Babka Cc: Signed-off-by: Andrew Morton --- tools/testing/selftests/mm/gup_longterm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/mm/gup_longterm.c b/tools/testing/selftests/mm/gup_longterm.c index 6279893a0adc..f61150d28eb2 100644 --- a/tools/testing/selftests/mm/gup_longterm.c +++ b/tools/testing/selftests/mm/gup_longterm.c @@ -179,7 +179,7 @@ static void do_test(int fd, size_t size, enum test_type type, bool shared) if (rw && shared && fs_is_unknown(fs_type)) { ksft_print_msg("Unknown filesystem\n"); result = KSFT_SKIP; - return; + break; } /* * R/O pinning or pinning in a private mapping is always From 18e87bceae6cdeceb9d31803bf81e2968073c191 Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Thu, 8 Jan 2026 11:09:54 +0000 Subject: [PATCH 289/443] mailmap: add entry for Daniel Thompson My linaro address stopped working a long time ago but I didn't update my mailmap entry. Fix that. Link: https://lkml.kernel.org/r/20260108-mailmap-daniel_thompson_linaro-org-v1-1-83f610876377@kernel.org Signed-off-by: Daniel Thompson Signed-off-by: Andrew Morton --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index bc94004bc4c2..4a8a160f28ed 100644 --- a/.mailmap +++ b/.mailmap @@ -207,6 +207,7 @@ Daniel Borkmann Daniel Borkmann Daniel Borkmann Daniel Borkmann +Daniel Thompson Danilo Krummrich David Brownell David Collins From f46c26f1bcd9164d7f3377f15ca75488a3e44362 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 8 Jan 2026 10:15:39 +0000 Subject: [PATCH 290/443] mm: numa,memblock: include for 'numa_nodes_parsed' The 'numa_nodes_parsed' is defined in but this file is not included in mm/numa_memblks.c (build x86_64) so add this to the incldues to fix the following sparse warning: mm/numa_memblks.c:13:12: warning: symbol 'numa_nodes_parsed' was not declared. Should it be static? Link: https://lkml.kernel.org/r/20260108101539.229192-1-ben.dooks@codethink.co.uk Fixes: 87482708210f ("mm: introduce numa_memblks") Signed-off-by: Ben Dooks Reviewed-by: Mike Rapoport (Microsoft) Cc: Ben Dooks Cc: Signed-off-by: Andrew Morton --- mm/numa_memblks.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/numa_memblks.c b/mm/numa_memblks.c index 5b009a9cd8b4..8f5735fda0a2 100644 --- a/mm/numa_memblks.c +++ b/mm/numa_memblks.c @@ -7,6 +7,8 @@ #include #include +#include + int numa_distance_cnt; static u8 *numa_distance; From 3e8e590fd65d0572584ab7bba89a35e6d19931f1 Mon Sep 17 00:00:00 2001 From: John Groves Date: Sat, 10 Jan 2026 13:18:04 -0600 Subject: [PATCH 291/443] drivers/dax: add some missing kerneldoc comment fields for struct dev_dax Add the missing @align and @memmap_on_memory fields to kerneldoc comment header for struct dev_dax. Also, some other fields were followed by '-' and others by ':'. Fix all to be ':' for actual kerneldoc compliance. Link: https://lkml.kernel.org/r/20260110191804.5739-1-john@groves.net Fixes: 33cf94d71766 ("device-dax: make align a per-device property") Fixes: 4eca0ef49af9 ("dax/kmem: allow kmem to add memory with memmap_on_memory") Signed-off-by: John Groves Cc: Dan Williams Cc: Joao Martins Cc: Vishal Verma Signed-off-by: Andrew Morton --- drivers/dax/dax-private.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index 0867115aeef2..c6ae27c982f4 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h @@ -67,14 +67,16 @@ struct dev_dax_range { /** * struct dev_dax - instance data for a subdivision of a dax region, and * data while the device is activated in the driver. - * @region - parent region - * @dax_dev - core dax functionality + * @region: parent region + * @dax_dev: core dax functionality + * @align: alignment of this instance * @target_node: effective numa node if dev_dax memory range is onlined * @dyn_id: is this a dynamic or statically created instance * @id: ida allocated id when the dax_region is not static * @ida: mapping id allocator - * @dev - device core - * @pgmap - pgmap for memmap setup / lifetime (driver owned) + * @dev: device core + * @pgmap: pgmap for memmap setup / lifetime (driver owned) + * @memmap_on_memory: allow kmem to put the memmap in the memory * @nr_range: size of @ranges * @ranges: range tuples of memory used */ From fc558188f251f5df6dd11ac409d668733d9baac7 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 30 Dec 2025 15:14:14 +0100 Subject: [PATCH 292/443] Drivers: hv: vmbus: fix typo in function name reference Replace cmxchg by cmpxchg. Signed-off-by: Julia Lawall Reviewed-by: Roman Kisel Signed-off-by: Wei Liu --- drivers/hv/hyperv_vmbus.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index b2862e0a317a..cdbc5f5c3215 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -375,7 +375,7 @@ static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type) return; /* - * The cmxchg() above does an implicit memory barrier to + * The cmpxchg() above does an implicit memory barrier to * ensure the write to MessageType (ie set to * HVMSG_NONE) happens before we read the * MessagePending and EOMing. Otherwise, the EOMing From 49f49d47af67f8a7b221db1d758fc634242dc91a Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Wed, 31 Dec 2025 12:14:47 -0800 Subject: [PATCH 293/443] Drivers: hv: Always do Hyper-V panic notification in hv_kmsg_dump() hv_kmsg_dump() currently skips the panic notification entirely if it doesn't get any message bytes to pass to Hyper-V due to an error from kmsg_dump_get_buffer(). Skipping the notification is undesirable because it leaves the Hyper-V host uncertain about the state of a panic'ed guest. Fix this by always doing the panic notification, even if bytes_written is zero. Also ensure that bytes_written is initialized, which fixes a kernel test robot warning. The warning is actually bogus because kmsg_dump_get_buffer() happens to set bytes_written even if it fails, and in the kernel test robot's CONFIG_PRINTK not set case, hv_kmsg_dump() is never called. But do the initialization for robustness and to quiet the static checker. Fixes: 9c318a1d9b50 ("Drivers: hv: move panic report code from vmbus to hv early init code") Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/all/202512172103.OcUspn1Z-lkp@intel.com/ Signed-off-by: Michael Kelley Reviewed-by: Roman Kisel Signed-off-by: Wei Liu --- drivers/hv/hv_common.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c index 0a3ab7efed46..f1c17fb60dc1 100644 --- a/drivers/hv/hv_common.c +++ b/drivers/hv/hv_common.c @@ -195,13 +195,15 @@ static void hv_kmsg_dump(struct kmsg_dumper *dumper, /* * Write dump contents to the page. No need to synchronize; panic should - * be single-threaded. + * be single-threaded. Ignore failures from kmsg_dump_get_buffer() since + * panic notification should be done even if there is no message data. + * Don't assume bytes_written is set in case of failure, so initialize it. */ kmsg_dump_rewind(&iter); - kmsg_dump_get_buffer(&iter, false, hv_panic_page, HV_HYP_PAGE_SIZE, + bytes_written = 0; + (void)kmsg_dump_get_buffer(&iter, false, hv_panic_page, HV_HYP_PAGE_SIZE, &bytes_written); - if (!bytes_written) - return; + /* * P3 to contain the physical address of the panic page & P4 to * contain the size of the panic data in that page. Rest of the @@ -210,7 +212,7 @@ static void hv_kmsg_dump(struct kmsg_dumper *dumper, hv_set_msr(HV_MSR_CRASH_P0, 0); hv_set_msr(HV_MSR_CRASH_P1, 0); hv_set_msr(HV_MSR_CRASH_P2, 0); - hv_set_msr(HV_MSR_CRASH_P3, virt_to_phys(hv_panic_page)); + hv_set_msr(HV_MSR_CRASH_P3, bytes_written ? virt_to_phys(hv_panic_page) : 0); hv_set_msr(HV_MSR_CRASH_P4, bytes_written); /* From 259add0d982cbe83170f0c2a9f160834f0f83dd4 Mon Sep 17 00:00:00 2001 From: Stanislav Kinsburskii Date: Wed, 7 Jan 2026 18:45:43 +0000 Subject: [PATCH 294/443] mshv: Align huge page stride with guest mapping Ensure that a stride larger than 1 (huge page) is only used when page points to a head of a huge page and both the guest frame number (gfn) and the operation size (page_count) are aligned to the huge page size (PTRS_PER_PMD). This matches the hypervisor requirement that map/unmap operations for huge pages must be guest-aligned and cover a full huge page. Add mshv_chunk_stride() to encapsulate this alignment and page-order validation, and plumb a huge_page flag into the region chunk handlers. This prevents issuing large-page map/unmap/share operations that the hypervisor would reject due to misaligned guest mappings. Fixes: abceb4297bf8 ("mshv: Fix huge page handling in memory region traversal") Signed-off-by: Stanislav Kinsburskii Reviewed-by: Nuno Das Neves Reviewed-by: Michael Kelley Signed-off-by: Wei Liu --- drivers/hv/mshv_regions.c | 93 ++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 31 deletions(-) diff --git a/drivers/hv/mshv_regions.c b/drivers/hv/mshv_regions.c index 30bacba6aec3..adba3564d9f1 100644 --- a/drivers/hv/mshv_regions.c +++ b/drivers/hv/mshv_regions.c @@ -19,6 +19,41 @@ #define MSHV_MAP_FAULT_IN_PAGES PTRS_PER_PMD +/** + * mshv_chunk_stride - Compute stride for mapping guest memory + * @page : The page to check for huge page backing + * @gfn : Guest frame number for the mapping + * @page_count: Total number of pages in the mapping + * + * Determines the appropriate stride (in pages) for mapping guest memory. + * Uses huge page stride if the backing page is huge and the guest mapping + * is properly aligned; otherwise falls back to single page stride. + * + * Return: Stride in pages, or -EINVAL if page order is unsupported. + */ +static int mshv_chunk_stride(struct page *page, + u64 gfn, u64 page_count) +{ + unsigned int page_order; + + /* + * Use single page stride by default. For huge page stride, the + * page must be compound and point to the head of the compound + * page, and both gfn and page_count must be huge-page aligned. + */ + if (!PageCompound(page) || !PageHead(page) || + !IS_ALIGNED(gfn, PTRS_PER_PMD) || + !IS_ALIGNED(page_count, PTRS_PER_PMD)) + return 1; + + page_order = folio_order(page_folio(page)); + /* The hypervisor only supports 2M huge page */ + if (page_order != PMD_ORDER) + return -EINVAL; + + return 1 << page_order; +} + /** * mshv_region_process_chunk - Processes a contiguous chunk of memory pages * in a region. @@ -45,25 +80,23 @@ static long mshv_region_process_chunk(struct mshv_mem_region *region, int (*handler)(struct mshv_mem_region *region, u32 flags, u64 page_offset, - u64 page_count)) + u64 page_count, + bool huge_page)) { - u64 count, stride; - unsigned int page_order; + u64 gfn = region->start_gfn + page_offset; + u64 count; struct page *page; - int ret; + int stride, ret; page = region->pages[page_offset]; if (!page) return -EINVAL; - page_order = folio_order(page_folio(page)); - /* The hypervisor only supports 4K and 2M page sizes */ - if (page_order && page_order != PMD_ORDER) - return -EINVAL; + stride = mshv_chunk_stride(page, gfn, page_count); + if (stride < 0) + return stride; - stride = 1 << page_order; - - /* Start at stride since the first page is validated */ + /* Start at stride since the first stride is validated */ for (count = stride; count < page_count; count += stride) { page = region->pages[page_offset + count]; @@ -71,12 +104,13 @@ static long mshv_region_process_chunk(struct mshv_mem_region *region, if (!page) break; - /* Break if page size changes */ - if (page_order != folio_order(page_folio(page))) + /* Break if stride size changes */ + if (stride != mshv_chunk_stride(page, gfn + count, + page_count - count)) break; } - ret = handler(region, flags, page_offset, count); + ret = handler(region, flags, page_offset, count, stride > 1); if (ret) return ret; @@ -108,7 +142,8 @@ static int mshv_region_process_range(struct mshv_mem_region *region, int (*handler)(struct mshv_mem_region *region, u32 flags, u64 page_offset, - u64 page_count)) + u64 page_count, + bool huge_page)) { long ret; @@ -162,11 +197,10 @@ struct mshv_mem_region *mshv_region_create(u64 guest_pfn, u64 nr_pages, static int mshv_region_chunk_share(struct mshv_mem_region *region, u32 flags, - u64 page_offset, u64 page_count) + u64 page_offset, u64 page_count, + bool huge_page) { - struct page *page = region->pages[page_offset]; - - if (PageHuge(page) || PageTransCompound(page)) + if (huge_page) flags |= HV_MODIFY_SPA_PAGE_HOST_ACCESS_LARGE_PAGE; return hv_call_modify_spa_host_access(region->partition->pt_id, @@ -188,11 +222,10 @@ int mshv_region_share(struct mshv_mem_region *region) static int mshv_region_chunk_unshare(struct mshv_mem_region *region, u32 flags, - u64 page_offset, u64 page_count) + u64 page_offset, u64 page_count, + bool huge_page) { - struct page *page = region->pages[page_offset]; - - if (PageHuge(page) || PageTransCompound(page)) + if (huge_page) flags |= HV_MODIFY_SPA_PAGE_HOST_ACCESS_LARGE_PAGE; return hv_call_modify_spa_host_access(region->partition->pt_id, @@ -212,11 +245,10 @@ int mshv_region_unshare(struct mshv_mem_region *region) static int mshv_region_chunk_remap(struct mshv_mem_region *region, u32 flags, - u64 page_offset, u64 page_count) + u64 page_offset, u64 page_count, + bool huge_page) { - struct page *page = region->pages[page_offset]; - - if (PageHuge(page) || PageTransCompound(page)) + if (huge_page) flags |= HV_MAP_GPA_LARGE_PAGE; return hv_call_map_gpa_pages(region->partition->pt_id, @@ -295,11 +327,10 @@ release_pages: static int mshv_region_chunk_unmap(struct mshv_mem_region *region, u32 flags, - u64 page_offset, u64 page_count) + u64 page_offset, u64 page_count, + bool huge_page) { - struct page *page = region->pages[page_offset]; - - if (PageHuge(page) || PageTransCompound(page)) + if (huge_page) flags |= HV_UNMAP_GPA_LARGE_PAGE; return hv_call_unmap_gpa_pages(region->partition->pt_id, From e020f604abaa6da9b7d579d9d73ffaf37072f520 Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Wed, 14 Jan 2026 09:01:12 -0800 Subject: [PATCH 295/443] mshv: Store the result of vfs_poll in a variable of type __poll_t vfs_poll() returns a result of type __poll_t, but current code is using an "unsigned int" local variable. The difference is that __poll_t carries the "bitwise" attribute. This attribute is not interpreted by the C compiler; it is only used by 'sparse' to flag incorrect usage of the return value. The return value is used correctly here, so there's no bug, but sparse complains about the type mismatch. In the interest of general correctness and to avoid noise from sparse, change the local variable to type __poll_t. No functional change. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202512141339.791TCKnB-lkp@intel.com/ Signed-off-by: Michael Kelley Reviewed-by: Nuno Das Neves Signed-off-by: Wei Liu --- drivers/hv/mshv_eventfd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hv/mshv_eventfd.c b/drivers/hv/mshv_eventfd.c index d93a18f09c76..0b75ff1edb73 100644 --- a/drivers/hv/mshv_eventfd.c +++ b/drivers/hv/mshv_eventfd.c @@ -388,7 +388,7 @@ static int mshv_irqfd_assign(struct mshv_partition *pt, { struct eventfd_ctx *eventfd = NULL, *resamplefd = NULL; struct mshv_irqfd *irqfd, *tmp; - unsigned int events; + __poll_t events; int ret; int idx; From d2999c0fbcb2a84b0994ad3ec0d30c190ccd5e67 Mon Sep 17 00:00:00 2001 From: Michael Kelley Date: Wed, 14 Jan 2026 10:15:08 -0800 Subject: [PATCH 296/443] mshv: Add __user attribute to argument passed to access_ok() access_ok() expects its first argument to have the __user attribute since it is checking access to user space. Current code passes an argument that lacks that attribute, resulting in 'sparse' flagging the incorrect usage. However, the compiler doesn't generate code based on the attribute, so there's no actual bug. In the interest of general correctness and to avoid noise from sparse, add the __user attribute. No functional change. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202512141339.791TCKnB-lkp@intel.com/ Signed-off-by: Michael Kelley Reviewed-by: Nuno Das Neves Signed-off-by: Wei Liu --- drivers/hv/mshv_root_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c index 1134a82c7881..99fdbc3988aa 100644 --- a/drivers/hv/mshv_root_main.c +++ b/drivers/hv/mshv_root_main.c @@ -1280,7 +1280,7 @@ mshv_map_user_memory(struct mshv_partition *partition, long ret; if (mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP) || - !access_ok((const void *)mem.userspace_addr, mem.size)) + !access_ok((const void __user *)mem.userspace_addr, mem.size)) return -EINVAL; mmap_read_lock(current->mm); From 69c88a6a49cfe1fd6bd5c1166d02a7dd29de9569 Mon Sep 17 00:00:00 2001 From: "Anirudh Rayabharam (Microsoft)" Date: Mon, 5 Jan 2026 12:28:36 +0000 Subject: [PATCH 297/443] mshv: add definitions for arm64 gpa intercepts Add definitions required for handling GPA intercepts on arm64. Signed-off-by: Anirudh Rayabharam (Microsoft) Reviewed-by: Stanislav Kinsburskii Signed-off-by: Wei Liu --- include/hyperv/hvhdk.h | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/include/hyperv/hvhdk.h b/include/hyperv/hvhdk.h index 469186df7826..08965970c17d 100644 --- a/include/hyperv/hvhdk.h +++ b/include/hyperv/hvhdk.h @@ -800,6 +800,53 @@ struct hv_x64_memory_intercept_message { u8 instruction_bytes[16]; } __packed; +#if IS_ENABLED(CONFIG_ARM64) +union hv_arm64_vp_execution_state { + u16 as_uint16; + struct { + u16 cpl:2; /* Exception Level (EL) */ + u16 debug_active:1; + u16 interruption_pending:1; + u16 vtl:4; + u16 virtualization_fault_active:1; + u16 reserved:7; + } __packed; +}; + +struct hv_arm64_intercept_message_header { + u32 vp_index; + u8 instruction_length; + u8 intercept_access_type; + union hv_arm64_vp_execution_state execution_state; + u64 pc; + u64 cpsr; +} __packed; + +union hv_arm64_memory_access_info { + u8 as_uint8; + struct { + u8 gva_valid:1; + u8 gva_gpa_valid:1; + u8 hypercall_output_pending:1; + u8 reserved:5; + } __packed; +}; + +struct hv_arm64_memory_intercept_message { + struct hv_arm64_intercept_message_header header; + u32 cache_type; /* enum hv_cache_type */ + u8 instruction_byte_count; + union hv_arm64_memory_access_info memory_access_info; + u16 reserved1; + u8 instruction_bytes[4]; + u32 reserved2; + u64 guest_virtual_address; + u64 guest_physical_address; + u64 syndrome; +} __packed; + +#endif /* CONFIG_ARM64 */ + /* * Dispatch state for the VP communicated by the hypervisor to the * VP-dispatching thread in the root on return from HVCALL_DISPATCH_VP. From 12ffd561d2de28825f39e15e8d22346d26b09688 Mon Sep 17 00:00:00 2001 From: "Anirudh Rayabharam (Microsoft)" Date: Mon, 5 Jan 2026 12:28:37 +0000 Subject: [PATCH 298/443] mshv: handle gpa intercepts for arm64 The mshv driver now uses movable pages for guests. For arm64 guests to be functional, handle gpa intercepts for arm64 too (the current code implements handling only for x86). Move some arch-agnostic functions out of #ifdefs so that they can be re-used. Fixes: b9a66cd5ccbb ("mshv: Add support for movable memory regions") Signed-off-by: Anirudh Rayabharam (Microsoft) Signed-off-by: Wei Liu --- drivers/hv/mshv_root_main.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c index 99fdbc3988aa..681b58154d5e 100644 --- a/drivers/hv/mshv_root_main.c +++ b/drivers/hv/mshv_root_main.c @@ -611,7 +611,6 @@ mshv_partition_region_by_gfn(struct mshv_partition *partition, u64 gfn) return NULL; } -#ifdef CONFIG_X86_64 static struct mshv_mem_region * mshv_partition_region_by_gfn_get(struct mshv_partition *p, u64 gfn) { @@ -643,12 +642,17 @@ static bool mshv_handle_gpa_intercept(struct mshv_vp *vp) { struct mshv_partition *p = vp->vp_partition; struct mshv_mem_region *region; - struct hv_x64_memory_intercept_message *msg; bool ret; u64 gfn; - - msg = (struct hv_x64_memory_intercept_message *) +#if defined(CONFIG_X86_64) + struct hv_x64_memory_intercept_message *msg = + (struct hv_x64_memory_intercept_message *) vp->vp_intercept_msg_page->u.payload; +#elif defined(CONFIG_ARM64) + struct hv_arm64_memory_intercept_message *msg = + (struct hv_arm64_memory_intercept_message *) + vp->vp_intercept_msg_page->u.payload; +#endif gfn = HVPFN_DOWN(msg->guest_physical_address); @@ -666,9 +670,6 @@ static bool mshv_handle_gpa_intercept(struct mshv_vp *vp) return ret; } -#else /* CONFIG_X86_64 */ -static bool mshv_handle_gpa_intercept(struct mshv_vp *vp) { return false; } -#endif /* CONFIG_X86_64 */ static bool mshv_vp_handle_intercept(struct mshv_vp *vp) { From ab2be3af8c4ea57f779474cd2a2fe8dd4ad537a6 Mon Sep 17 00:00:00 2001 From: Zhang Heng Date: Thu, 15 Jan 2026 09:58:44 +0800 Subject: [PATCH 299/443] ALSA: hda/realtek: Add quirk for HP Pavilion x360 to enable mute LED This quirk enables mute LED on HP Pavilion x360 2-in-1 Laptop 14-ek0xxx, which use ALC245 codec. Link: https://bugzilla.kernel.org/show_bug.cgi?id=220220 Cc: Signed-off-by: Zhang Heng Link: https://patch.msgid.link/20260115015844.3129890-1-zhangheng@kylinos.cn Signed-off-by: Takashi Iwai --- sound/hda/codecs/realtek/alc269.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index dbbe8b498583..29469e549791 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -6613,6 +6613,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8a30, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8a31, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8a34, "HP Pavilion x360 2-in-1 Laptop 14-ek0xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), SND_PCI_QUIRK(0x103c, 0x8a4f, "HP Victus 15-fa0xxx (MB 8A4F)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), SND_PCI_QUIRK(0x103c, 0x8a6e, "HP EDNA 360", ALC287_FIXUP_CS35L41_I2C_4), SND_PCI_QUIRK(0x103c, 0x8a74, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED), From 0d26ca8ec461c01f682402f73a89643f4fefbbb3 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 15 Jan 2026 18:50:48 +0800 Subject: [PATCH 300/443] LoongArch: Remove redundant code in head.S SETUP_MODES already setup the initial values of CSR.CRMD, CSR.PRMD and CSR.EUEN, so the redundant open code can be removed. Fixes: 7b2afeafaf9c2d5 ("LoongArch: Adjust boot & setup for 32BIT/64BIT") Signed-off-by: Huacai Chen --- arch/loongarch/kernel/head.S | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S index 7f288e89573b..4eed7bc312a8 100644 --- a/arch/loongarch/kernel/head.S +++ b/arch/loongarch/kernel/head.S @@ -126,14 +126,6 @@ SYM_CODE_START(smpboot_entry) LONG_LI t1, CSR_STFILL csrxchg t0, t1, LOONGARCH_CSR_IMPCTL1 #endif - /* Enable PG */ - li.w t0, 0xb0 # PLV=0, IE=0, PG=1 - csrwr t0, LOONGARCH_CSR_CRMD - li.w t0, 0x04 # PLV=0, PIE=1, PWE=0 - csrwr t0, LOONGARCH_CSR_PRMD - li.w t0, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0 - csrwr t0, LOONGARCH_CSR_EUEN - la.pcrel t0, cpuboot_data ld.d sp, t0, CPU_BOOT_STACK ld.d tp, t0, CPU_BOOT_TINFO From be5a39e7994ec9f003c8569b670c794a4e5d1551 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 14 Jan 2026 22:08:35 +0000 Subject: [PATCH 301/443] ASoC: rt5640: Fix duplicate clock properties in DT binding Not quite overlapping changes to the rt5640 binding resulted in duplicate definitions of the clocks and clock-names properties. Delete one of them, preferring the simpler one. Reported-by: Jon Hunter Closes: https://lore.kernel.org/r/0e68c5f4-f68d-4544-bc7a-40694829db75@nvidia.com Signed-off-by: Mark Brown Link: https://patch.msgid.link/20260114-asoc-fix-rt5640-dt-clocks-v1-1-421d438673c2@kernel.org Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/realtek,rt5640.yaml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml index 02591d6be12b..2eb631950963 100644 --- a/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml +++ b/Documentation/devicetree/bindings/sound/realtek,rt5640.yaml @@ -44,14 +44,6 @@ properties: - realtek,rt5640 - realtek,rt5639 - clocks: - items: - - description: phandle and clock specifier for codec MCLK. - - clock-names: - items: - - const: mclk - reg: maxItems: 1 From 46b8d0888f01f250fbd24d00ff80b755c3c42cd4 Mon Sep 17 00:00:00 2001 From: Shenghao Ding Date: Thu, 15 Jan 2026 20:49:06 +0800 Subject: [PATCH 302/443] ALSA: hda/tas2781: Add newly-released HP laptop HP released the new laptop with the subid 0x103C. Signed-off-by: Shenghao Ding Link: https://patch.msgid.link/20260115124907.629-1-shenghao-ding@ti.com Signed-off-by: Takashi Iwai --- sound/hda/codecs/side-codecs/tas2781_hda_i2c.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index 0e4bda3a544e..624a822341bb 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -2,7 +2,7 @@ // // TAS2781 HDA I2C driver // -// Copyright 2023 - 2025 Texas Instruments, Inc. +// Copyright 2023 - 2026 Texas Instruments, Inc. // // Author: Shenghao Ding // Current maintainer: Baojun Xu @@ -571,6 +571,9 @@ static int tas2781_hda_bind(struct device *dev, struct device *master, case 0x1028: tas_hda->catlog_id = DELL; break; + case 0x103C: + tas_hda->catlog_id = HP; + break; default: tas_hda->catlog_id = LENOVO; break; From ec19ed2b3e2af8ec5380400cdee9cb6560144506 Mon Sep 17 00:00:00 2001 From: Chaitanya Kulkarni Date: Mon, 12 Jan 2026 15:19:28 -0800 Subject: [PATCH 303/443] rnbd-clt: fix refcount underflow in device unmap path During device unmapping (triggered by module unload or explicit unmap), a refcount underflow occurs causing a use-after-free warning: [14747.574913] ------------[ cut here ]------------ [14747.574916] refcount_t: underflow; use-after-free. [14747.574917] WARNING: lib/refcount.c:28 at refcount_warn_saturate+0x55/0x90, CPU#9: kworker/9:1/378 [14747.574924] Modules linked in: rnbd_client(-) rtrs_client rnbd_server rtrs_server rtrs_core ... [14747.574998] CPU: 9 UID: 0 PID: 378 Comm: kworker/9:1 Tainted: G O N 6.19.0-rc3lblk-fnext+ #42 PREEMPT(voluntary) [14747.575005] Workqueue: rnbd_clt_wq unmap_device_work [rnbd_client] [14747.575010] RIP: 0010:refcount_warn_saturate+0x55/0x90 [14747.575037] Call Trace: [14747.575038] [14747.575038] rnbd_clt_unmap_device+0x170/0x1d0 [rnbd_client] [14747.575044] process_one_work+0x211/0x600 [14747.575052] worker_thread+0x184/0x330 [14747.575055] ? __pfx_worker_thread+0x10/0x10 [14747.575058] kthread+0x10d/0x250 [14747.575062] ? __pfx_kthread+0x10/0x10 [14747.575066] ret_from_fork+0x319/0x390 [14747.575069] ? __pfx_kthread+0x10/0x10 [14747.575072] ret_from_fork_asm+0x1a/0x30 [14747.575083] [14747.575096] ---[ end trace 0000000000000000 ]--- Befor this patch :- The bug is a double kobject_put() on dev->kobj during device cleanup. Kobject Lifecycle: kobject_init_and_add() sets kobj.kref = 1 (initialization) kobject_put() sets kobj.kref = 0 (should be called once) * Before this patch: rnbd_clt_unmap_device() rnbd_destroy_sysfs() kobject_del(&dev->kobj) [remove from sysfs] kobject_put(&dev->kobj) PUT #1 (WRONG!) kref: 1 to 0 rnbd_dev_release() kfree(dev) [DEVICE FREED!] rnbd_destroy_gen_disk() [use-after-free!] rnbd_clt_put_dev() refcount_dec_and_test(&dev->refcount) kobject_put(&dev->kobj) PUT #2 (UNDERFLOW!) kref: 0 to -1 [WARNING!] The first kobject_put() in rnbd_destroy_sysfs() prematurely frees the device via rnbd_dev_release(), then the second kobject_put() in rnbd_clt_put_dev() causes refcount underflow. * After this patch :- Remove kobject_put() from rnbd_destroy_sysfs(). This function should only remove sysfs visibility (kobject_del), not manage object lifetime. Call Graph (FIXED): rnbd_clt_unmap_device() rnbd_destroy_sysfs() kobject_del(&dev->kobj) [remove from sysfs only] [kref unchanged: 1] rnbd_destroy_gen_disk() [device still valid] rnbd_clt_put_dev() refcount_dec_and_test(&dev->refcount) kobject_put(&dev->kobj) ONLY PUT (CORRECT!) kref: 1 to 0 [BALANCED] rnbd_dev_release() kfree(dev) [CLEAN DESTRUCTION] This follows the kernel pattern where sysfs removal (kobject_del) is separate from object destruction (kobject_put). Fixes: 581cf833cac4 ("block: rnbd: add .release to rnbd_dev_ktype") Signed-off-by: Chaitanya Kulkarni Acked-by: Jack Wang Reviewed-by: Jack Wang Signed-off-by: Jens Axboe --- drivers/block/rnbd/rnbd-clt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/block/rnbd/rnbd-clt.c b/drivers/block/rnbd/rnbd-clt.c index d1c354636315..8194a970f002 100644 --- a/drivers/block/rnbd/rnbd-clt.c +++ b/drivers/block/rnbd/rnbd-clt.c @@ -1662,7 +1662,6 @@ static void destroy_sysfs(struct rnbd_clt_dev *dev, /* To avoid deadlock firstly remove itself */ sysfs_remove_file_self(&dev->kobj, sysfs_self); kobject_del(&dev->kobj); - kobject_put(&dev->kobj); } } From be55257fab181b93af38f8c4b1b3cb453a78d742 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 13 Jan 2026 07:22:42 -0800 Subject: [PATCH 304/443] ftrace: Do not over-allocate ftrace memory The pg_remaining calculation in ftrace_process_locs() assumes that ENTRIES_PER_PAGE multiplied by 2^order equals the actual capacity of the allocated page group. However, ENTRIES_PER_PAGE is PAGE_SIZE / ENTRY_SIZE (integer division). When PAGE_SIZE is not a multiple of ENTRY_SIZE (e.g. 4096 / 24 = 170 with remainder 16), high-order allocations (like 256 pages) have significantly more capacity than 256 * 170. This leads to pg_remaining being underestimated, which in turn makes skip (derived from skipped - pg_remaining) larger than expected, causing the WARN(skip != remaining) to trigger. Extra allocated pages for ftrace: 2 with 654 skipped WARNING: CPU: 0 PID: 0 at kernel/trace/ftrace.c:7295 ftrace_process_locs+0x5bf/0x5e0 A similar problem in ftrace_allocate_records() can result in allocating too many pages. This can trigger the second warning in ftrace_process_locs(). Extra allocated pages for ftrace WARNING: CPU: 0 PID: 0 at kernel/trace/ftrace.c:7276 ftrace_process_locs+0x548/0x580 Use the actual capacity of a page group to determine the number of pages to allocate. Have ftrace_allocate_pages() return the number of allocated pages to avoid having to calculate it. Use the actual page group capacity when validating the number of unused pages due to skipped entries. Drop the definition of ENTRIES_PER_PAGE since it is no longer used. Cc: stable@vger.kernel.org Fixes: 4a3efc6baff93 ("ftrace: Update the mcount_loc check of skipped entries") Link: https://patch.msgid.link/20260113152243.3557219-1-linux@roeck-us.net Signed-off-by: Guenter Roeck Signed-off-by: Steven Rostedt (Google) --- kernel/trace/ftrace.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index ef2d5dca6f70..aa758efc3731 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1148,7 +1148,6 @@ struct ftrace_page { }; #define ENTRY_SIZE sizeof(struct dyn_ftrace) -#define ENTRIES_PER_PAGE (PAGE_SIZE / ENTRY_SIZE) static struct ftrace_page *ftrace_pages_start; static struct ftrace_page *ftrace_pages; @@ -3834,7 +3833,8 @@ static int ftrace_update_code(struct module *mod, struct ftrace_page *new_pgs) return 0; } -static int ftrace_allocate_records(struct ftrace_page *pg, int count) +static int ftrace_allocate_records(struct ftrace_page *pg, int count, + unsigned long *num_pages) { int order; int pages; @@ -3844,7 +3844,7 @@ static int ftrace_allocate_records(struct ftrace_page *pg, int count) return -EINVAL; /* We want to fill as much as possible, with no empty pages */ - pages = DIV_ROUND_UP(count, ENTRIES_PER_PAGE); + pages = DIV_ROUND_UP(count * ENTRY_SIZE, PAGE_SIZE); order = fls(pages) - 1; again: @@ -3859,6 +3859,7 @@ static int ftrace_allocate_records(struct ftrace_page *pg, int count) } ftrace_number_of_pages += 1 << order; + *num_pages += 1 << order; ftrace_number_of_groups++; cnt = (PAGE_SIZE << order) / ENTRY_SIZE; @@ -3887,12 +3888,14 @@ static void ftrace_free_pages(struct ftrace_page *pages) } static struct ftrace_page * -ftrace_allocate_pages(unsigned long num_to_init) +ftrace_allocate_pages(unsigned long num_to_init, unsigned long *num_pages) { struct ftrace_page *start_pg; struct ftrace_page *pg; int cnt; + *num_pages = 0; + if (!num_to_init) return NULL; @@ -3906,7 +3909,7 @@ ftrace_allocate_pages(unsigned long num_to_init) * waste as little space as possible. */ for (;;) { - cnt = ftrace_allocate_records(pg, num_to_init); + cnt = ftrace_allocate_records(pg, num_to_init, num_pages); if (cnt < 0) goto free_pages; @@ -7192,8 +7195,6 @@ static int ftrace_process_locs(struct module *mod, if (!count) return 0; - pages = DIV_ROUND_UP(count, ENTRIES_PER_PAGE); - /* * Sorting mcount in vmlinux at build time depend on * CONFIG_BUILDTIME_MCOUNT_SORT, while mcount loc in @@ -7206,7 +7207,7 @@ static int ftrace_process_locs(struct module *mod, test_is_sorted(start, count); } - start_pg = ftrace_allocate_pages(count); + start_pg = ftrace_allocate_pages(count, &pages); if (!start_pg) return -ENOMEM; @@ -7305,27 +7306,27 @@ static int ftrace_process_locs(struct module *mod, /* We should have used all pages unless we skipped some */ if (pg_unuse) { unsigned long pg_remaining, remaining = 0; - unsigned long skip; + long skip; /* Count the number of entries unused and compare it to skipped. */ - pg_remaining = (ENTRIES_PER_PAGE << pg->order) - pg->index; + pg_remaining = (PAGE_SIZE << pg->order) / ENTRY_SIZE - pg->index; if (!WARN(skipped < pg_remaining, "Extra allocated pages for ftrace")) { skip = skipped - pg_remaining; - for (pg = pg_unuse; pg; pg = pg->next) + for (pg = pg_unuse; pg && skip > 0; pg = pg->next) { remaining += 1 << pg->order; + skip -= (PAGE_SIZE << pg->order) / ENTRY_SIZE; + } pages -= remaining; - skip = DIV_ROUND_UP(skip, ENTRIES_PER_PAGE); - /* * Check to see if the number of pages remaining would * just fit the number of entries skipped. */ - WARN(skip != remaining, "Extra allocated pages for ftrace: %lu with %lu skipped", + WARN(pg || skip > 0, "Extra allocated pages for ftrace: %lu with %lu skipped", remaining, skipped); } /* Need to synchronize with ftrace_location_range() */ From 2150467fc61ddb473145ace99afdcde88b54af8e Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Wed, 17 Dec 2025 10:47:44 +0000 Subject: [PATCH 305/443] Revert "arm64: tegra: Add interconnect properties for Tegra210" Commit 59a42707a094 ("arm64: tegra: Add interconnect properties for Tegra210") populated interconnect properties for Tegra210 and this is preventing the Tegra DRM driver from probing successfully. The following error is observed on boot ... drm drm: failed to initialize 54240000.dc: -517 For now revert this change, until a fix is available. Fixes: 59a42707a094 ("arm64: tegra: Add interconnect properties for Tegra210") Signed-off-by: Jon Hunter Acked-by: Thierry Reding Signed-off-by: Arnd Bergmann --- arch/arm64/boot/dts/nvidia/tegra210.dtsi | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi index 709da31d5785..137aa8375257 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi @@ -202,19 +202,6 @@ nvidia,outputs = <&dsia &dsib &sor0 &sor1>; nvidia,head = <0>; - - interconnects = <&mc TEGRA210_MC_DISPLAY0A &emc>, - <&mc TEGRA210_MC_DISPLAY0B &emc>, - <&mc TEGRA210_MC_DISPLAY0C &emc>, - <&mc TEGRA210_MC_DISPLAYHC &emc>, - <&mc TEGRA210_MC_DISPLAYD &emc>, - <&mc TEGRA210_MC_DISPLAYT &emc>; - interconnect-names = "wina", - "winb", - "winc", - "cursor", - "wind", - "wint"; }; dc@54240000 { @@ -230,15 +217,6 @@ nvidia,outputs = <&dsia &dsib &sor0 &sor1>; nvidia,head = <1>; - - interconnects = <&mc TEGRA210_MC_DISPLAY0AB &emc>, - <&mc TEGRA210_MC_DISPLAY0BB &emc>, - <&mc TEGRA210_MC_DISPLAY0CB &emc>, - <&mc TEGRA210_MC_DISPLAYHCB &emc>; - interconnect-names = "wina", - "winb", - "winc", - "cursor"; }; dsia: dsi@54300000 { @@ -1052,7 +1030,6 @@ #iommu-cells = <1>; #reset-cells = <1>; - #interconnect-cells = <1>; }; emc: external-memory-controller@7001b000 { @@ -1066,7 +1043,6 @@ nvidia,memory-controller = <&mc>; operating-points-v2 = <&emc_icc_dvfs_opp_table>; - #interconnect-cells = <0>; #cooling-cells = <2>; }; From 8bb9fd440aec080f69d54697d069c295940aa995 Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Thu, 15 Jan 2026 10:03:35 +0800 Subject: [PATCH 306/443] MAINTAINERS: update email address for Yixun Lan Switch my email address to kernel.org account for more convenience. Also add entries to the mailmap. Signed-off-by: Yixun Lan Link: https://lore.kernel.org/r/20260115-11-maintainer-dlan-v1-1-64bb698da846@kernel.org Signed-off-by: Arnd Bergmann --- .mailmap | 2 ++ MAINTAINERS | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index fa018b5bd533..4aabbc1d2f56 100644 --- a/.mailmap +++ b/.mailmap @@ -876,6 +876,8 @@ Wolfram Sang Yakir Yang Yanteng Si Ying Huang +Yixun Lan +Yixun Lan Yosry Ahmed Yu-Chun Lin Yusuke Goda diff --git a/MAINTAINERS b/MAINTAINERS index 0d044a58cbfe..5dfbe58cb00f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22526,7 +22526,7 @@ F: drivers/mailbox/riscv-sbi-mpxy-mbox.c F: include/linux/mailbox/riscv-rpmi-message.h RISC-V SPACEMIT SoC Support -M: Yixun Lan +M: Yixun Lan L: linux-riscv@lists.infradead.org L: spacemit@lists.linux.dev S: Maintained From d5811e6297f3fd9020ac31f51fc317dfdb260cb0 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 10 Jan 2026 18:53:34 -0500 Subject: [PATCH 307/443] NFS: Fix size read races in truncate, fallocate and copy offload If the pre-operation file size is read before locking the inode and quiescing O_DIRECT writes, then nfs_truncate_last_folio() might end up overwriting valid file data. Fixes: b1817b18ff20 ("NFS: Protect against 'eof page pollution'") Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 10 ++++++---- fs/nfs/io.c | 2 ++ fs/nfs/nfs42proc.c | 29 +++++++++++++++++++---------- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 84049f3cd340..de2cce1d08f4 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -716,7 +716,7 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, { struct inode *inode = d_inode(dentry); struct nfs_fattr *fattr; - loff_t oldsize = i_size_read(inode); + loff_t oldsize; int error = 0; kuid_t task_uid = current_fsuid(); kuid_t owner_uid = inode->i_uid; @@ -727,6 +727,10 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) attr->ia_valid &= ~ATTR_MODE; + if (S_ISREG(inode->i_mode)) + nfs_file_block_o_direct(NFS_I(inode)); + + oldsize = i_size_read(inode); if (attr->ia_valid & ATTR_SIZE) { BUG_ON(!S_ISREG(inode->i_mode)); @@ -774,10 +778,8 @@ nfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, trace_nfs_setattr_enter(inode); /* Write all dirty data */ - if (S_ISREG(inode->i_mode)) { - nfs_file_block_o_direct(NFS_I(inode)); + if (S_ISREG(inode->i_mode)) nfs_sync_inode(inode); - } fattr = nfs_alloc_fattr_with_label(NFS_SERVER(inode)); if (fattr == NULL) { diff --git a/fs/nfs/io.c b/fs/nfs/io.c index d275b0a250bf..8337f0ae852d 100644 --- a/fs/nfs/io.c +++ b/fs/nfs/io.c @@ -84,6 +84,7 @@ nfs_start_io_write(struct inode *inode) nfs_file_block_o_direct(NFS_I(inode)); return err; } +EXPORT_SYMBOL_GPL(nfs_start_io_write); /** * nfs_end_io_write - declare that the buffered write operation is done @@ -97,6 +98,7 @@ nfs_end_io_write(struct inode *inode) { up_write(&inode->i_rwsem); } +EXPORT_SYMBOL_GPL(nfs_end_io_write); /* Call with exclusively locked inode->i_rwsem */ static void nfs_block_buffered(struct nfs_inode *nfsi, struct inode *inode) diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c index d537fb0c230e..c08520828708 100644 --- a/fs/nfs/nfs42proc.c +++ b/fs/nfs/nfs42proc.c @@ -114,7 +114,6 @@ static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep, exception.inode = inode; exception.state = lock->open_context->state; - nfs_file_block_o_direct(NFS_I(inode)); err = nfs_sync_inode(inode); if (err) goto out; @@ -138,13 +137,17 @@ int nfs42_proc_allocate(struct file *filep, loff_t offset, loff_t len) .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE], }; struct inode *inode = file_inode(filep); - loff_t oldsize = i_size_read(inode); + loff_t oldsize; int err; if (!nfs_server_capable(inode, NFS_CAP_ALLOCATE)) return -EOPNOTSUPP; - inode_lock(inode); + err = nfs_start_io_write(inode); + if (err) + return err; + + oldsize = i_size_read(inode); err = nfs42_proc_fallocate(&msg, filep, offset, len); @@ -155,7 +158,7 @@ int nfs42_proc_allocate(struct file *filep, loff_t offset, loff_t len) NFS_SERVER(inode)->caps &= ~(NFS_CAP_ALLOCATE | NFS_CAP_ZERO_RANGE); - inode_unlock(inode); + nfs_end_io_write(inode); return err; } @@ -170,7 +173,9 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len) if (!nfs_server_capable(inode, NFS_CAP_DEALLOCATE)) return -EOPNOTSUPP; - inode_lock(inode); + err = nfs_start_io_write(inode); + if (err) + return err; err = nfs42_proc_fallocate(&msg, filep, offset, len); if (err == 0) @@ -179,7 +184,7 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len) NFS_SERVER(inode)->caps &= ~(NFS_CAP_DEALLOCATE | NFS_CAP_ZERO_RANGE); - inode_unlock(inode); + nfs_end_io_write(inode); return err; } @@ -189,14 +194,17 @@ int nfs42_proc_zero_range(struct file *filep, loff_t offset, loff_t len) .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ZERO_RANGE], }; struct inode *inode = file_inode(filep); - loff_t oldsize = i_size_read(inode); + loff_t oldsize; int err; if (!nfs_server_capable(inode, NFS_CAP_ZERO_RANGE)) return -EOPNOTSUPP; - inode_lock(inode); + err = nfs_start_io_write(inode); + if (err) + return err; + oldsize = i_size_read(inode); err = nfs42_proc_fallocate(&msg, filep, offset, len); if (err == 0) { nfs_truncate_last_folio(inode->i_mapping, oldsize, @@ -205,7 +213,7 @@ int nfs42_proc_zero_range(struct file *filep, loff_t offset, loff_t len) } else if (err == -EOPNOTSUPP) NFS_SERVER(inode)->caps &= ~NFS_CAP_ZERO_RANGE; - inode_unlock(inode); + nfs_end_io_write(inode); return err; } @@ -416,7 +424,7 @@ static ssize_t _nfs42_proc_copy(struct file *src, struct nfs_server *src_server = NFS_SERVER(src_inode); loff_t pos_src = args->src_pos; loff_t pos_dst = args->dst_pos; - loff_t oldsize_dst = i_size_read(dst_inode); + loff_t oldsize_dst; size_t count = args->count; ssize_t status; @@ -461,6 +469,7 @@ static ssize_t _nfs42_proc_copy(struct file *src, &src_lock->open_context->state->flags); set_bit(NFS_CLNT_DST_SSC_COPY_STATE, &dst_lock->open_context->state->flags); + oldsize_dst = i_size_read(dst_inode); status = nfs4_call_sync(dst_server->client, dst_server, &msg, &args->seq_args, &res->seq_res, 0); From 375410bb9a403009a44af3cc7f087090da076e09 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 6 Jan 2026 11:41:13 +0100 Subject: [PATCH 308/443] sched/deadline: Ensure get_prio_dl() is up-to-date Pratheek tripped a WARN and noted the following issue: > Inspecting the set of events that led to the warning being triggered > showed the following: > > systemd-1 [008] dN.31 ...: do_set_cpus_allowed: set_cpus_allowed begin! > > systemd-1 [008] dN.31 ...: sched_change_begin: Begin! > systemd-1 [008] dN.31 ...: sched_change_begin: Before dequeue_task()! > systemd-1 [008] dN.31 ...: update_curr_dl_se: update_curr_dl_se: ENQUEUE_REPLENISH > systemd-1 [008] dN.31 ...: enqueue_dl_entity: enqueue_dl_entity: ENQUEUE_REPLENISH > systemd-1 [008] dN.31 ...: replenish_dl_entity: Replenish before: 14815760217 > systemd-1 [008] dN.31 ...: replenish_dl_entity: Replenish after: 14816960047 > systemd-1 [008] dN.31 ...: sched_change_begin: Before put_prev_task()! > > systemd-1 [008] dN.31 ...: sched_change_end: Before enqueue_task()! > systemd-1 [008] dN.31 ...: sched_change_end: Before put_prev_task()! > systemd-1 [008] dN.31 ...: prio_changed_dl: Queuing pull task on prio change: 14815760217 -> 14816960047 > systemd-1 [008] dN.31 ...: prio_changed_dl: Queuing balance callback! > systemd-1 [008] dN.31 ...: sched_change_end: End! > > systemd-1 [008] dN.31 ...: do_set_cpus_allowed: set_cpus_allowed end! > systemd-1 [008] dN.21 ...: __schedule: Woops! Balance callback found! > > 1. sched_change_begin() from guard(sched_change) in > do_set_cpus_allowed() stashes the priority, which for the deadline > task, is "p->dl.deadline". > 2. The dequeue of the deadline task replenishes the deadline. > 3. The task is enqueued back after guard's scope ends and since there is > no *_CLASS flags set, sched_change_end() calls > dl_sched_class->prio_changed() which compares the deadline. > 4. Since deadline was moved on dequeue, prio_changed_dl() sees the value > differ from the stashed value and queues a balance pull callback. > 5. do_set_cpus_allowed() finishes and drops the rq_lock without doing a > do_balance_callbacks(). > 6. Grabbing the rq_lock() at subsequent __schedule() triggers the > warning since the balance pull callback was never executed before > dropping the lock. Meaning get_prio_dl() ought to update current and return an up-to-date value. Fixes: 6455ad5346c9 ("sched: Move sched_class::prio_changed() into the change pattern") Reported-by: K Prateek Nayak Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: K Prateek Nayak Tested-by: K Prateek Nayak Link: https://patch.msgid.link/20260106104113.GX3707891@noisy.programming.kicks-ass.net --- kernel/sched/deadline.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index b5c19b17e386..b7acf74b6527 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -3296,6 +3296,12 @@ static void switched_to_dl(struct rq *rq, struct task_struct *p) static u64 get_prio_dl(struct rq *rq, struct task_struct *p) { + /* + * Make sure to update current so we don't return a stale value. + */ + if (task_current_donor(rq, p)) + update_curr_dl(rq); + return p->dl.deadline; } From 4de9ff76067b40c3660df73efaea57389e62ea7a Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 13 Jan 2026 12:57:14 +0100 Subject: [PATCH 309/443] sched/deadline: Avoid double update_rq_clock() When setup_new_dl_entity() is called from enqueue_task_dl() -> enqueue_dl_entity(), the rq-clock should already be updated, and calling update_rq_clock() again is not right. Move the update_rq_clock() to the one other caller of setup_new_dl_entity(): sched_init_dl_server(). Fixes: 9f239df55546 ("sched/deadline: Initialize dl_servers after SMP") Reported-by: Pierre Gondois Signed-off-by: Peter Zijlstra (Intel) Tested-by: Pierre Gondois Link: https://patch.msgid.link/20260113115622.GA831285@noisy.programming.kicks-ass.net --- kernel/sched/deadline.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index b7acf74b6527..5d6f3cced740 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -752,8 +752,6 @@ static inline void setup_new_dl_entity(struct sched_dl_entity *dl_se) struct dl_rq *dl_rq = dl_rq_of_se(dl_se); struct rq *rq = rq_of_dl_rq(dl_rq); - update_rq_clock(rq); - WARN_ON(is_dl_boosted(dl_se)); WARN_ON(dl_time_before(rq_clock(rq), dl_se->deadline)); @@ -1839,6 +1837,7 @@ void sched_init_dl_servers(void) rq = cpu_rq(cpu); guard(rq_lock_irq)(rq); + update_rq_clock(rq); dl_se = &rq->fair_server; From 49041e87f9cd3e6be8926b80b3fee71e89323e1c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 15 Jan 2026 09:16:44 +0100 Subject: [PATCH 310/443] sched: Fold rq-pin swizzle into __balance_callbacks() Prepare for more users needing the rq-pin swizzle. Signed-off-by: Peter Zijlstra (Intel) Tested-by: Pierre Gondois Tested-by: Juri Lelli Link: https://patch.msgid.link/20260114130528.GB831285@noisy.programming.kicks-ass.net --- kernel/sched/core.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 60afadb6eede..842a3adaf746 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -4950,9 +4950,13 @@ struct balance_callback *splice_balance_callbacks(struct rq *rq) return __splice_balance_callbacks(rq, true); } -static void __balance_callbacks(struct rq *rq) +static void __balance_callbacks(struct rq *rq, struct rq_flags *rf) { + if (rf) + rq_unpin_lock(rq, rf); do_balance_callbacks(rq, __splice_balance_callbacks(rq, false)); + if (rf) + rq_repin_lock(rq, rf); } void balance_callbacks(struct rq *rq, struct balance_callback *head) @@ -4991,7 +4995,7 @@ static inline void finish_lock_switch(struct rq *rq) * prev into current: */ spin_acquire(&__rq_lockp(rq)->dep_map, 0, 0, _THIS_IP_); - __balance_callbacks(rq); + __balance_callbacks(rq, NULL); raw_spin_rq_unlock_irq(rq); } @@ -6867,7 +6871,7 @@ keep_resched: proxy_tag_curr(rq, next); rq_unpin_lock(rq, &rf); - __balance_callbacks(rq); + __balance_callbacks(rq, NULL); raw_spin_rq_unlock_irq(rq); } trace_sched_exit_tp(is_switch); @@ -7362,9 +7366,7 @@ void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task) out_unlock: /* Caller holds task_struct::pi_lock, IRQs are still disabled */ - rq_unpin_lock(rq, &rf); - __balance_callbacks(rq); - rq_repin_lock(rq, &rf); + __balance_callbacks(rq, &rf); __task_rq_unlock(rq, p, &rf); } #endif /* CONFIG_RT_MUTEXES */ From 53439363c0a111f11625982b69c88ee2ce8608ec Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 15 Jan 2026 09:17:49 +0100 Subject: [PATCH 311/443] sched: Audit MOVE vs balance_callbacks The {DE,EN}QUEUE_MOVE flag indicates a task is allowed to change priority, which means there could be balance callbacks queued. Therefore audit all MOVE users and make sure they do run balance callbacks before dropping rq-lock. Fixes: 6455ad5346c9 ("sched: Move sched_class::prio_changed() into the change pattern") Signed-off-by: Peter Zijlstra (Intel) Tested-by: Pierre Gondois Tested-by: Juri Lelli Link: https://patch.msgid.link/20260114130528.GB831285@noisy.programming.kicks-ass.net --- kernel/sched/core.c | 4 +++- kernel/sched/ext.c | 1 + kernel/sched/sched.h | 5 ++++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 842a3adaf746..4d925d7ad097 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -4950,7 +4950,7 @@ struct balance_callback *splice_balance_callbacks(struct rq *rq) return __splice_balance_callbacks(rq, true); } -static void __balance_callbacks(struct rq *rq, struct rq_flags *rf) +void __balance_callbacks(struct rq *rq, struct rq_flags *rf) { if (rf) rq_unpin_lock(rq, rf); @@ -9126,6 +9126,8 @@ void sched_move_task(struct task_struct *tsk, bool for_autogroup) if (resched) resched_curr(rq); + + __balance_callbacks(rq, &rq_guard.rf); } static struct cgroup_subsys_state * diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c index 8f6d8d7f895c..afe28c04d5aa 100644 --- a/kernel/sched/ext.c +++ b/kernel/sched/ext.c @@ -545,6 +545,7 @@ static void scx_task_iter_start(struct scx_task_iter *iter) static void __scx_task_iter_rq_unlock(struct scx_task_iter *iter) { if (iter->locked_task) { + __balance_callbacks(iter->rq, &iter->rf); task_rq_unlock(iter->rq, iter->locked_task, &iter->rf); iter->locked_task = NULL; } diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index e885a935b716..93fce4bbff5e 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -2388,7 +2388,8 @@ extern const u32 sched_prio_to_wmult[40]; * should preserve as much state as possible. * * MOVE - paired with SAVE/RESTORE, explicitly does not preserve the location - * in the runqueue. + * in the runqueue. IOW the priority is allowed to change. Callers + * must expect to deal with balance callbacks. * * NOCLOCK - skip the update_rq_clock() (avoids double updates) * @@ -3969,6 +3970,8 @@ extern void enqueue_task(struct rq *rq, struct task_struct *p, int flags); extern bool dequeue_task(struct rq *rq, struct task_struct *p, int flags); extern struct balance_callback *splice_balance_callbacks(struct rq *rq); + +extern void __balance_callbacks(struct rq *rq, struct rq_flags *rf); extern void balance_callbacks(struct rq *rq, struct balance_callback *head); /* From e008ec6c7904ed99d3b2cb634b6545b008a99288 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 15 Jan 2026 09:25:37 +0100 Subject: [PATCH 312/443] sched: Deadline has dynamic priority While FIFO/RR have static priority, DEADLINE is a dynamic priority scheme. Notably it has static priority -1. Do not assume the priority doesn't change for deadline tasks just because the static priority doesn't change. This ensures DL always sees {DE,EN}QUEUE_MOVE where appropriate. Fixes: ff77e4685359 ("sched/rt: Fix PI handling vs. sched_setscheduler()") Signed-off-by: Peter Zijlstra (Intel) Tested-by: Pierre Gondois Tested-by: Juri Lelli Link: https://patch.msgid.link/20260114130528.GB831285@noisy.programming.kicks-ass.net --- kernel/sched/core.c | 2 +- kernel/sched/syscalls.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 4d925d7ad097..045f83ad261e 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7320,7 +7320,7 @@ void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task) trace_sched_pi_setprio(p, pi_task); oldprio = p->prio; - if (oldprio == prio) + if (oldprio == prio && !dl_prio(prio)) queue_flag &= ~DEQUEUE_MOVE; prev_class = p->sched_class; diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c index cb337de679b8..6f10db3646e7 100644 --- a/kernel/sched/syscalls.c +++ b/kernel/sched/syscalls.c @@ -639,7 +639,7 @@ change: * itself. */ newprio = rt_effective_prio(p, newprio); - if (newprio == oldprio) + if (newprio == oldprio && !dl_prio(newprio)) queue_flags &= ~DEQUEUE_MOVE; } From 627cc25f84466d557d86e5dc67b43a4eea604c80 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 15 Jan 2026 09:27:22 +0100 Subject: [PATCH 313/443] sched/deadline: Use ENQUEUE_MOVE to allow priority change Pierre reported hitting balance callback warnings for deadline tasks after commit 6455ad5346c9 ("sched: Move sched_class::prio_changed() into the change pattern"). It turns out that DEQUEUE_SAVE+ENQUEUE_RESTORE does not preserve DL priority and subsequently trips a balance pass -- where one was not expected. From discussion with Juri and Luca, the purpose of this clause was to deal with tasks new to DL and all those sites will have MOVE set (as well as CLASS, but MOVE is move conservative at this point). Per the previous patches MOVE is audited to always run the balance callbacks, so switch enqueue_dl_entity() to use MOVE for this case. Fixes: 6455ad5346c9 ("sched: Move sched_class::prio_changed() into the change pattern") Reported-by: Pierre Gondois Signed-off-by: Peter Zijlstra (Intel) Tested-by: Pierre Gondois Tested-by: Juri Lelli Link: https://patch.msgid.link/20260114130528.GB831285@noisy.programming.kicks-ass.net --- kernel/sched/deadline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index 5d6f3cced740..c509f2e7d69d 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -2214,7 +2214,7 @@ enqueue_dl_entity(struct sched_dl_entity *dl_se, int flags) update_dl_entity(dl_se); } else if (flags & ENQUEUE_REPLENISH) { replenish_dl_entity(dl_se); - } else if ((flags & ENQUEUE_RESTORE) && + } else if ((flags & ENQUEUE_MOVE) && !is_dl_boosted(dl_se) && dl_time_before(dl_se->deadline, rq_clock(rq_of_dl_se(dl_se)))) { setup_new_dl_entity(dl_se); From 983d014aafb14ee5e4915465bf8948e8f3a723b5 Mon Sep 17 00:00:00 2001 From: Tim Bird Date: Thu, 15 Jan 2026 17:04:31 -0700 Subject: [PATCH 314/443] kernel: modules: Add SPDX license identifier to kmod.c Add a GPL-2.0 license identifier line for this file. kmod.c was originally introduced in the kernel in February of 1998 by Linus Torvalds - who was familiar with kernel licensing at the time this was introduced. Signed-off-by: Tim Bird Signed-off-by: Linus Torvalds --- kernel/module/kmod.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/module/kmod.c b/kernel/module/kmod.c index 25f253812512..a25dccdf7aa7 100644 --- a/kernel/module/kmod.c +++ b/kernel/module/kmod.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * kmod - the kernel module loader * From c4efd7a770c54964bf2d8c98b2f4fd10be13dc54 Mon Sep 17 00:00:00 2001 From: Simon Schippers Date: Tue, 13 Jan 2026 08:51:38 +0100 Subject: [PATCH 315/443] usbnet: fix crash due to missing BQL accounting after resume In commit 7ff14c52049e ("usbnet: Add support for Byte Queue Limits (BQL)"), it was missed that usbnet_resume() may enqueue SKBs using __skb_queue_tail() without reporting them to BQL. As a result, the next call to netdev_completed_queue() triggers a BUG_ON() in dql_completed(), since the SKBs queued during resume were never accounted for. This patch fixes the issue by adding a corresponding netdev_sent_queue() call in usbnet_resume() when SKBs are queued after suspend. Because dev->txq.lock is held at this point, no concurrent calls to netdev_sent_queue() from usbnet_start_xmit() can occur. The crash can be reproduced by generating network traffic (e.g. iperf3 -c ... -t 0), suspending the system, and then waking it up (e.g. rtcwake -m mem -s 5). When testing USB2 Android tethering (cdc_ncm), the system crashed within three suspend/resume cycles without this patch. With the patch applied, no crashes were observed after 90 cycles. Testing with an AX88179 USB Ethernet adapter also showed no crashes. Fixes: 7ff14c52049e ("usbnet: Add support for Byte Queue Limits (BQL)") Reported-by: Bard Liao Tested-by: Bard Liao Tested-by: Simon Schippers Signed-off-by: Simon Schippers Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/20260113075139.6735-1-simon.schippers@tu-dortmund.de Signed-off-by: Jakub Kicinski --- drivers/net/usb/usbnet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 36742e64cff7..35789ff4dd55 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1984,6 +1984,7 @@ int usbnet_resume(struct usb_interface *intf) } else { netif_trans_update(dev->net); __skb_queue_tail(&dev->txq, skb); + netdev_sent_queue(dev->net, skb->len); } } From 0386bd321d0f95d041a7b3d7b07643411b044a96 Mon Sep 17 00:00:00 2001 From: Michal Luczaj Date: Tue, 13 Jan 2026 16:08:18 +0100 Subject: [PATCH 316/443] vsock/virtio: Coalesce only linear skb vsock/virtio common tries to coalesce buffers in rx queue: if a linear skb (with a spare tail room) is followed by a small skb (length limited by GOOD_COPY_LEN = 128), an attempt is made to join them. Since the introduction of MSG_ZEROCOPY support, assumption that a small skb will always be linear is incorrect. In the zerocopy case, data is lost and the linear skb is appended with uninitialized kernel memory. Of all 3 supported virtio-based transports, only loopback-transport is affected. G2H virtio-transport rx queue operates on explicitly linear skbs; see virtio_vsock_alloc_linear_skb() in virtio_vsock_rx_fill(). H2G vhost-transport may allocate non-linear skbs, but only for sizes that are not considered for coalescence; see PAGE_ALLOC_COSTLY_ORDER in virtio_vsock_alloc_skb(). Ensure only linear skbs are coalesced. Note that skb_tailroom(last_skb) > 0 guarantees last_skb is linear. Fixes: 581512a6dc93 ("vsock/virtio: MSG_ZEROCOPY flag support") Signed-off-by: Michal Luczaj Reviewed-by: Stefano Garzarella Link: https://patch.msgid.link/20260113-vsock-recv-coalescence-v2-1-552b17837cf4@rbox.co Signed-off-by: Jakub Kicinski --- net/vmw_vsock/virtio_transport_common.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c index dcc8a1d5851e..26b979ad71f0 100644 --- a/net/vmw_vsock/virtio_transport_common.c +++ b/net/vmw_vsock/virtio_transport_common.c @@ -1359,9 +1359,11 @@ virtio_transport_recv_enqueue(struct vsock_sock *vsk, /* Try to copy small packets into the buffer of last packet queued, * to avoid wasting memory queueing the entire buffer with a small - * payload. + * payload. Skip non-linear (e.g. zerocopy) skbs; these carry payload + * in skb_shinfo. */ - if (len <= GOOD_COPY_LEN && !skb_queue_empty(&vvs->rx_queue)) { + if (len <= GOOD_COPY_LEN && !skb_queue_empty(&vvs->rx_queue) && + !skb_is_nonlinear(skb)) { struct virtio_vsock_hdr *last_hdr; struct sk_buff *last_skb; From a63e5fe0959200afcfefa7640db44c491f102c4c Mon Sep 17 00:00:00 2001 From: Michal Luczaj Date: Tue, 13 Jan 2026 16:08:19 +0100 Subject: [PATCH 317/443] vsock/test: Add test for a linear and non-linear skb getting coalesced Loopback transport can mangle data in rx queue when a linear skb is followed by a small MSG_ZEROCOPY packet. To exercise the logic, send out two packets: a weirdly sized one (to ensure some spare tail room in the skb) and a zerocopy one that's small enough to fit in the spare room of its predecessor. Then, wait for both to land in the rx queue, and check the data received. Faulty packets merger manifests itself by corrupting payload of the later packet. Signed-off-by: Michal Luczaj Reviewed-by: Stefano Garzarella Link: https://patch.msgid.link/20260113-vsock-recv-coalescence-v2-2-552b17837cf4@rbox.co Signed-off-by: Jakub Kicinski --- tools/testing/vsock/vsock_test.c | 5 ++ tools/testing/vsock/vsock_test_zerocopy.c | 74 +++++++++++++++++++++++ tools/testing/vsock/vsock_test_zerocopy.h | 3 + 3 files changed, 82 insertions(+) diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c index bbe3723babdc..27e39354499a 100644 --- a/tools/testing/vsock/vsock_test.c +++ b/tools/testing/vsock/vsock_test.c @@ -2403,6 +2403,11 @@ static struct test_case test_cases[] = { .run_client = test_stream_accepted_setsockopt_client, .run_server = test_stream_accepted_setsockopt_server, }, + { + .name = "SOCK_STREAM virtio MSG_ZEROCOPY coalescence corruption", + .run_client = test_stream_msgzcopy_mangle_client, + .run_server = test_stream_msgzcopy_mangle_server, + }, {}, }; diff --git a/tools/testing/vsock/vsock_test_zerocopy.c b/tools/testing/vsock/vsock_test_zerocopy.c index 9d9a6cb9614a..a31ddfc1cd0c 100644 --- a/tools/testing/vsock/vsock_test_zerocopy.c +++ b/tools/testing/vsock/vsock_test_zerocopy.c @@ -9,14 +9,18 @@ #include #include #include +#include #include #include #include #include #include +#include +#include #include #include "control.h" +#include "timeout.h" #include "vsock_test_zerocopy.h" #include "msg_zerocopy_common.h" @@ -356,3 +360,73 @@ void test_stream_msgzcopy_empty_errq_server(const struct test_opts *opts) control_expectln("DONE"); close(fd); } + +#define GOOD_COPY_LEN 128 /* net/vmw_vsock/virtio_transport_common.c */ + +void test_stream_msgzcopy_mangle_client(const struct test_opts *opts) +{ + char sbuf1[PAGE_SIZE + 1], sbuf2[GOOD_COPY_LEN]; + unsigned long hash; + struct pollfd fds; + int fd, i; + + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); + if (fd < 0) { + perror("connect"); + exit(EXIT_FAILURE); + } + + enable_so_zerocopy_check(fd); + + memset(sbuf1, 'x', sizeof(sbuf1)); + send_buf(fd, sbuf1, sizeof(sbuf1), 0, sizeof(sbuf1)); + + for (i = 0; i < sizeof(sbuf2); i++) + sbuf2[i] = rand() & 0xff; + + send_buf(fd, sbuf2, sizeof(sbuf2), MSG_ZEROCOPY, sizeof(sbuf2)); + + hash = hash_djb2(sbuf2, sizeof(sbuf2)); + control_writeulong(hash); + + fds.fd = fd; + fds.events = 0; + + if (poll(&fds, 1, TIMEOUT * MSEC_PER_SEC) != 1 || + !(fds.revents & POLLERR)) { + perror("poll"); + exit(EXIT_FAILURE); + } + + close(fd); +} + +void test_stream_msgzcopy_mangle_server(const struct test_opts *opts) +{ + unsigned long local_hash, remote_hash; + char rbuf[PAGE_SIZE + 1]; + int fd; + + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); + if (fd < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } + + /* Wait, don't race the (buggy) skbs coalescence. */ + vsock_ioctl_int(fd, SIOCINQ, PAGE_SIZE + 1 + GOOD_COPY_LEN); + + /* Discard the first packet. */ + recv_buf(fd, rbuf, PAGE_SIZE + 1, 0, PAGE_SIZE + 1); + + recv_buf(fd, rbuf, GOOD_COPY_LEN, 0, GOOD_COPY_LEN); + remote_hash = control_readulong(); + local_hash = hash_djb2(rbuf, GOOD_COPY_LEN); + + if (local_hash != remote_hash) { + fprintf(stderr, "Data received corrupted\n"); + exit(EXIT_FAILURE); + } + + close(fd); +} diff --git a/tools/testing/vsock/vsock_test_zerocopy.h b/tools/testing/vsock/vsock_test_zerocopy.h index 3ef2579e024d..d46c91a69f16 100644 --- a/tools/testing/vsock/vsock_test_zerocopy.h +++ b/tools/testing/vsock/vsock_test_zerocopy.h @@ -12,4 +12,7 @@ void test_seqpacket_msgzcopy_server(const struct test_opts *opts); void test_stream_msgzcopy_empty_errq_client(const struct test_opts *opts); void test_stream_msgzcopy_empty_errq_server(const struct test_opts *opts); +void test_stream_msgzcopy_mangle_client(const struct test_opts *opts); +void test_stream_msgzcopy_mangle_server(const struct test_opts *opts); + #endif /* VSOCK_TEST_ZEROCOPY_H */ From 7d7dbafefbe74f5a25efc4807af093b857a7612e Mon Sep 17 00:00:00 2001 From: Ethan Nelson-Moore Date: Mon, 12 Jan 2026 22:39:24 -0800 Subject: [PATCH 318/443] net: usb: dm9601: remove broken SR9700 support The SR9700 chip sends more than one packet in a USB transaction, like the DM962x chips can optionally do, but the dm9601 driver does not support this mode, and the hardware does not have the DM962x MODE_CTL register to disable it, so this driver drops packets on SR9700 devices. The sr9700 driver correctly handles receiving more than one packet per transaction. While the dm9601 driver could be improved to handle this, the easiest way to fix this issue in the short term is to remove the SR9700 device ID from the dm9601 driver so the sr9700 driver is always used. This device ID should not have been in more than one driver to begin with. The "Fixes" commit was chosen so that the patch is automatically included in all kernels that have the sr9700 driver, even though the issue affects dm9601. Fixes: c9b37458e956 ("USB2NET : SR9700 : One chip USB 1.1 USB2NET SR9700Device Driver Support") Signed-off-by: Ethan Nelson-Moore Acked-by: Peter Korsgaard Link: https://patch.msgid.link/20260113063924.74464-1-enelsonmoore@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/usb/dm9601.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index 8b6d6a1b3c2e..2b4716ccf0c5 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -603,10 +603,6 @@ static const struct usb_device_id products[] = { USB_DEVICE(0x0fe6, 0x8101), /* DM9601 USB to Fast Ethernet Adapter */ .driver_info = (unsigned long)&dm9601_info, }, - { - USB_DEVICE(0x0fe6, 0x9700), /* DM9601 USB to Fast Ethernet Adapter */ - .driver_info = (unsigned long)&dm9601_info, - }, { USB_DEVICE(0x0a46, 0x9000), /* DM9000E */ .driver_info = (unsigned long)&dm9601_info, From 220d89df1da6ed95ac74883a72a5fb43abf2a586 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 12 Jan 2026 17:26:21 +0000 Subject: [PATCH 319/443] net: add skb->data_len and (skb>end - skb->tail) to skb_dump() While working on a syzbot report, I found that skb_dump() is lacking two important parts : - skb->data_len. - (skb>end - skb->tail) tailroom is zero if skb is not linear. Signed-off-by: Eric Dumazet Reviewed-by: Willem de Bruijn Link: https://patch.msgid.link/20260112172621.4188700-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/core/skbuff.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index a56133902c0d..61746c2b95f6 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1312,14 +1312,15 @@ void skb_dump(const char *level, const struct sk_buff *skb, bool full_pkt) has_mac = skb_mac_header_was_set(skb); has_trans = skb_transport_header_was_set(skb); - printk("%sskb len=%u headroom=%u headlen=%u tailroom=%u\n" - "mac=(%d,%d) mac_len=%u net=(%d,%d) trans=%d\n" + printk("%sskb len=%u data_len=%u headroom=%u headlen=%u tailroom=%u\n" + "end-tail=%u mac=(%d,%d) mac_len=%u net=(%d,%d) trans=%d\n" "shinfo(txflags=%u nr_frags=%u gso(size=%hu type=%u segs=%hu))\n" "csum(0x%x start=%u offset=%u ip_summed=%u complete_sw=%u valid=%u level=%u)\n" "hash(0x%x sw=%u l4=%u) proto=0x%04x pkttype=%u iif=%d\n" "priority=0x%x mark=0x%x alloc_cpu=%u vlan_all=0x%x\n" "encapsulation=%d inner(proto=0x%04x, mac=%u, net=%u, trans=%u)\n", - level, skb->len, headroom, skb_headlen(skb), tailroom, + level, skb->len, skb->data_len, headroom, skb_headlen(skb), + tailroom, skb->end - skb->tail, has_mac ? skb->mac_header : -1, has_mac ? skb_mac_header_len(skb) : -1, skb->mac_len, From c84fcb79e5dbde0b8d5aeeaf04282d2149aebcf6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Jan 2026 19:12:01 +0000 Subject: [PATCH 320/443] bonding: limit BOND_MODE_8023AD to Ethernet devices BOND_MODE_8023AD makes sense for ARPHRD_ETHER only. syzbot reported: BUG: KASAN: global-out-of-bounds in __hw_addr_create net/core/dev_addr_lists.c:63 [inline] BUG: KASAN: global-out-of-bounds in __hw_addr_add_ex+0x25d/0x760 net/core/dev_addr_lists.c:118 Read of size 16 at addr ffffffff8bf94040 by task syz.1.3580/19497 CPU: 1 UID: 0 PID: 19497 Comm: syz.1.3580 Tainted: G L syzkaller #0 PREEMPT(full) Tainted: [L]=SOFTLOCKUP Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/25/2025 Call Trace: dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120 print_address_description mm/kasan/report.c:378 [inline] print_report+0xca/0x240 mm/kasan/report.c:482 kasan_report+0x118/0x150 mm/kasan/report.c:595 check_region_inline mm/kasan/generic.c:-1 [inline] kasan_check_range+0x2b0/0x2c0 mm/kasan/generic.c:200 __asan_memcpy+0x29/0x70 mm/kasan/shadow.c:105 __hw_addr_create net/core/dev_addr_lists.c:63 [inline] __hw_addr_add_ex+0x25d/0x760 net/core/dev_addr_lists.c:118 __dev_mc_add net/core/dev_addr_lists.c:868 [inline] dev_mc_add+0xa1/0x120 net/core/dev_addr_lists.c:886 bond_enslave+0x2b8b/0x3ac0 drivers/net/bonding/bond_main.c:2180 do_set_master+0x533/0x6d0 net/core/rtnetlink.c:2963 do_setlink+0xcf0/0x41c0 net/core/rtnetlink.c:3165 rtnl_changelink net/core/rtnetlink.c:3776 [inline] __rtnl_newlink net/core/rtnetlink.c:3935 [inline] rtnl_newlink+0x161c/0x1c90 net/core/rtnetlink.c:4072 rtnetlink_rcv_msg+0x7cf/0xb70 net/core/rtnetlink.c:6958 netlink_rcv_skb+0x208/0x470 net/netlink/af_netlink.c:2550 netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline] netlink_unicast+0x82f/0x9e0 net/netlink/af_netlink.c:1344 netlink_sendmsg+0x805/0xb30 net/netlink/af_netlink.c:1894 sock_sendmsg_nosec net/socket.c:727 [inline] __sock_sendmsg+0x21c/0x270 net/socket.c:742 ____sys_sendmsg+0x505/0x820 net/socket.c:2592 ___sys_sendmsg+0x21f/0x2a0 net/socket.c:2646 __sys_sendmsg+0x164/0x220 net/socket.c:2678 do_syscall_32_irqs_on arch/x86/entry/syscall_32.c:83 [inline] __do_fast_syscall_32+0x1dc/0x560 arch/x86/entry/syscall_32.c:307 do_fast_syscall_32+0x34/0x80 arch/x86/entry/syscall_32.c:332 entry_SYSENTER_compat_after_hwframe+0x84/0x8e The buggy address belongs to the variable: lacpdu_mcast_addr+0x0/0x40 Fixes: 872254dd6b1f ("net/bonding: Enable bonding to enslave non ARPHRD_ETHER") Reported-by: syzbot+9c081b17773615f24672@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/6966946b.a70a0220.245e30.0002.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Cc: Andrew Lunn Acked-by: Jay Vosburgh Link: https://patch.msgid.link/20260113191201.3970737-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- drivers/net/bonding/bond_main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 3d56339a8a10..0aca6c937297 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1862,6 +1862,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, */ if (!bond_has_slaves(bond)) { if (bond_dev->type != slave_dev->type) { + if (slave_dev->type != ARPHRD_ETHER && + BOND_MODE(bond) == BOND_MODE_8023AD) { + SLAVE_NL_ERR(bond_dev, slave_dev, extack, + "8023AD mode requires Ethernet devices"); + return -EINVAL; + } slave_dbg(bond_dev, slave_dev, "change device type from %d to %d\n", bond_dev->type, slave_dev->type); From 4d10edfd1475b69dbd4c47f34b61a3772ece83ca Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Tue, 13 Jan 2026 18:54:44 +0000 Subject: [PATCH 321/443] l2tp: Fix memleak in l2tp_udp_encap_recv(). syzbot reported memleak of struct l2tp_session, l2tp_tunnel, sock, etc. [0] The cited commit moved down the validation of the protocol version in l2tp_udp_encap_recv(). The new place requires an extra error handling to avoid the memleak. Let's call l2tp_session_put() there. [0]: BUG: memory leak unreferenced object 0xffff88810a290200 (size 512): comm "syz.0.17", pid 6086, jiffies 4294944299 hex dump (first 32 bytes): 7d eb 04 0c 00 00 00 00 01 00 00 00 00 00 00 00 }............... 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace (crc babb6a4f): kmemleak_alloc_recursive include/linux/kmemleak.h:44 [inline] slab_post_alloc_hook mm/slub.c:4958 [inline] slab_alloc_node mm/slub.c:5263 [inline] __do_kmalloc_node mm/slub.c:5656 [inline] __kmalloc_noprof+0x3e0/0x660 mm/slub.c:5669 kmalloc_noprof include/linux/slab.h:961 [inline] kzalloc_noprof include/linux/slab.h:1094 [inline] l2tp_session_create+0x3a/0x3b0 net/l2tp/l2tp_core.c:1778 pppol2tp_connect+0x48b/0x920 net/l2tp/l2tp_ppp.c:755 __sys_connect_file+0x7a/0xb0 net/socket.c:2089 __sys_connect+0xde/0x110 net/socket.c:2108 __do_sys_connect net/socket.c:2114 [inline] __se_sys_connect net/socket.c:2111 [inline] __x64_sys_connect+0x1c/0x30 net/socket.c:2111 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xa4/0xf80 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f Fixes: 364798056f518 ("l2tp: Support different protocol versions with same IP/port quadruple") Reported-by: syzbot+2c42ea4485b29beb0643@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/696693f2.a70a0220.245e30.0001.GAE@google.com/ Signed-off-by: Kuniyuki Iwashima Reviewed-by: Guillaume Nault Link: https://patch.msgid.link/20260113185446.2533333-1-kuniyu@google.com Signed-off-by: Jakub Kicinski --- net/l2tp/l2tp_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 687c1366a4d0..70335667ef03 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1086,8 +1086,10 @@ int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb) tunnel = session->tunnel; /* Check protocol version */ - if (version != tunnel->version) + if (version != tunnel->version) { + l2tp_session_put(session); goto invalid; + } if (version == L2TP_HDR_VER_3 && l2tp_v3_ensure_opt_in_linear(session, skb, &ptr, &optr)) { From 4f5f148dd7c0459229d2ab9a769b2e820f9ee6a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20B=2E=20Marli=C3=A8re?= Date: Tue, 13 Jan 2026 12:37:44 -0300 Subject: [PATCH 322/443] selftests: net: fib-onlink-tests: Convert to use namespaces by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the test breaks if the SUT already has a default route configured for IPv6. Fix by avoiding the use of the default namespace. Fixes: 4ed591c8ab44 ("net/ipv6: Allow onlink routes to have a device mismatch if it is the default route") Suggested-by: Fernando Fernandez Mancera Signed-off-by: Ricardo B. Marlière Reviewed-by: Ido Schimmel Reviewed-by: Fernando Fernandez Mancera Link: https://patch.msgid.link/20260113-selftests-net-fib-onlink-v2-1-89de2b931389@suse.com Signed-off-by: Jakub Kicinski --- .../testing/selftests/net/fib-onlink-tests.sh | 71 ++++++++----------- 1 file changed, 30 insertions(+), 41 deletions(-) diff --git a/tools/testing/selftests/net/fib-onlink-tests.sh b/tools/testing/selftests/net/fib-onlink-tests.sh index ec2d6ceb1f08..c01be076b210 100755 --- a/tools/testing/selftests/net/fib-onlink-tests.sh +++ b/tools/testing/selftests/net/fib-onlink-tests.sh @@ -120,7 +120,7 @@ log_subsection() run_cmd() { - local cmd="$*" + local cmd="$1" local out local rc @@ -145,7 +145,7 @@ get_linklocal() local pfx local addr - addr=$(${pfx} ip -6 -br addr show dev ${dev} | \ + addr=$(${pfx} ${IP} -6 -br addr show dev ${dev} | \ awk '{ for (i = 3; i <= NF; ++i) { if ($i ~ /^fe80/) @@ -173,58 +173,48 @@ setup() set -e - # create namespace - setup_ns PEER_NS + # create namespaces + setup_ns ns1 + IP="ip -netns $ns1" + setup_ns ns2 # add vrf table - ip li add ${VRF} type vrf table ${VRF_TABLE} - ip li set ${VRF} up - ip ro add table ${VRF_TABLE} unreachable default metric 8192 - ip -6 ro add table ${VRF_TABLE} unreachable default metric 8192 + ${IP} li add ${VRF} type vrf table ${VRF_TABLE} + ${IP} li set ${VRF} up + ${IP} ro add table ${VRF_TABLE} unreachable default metric 8192 + ${IP} -6 ro add table ${VRF_TABLE} unreachable default metric 8192 # create test interfaces - ip li add ${NETIFS[p1]} type veth peer name ${NETIFS[p2]} - ip li add ${NETIFS[p3]} type veth peer name ${NETIFS[p4]} - ip li add ${NETIFS[p5]} type veth peer name ${NETIFS[p6]} - ip li add ${NETIFS[p7]} type veth peer name ${NETIFS[p8]} + ${IP} li add ${NETIFS[p1]} type veth peer name ${NETIFS[p2]} + ${IP} li add ${NETIFS[p3]} type veth peer name ${NETIFS[p4]} + ${IP} li add ${NETIFS[p5]} type veth peer name ${NETIFS[p6]} + ${IP} li add ${NETIFS[p7]} type veth peer name ${NETIFS[p8]} # enslave vrf interfaces for n in 5 7; do - ip li set ${NETIFS[p${n}]} vrf ${VRF} + ${IP} li set ${NETIFS[p${n}]} vrf ${VRF} done # add addresses for n in 1 3 5 7; do - ip li set ${NETIFS[p${n}]} up - ip addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]} - ip addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} nodad + ${IP} li set ${NETIFS[p${n}]} up + ${IP} addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]} + ${IP} addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} nodad done # move peer interfaces to namespace and add addresses for n in 2 4 6 8; do - ip li set ${NETIFS[p${n}]} netns ${PEER_NS} up - ip -netns ${PEER_NS} addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]} - ip -netns ${PEER_NS} addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} nodad + ${IP} li set ${NETIFS[p${n}]} netns ${ns2} up + ip -netns $ns2 addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]} + ip -netns $ns2 addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} nodad done - ip -6 ro add default via ${V6ADDRS[p3]/::[0-9]/::64} - ip -6 ro add table ${VRF_TABLE} default via ${V6ADDRS[p7]/::[0-9]/::64} + ${IP} -6 ro add default via ${V6ADDRS[p3]/::[0-9]/::64} + ${IP} -6 ro add table ${VRF_TABLE} default via ${V6ADDRS[p7]/::[0-9]/::64} set +e } -cleanup() -{ - # make sure we start from a clean slate - cleanup_ns ${PEER_NS} 2>/dev/null - for n in 1 3 5 7; do - ip link del ${NETIFS[p${n}]} 2>/dev/null - done - ip link del ${VRF} 2>/dev/null - ip ro flush table ${VRF_TABLE} - ip -6 ro flush table ${VRF_TABLE} -} - ################################################################################ # IPv4 tests # @@ -241,7 +231,7 @@ run_ip() # dev arg may be empty [ -n "${dev}" ] && dev="dev ${dev}" - run_cmd ip ro add table "${table}" "${prefix}"/32 via "${gw}" "${dev}" onlink + run_cmd "${IP} ro add table ${table} ${prefix}/32 via ${gw} ${dev} onlink" log_test $? ${exp_rc} "${desc}" } @@ -257,8 +247,8 @@ run_ip_mpath() # dev arg may be empty [ -n "${dev}" ] && dev="dev ${dev}" - run_cmd ip ro add table "${table}" "${prefix}"/32 \ - nexthop via ${nh1} nexthop via ${nh2} + run_cmd "${IP} ro add table ${table} ${prefix}/32 \ + nexthop via ${nh1} nexthop via ${nh2}" log_test $? ${exp_rc} "${desc}" } @@ -339,7 +329,7 @@ run_ip6() # dev arg may be empty [ -n "${dev}" ] && dev="dev ${dev}" - run_cmd ip -6 ro add table "${table}" "${prefix}"/128 via "${gw}" "${dev}" onlink + run_cmd "${IP} -6 ro add table ${table} ${prefix}/128 via ${gw} ${dev} onlink" log_test $? ${exp_rc} "${desc}" } @@ -353,8 +343,8 @@ run_ip6_mpath() local exp_rc="$6" local desc="$7" - run_cmd ip -6 ro add table "${table}" "${prefix}"/128 "${opts}" \ - nexthop via ${nh1} nexthop via ${nh2} + run_cmd "${IP} -6 ro add table ${table} ${prefix}/128 ${opts} \ + nexthop via ${nh1} nexthop via ${nh2}" log_test $? ${exp_rc} "${desc}" } @@ -491,10 +481,9 @@ do esac done -cleanup setup run_onlink_tests -cleanup +cleanup_ns ${ns1} ${ns2} if [ "$TESTS" != "none" ]; then printf "\nTests passed: %3d\n" ${nsuccess} From a74c7a58ca2ca1cbb93f4c01421cf24b8642b962 Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Wed, 14 Jan 2026 09:02:46 +0100 Subject: [PATCH 323/443] net: freescale: ucc_geth: Return early when TBI PHY can't be found In ucc_geth's .mac_config(), we configure the TBI Serdes block represented by a struct phy_device that we get from firmware. While porting to phylink, a check was missed to make sure we don't try to access the TBI PHY if we can't get it. Let's add it and return early in case of error Reported-by: kernel test robot Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/202601130843.rFGNXA5a-lkp@intel.com/ Fixes: 53036aa8d031 ("net: freescale: ucc_geth: phylink conversion") Signed-off-by: Maxime Chevallier Link: https://patch.msgid.link/20260114080247.366252-1-maxime.chevallier@bootlin.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/freescale/ucc_geth.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c index affd5a6c44e7..131d1210dc4a 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.c +++ b/drivers/net/ethernet/freescale/ucc_geth.c @@ -1602,8 +1602,10 @@ static void ugeth_mac_config(struct phylink_config *config, unsigned int mode, pr_warn("TBI mode requires that the device tree specify a tbi-handle\n"); tbiphy = of_phy_find_device(ug_info->tbi_node); - if (!tbiphy) + if (!tbiphy) { pr_warn("Could not get TBI device\n"); + return; + } value = phy_read(tbiphy, ENET_TBI_MII_CR); value &= ~0x1000; /* Turn off autonegotiation */ From 09444bef413fcafabe965c1ff14e3bc9c2c0f4f9 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Tue, 13 Jan 2026 23:54:35 -0500 Subject: [PATCH 324/443] MAINTAINERS: Add Chen Ridong as cpuset reviewer Add Chen Ridong as a reviewer for the cpuset cgroup subsystem. Signed-off-by: Waiman Long Acked-by: Chen Ridong Signed-off-by: Tejun Heo --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index d701a4d5b00e..9c79da17b438 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6402,6 +6402,7 @@ F: include/linux/blk-cgroup.h CONTROL GROUP - CPUSET M: Waiman Long +R: Chen Ridong L: cgroups@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git From a1b3421a023e920b006d9a55eac334b14d115687 Mon Sep 17 00:00:00 2001 From: Tim Bird Date: Wed, 14 Jan 2026 13:30:27 -0700 Subject: [PATCH 325/443] kernel: cgroup: Add SPDX-License-Identifier lines Add GPL-2.0 SPDX license id lines to a few old files, replacing the reference to the COPYING file. The COPYING file at the time of creation of these files (2007 and 2005) was GPL-v2.0, with an additional clause indicating that only v2 applied. Signed-off-by: Tim Bird Signed-off-by: Tejun Heo --- kernel/cgroup/cgroup.c | 5 +---- kernel/cgroup/cpuset.c | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 554a02ee298b..5f0d33b04910 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Generic process-grouping system. * @@ -20,10 +21,6 @@ * 2003-10-22 Updates by Stephen Hemminger. * 2004 May-July Rework by Paul Jackson. * --------------------------------------------------- - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of the Linux - * distribution for more details. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 3e8cc34d8d50..c06e2e96f79d 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * kernel/cpuset.c * @@ -16,10 +17,6 @@ * 2006 Rework by Paul Menage to use generic cgroups * 2008 Rework of the scheduler domains and CPU hotplug handling * by Max Krasnyansky - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of the Linux - * distribution for more details. */ #include "cpuset-internal.h" From 84697bf5532923f70ac99ea9784fab325c560df0 Mon Sep 17 00:00:00 2001 From: Tim Bird Date: Wed, 14 Jan 2026 16:22:08 -0700 Subject: [PATCH 326/443] kernel: cgroup: Add LGPL-2.1 SPDX license ID to legacy_freezer.c Add an appropriate SPDX-License-Identifier line to the file, and remove the GNU boilerplate text. Signed-off-by: Tim Bird Signed-off-by: Tejun Heo --- kernel/cgroup/legacy_freezer.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/kernel/cgroup/legacy_freezer.c b/kernel/cgroup/legacy_freezer.c index 915b02f65980..817c33450fee 100644 --- a/kernel/cgroup/legacy_freezer.c +++ b/kernel/cgroup/legacy_freezer.c @@ -1,17 +1,10 @@ +// SPDX-License-Identifier: LGPL-2.1 /* * cgroup_freezer.c - control group freezer subsystem * * Copyright IBM Corporation, 2007 * * Author : Cedric Le Goater - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #include From dd83dc1249737b837ac5d57c81f2b0977c613d9f Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Fri, 16 Jan 2026 01:37:58 +0200 Subject: [PATCH 327/443] xhci: sideband: don't dereference freed ring when removing sideband endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit xhci_sideband_remove_endpoint() incorrecly assumes that the endpoint is running and has a valid transfer ring. Lianqin reported a crash during suspend/wake-up stress testing, and found the cause to be dereferencing a non-existing transfer ring 'ep->ring' during xhci_sideband_remove_endpoint(). The endpoint and its ring may be in unknown state if this function is called after xHCI was reinitialized in resume (lost power), or if device is being re-enumerated, disconnected or endpoint already dropped. Fix this by both removing unnecessary ring access, and by checking ep->ring exists before dereferencing it. Also make sure endpoint is running before attempting to stop it. Remove the xhci_initialize_ring_info() call during sideband endpoint removal as is it only initializes ring structure enqueue, dequeue and cycle state values to their starting values without changing actual hardware enqueue, dequeue and cycle state. Leaving them out of sync is worse than leaving it as it is. The endpoint will get freed in after this in most usecases. If the (audio) class driver want's to reuse the endpoint after offload then it is up to the class driver to ensure endpoint is properly set up. Reported-by: 胡连勤 Closes: https://lore.kernel.org/linux-usb/TYUPR06MB6217B105B059A7730C4F6EC8D2B9A@TYUPR06MB6217.apcprd06.prod.outlook.com/ Tested-by: 胡连勤 Fixes: de66754e9f80 ("xhci: sideband: add initial api to register a secondary interrupter entity") Cc: stable@vger.kernel.org Signed-off-by: Mathias Nyman Link: https://patch.msgid.link/20260115233758.364097-2-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-sideband.c | 1 - drivers/usb/host/xhci.c | 15 ++++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/xhci-sideband.c b/drivers/usb/host/xhci-sideband.c index a85f62a73313..2bd77255032b 100644 --- a/drivers/usb/host/xhci-sideband.c +++ b/drivers/usb/host/xhci-sideband.c @@ -210,7 +210,6 @@ xhci_sideband_remove_endpoint(struct xhci_sideband *sb, return -ENODEV; __xhci_sideband_remove_endpoint(sb, ep); - xhci_initialize_ring_info(ep->ring); return 0; } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 02c9bfe21ae2..b3ba16b9718c 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2898,16 +2898,25 @@ int xhci_stop_endpoint_sync(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, int gfp_t gfp_flags) { struct xhci_command *command; + struct xhci_ep_ctx *ep_ctx; unsigned long flags; - int ret; + int ret = -ENODEV; command = xhci_alloc_command(xhci, true, gfp_flags); if (!command) return -ENOMEM; spin_lock_irqsave(&xhci->lock, flags); - ret = xhci_queue_stop_endpoint(xhci, command, ep->vdev->slot_id, - ep->ep_index, suspend); + + /* make sure endpoint exists and is running before stopping it */ + if (ep->ring) { + ep_ctx = xhci_get_ep_ctx(xhci, ep->vdev->out_ctx, ep->ep_index); + if (GET_EP_CTX_STATE(ep_ctx) == EP_STATE_RUNNING) + ret = xhci_queue_stop_endpoint(xhci, command, + ep->vdev->slot_id, + ep->ep_index, suspend); + } + if (ret < 0) { spin_unlock_irqrestore(&xhci->lock, flags); goto out; From b5a69c4869211a6ab61a95f5cc987b25f383dbc3 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Mon, 12 Jan 2026 16:58:28 +0000 Subject: [PATCH 328/443] arm_mpam: Remove duplicate linux/srcu.h header ./drivers/resctrl/mpam_internal.h: linux/srcu.h is included more than once. Reviewed-by: Jonathan Cameron Reported-by: Abaci Robot Closes: https://bugzilla.openanolis.cn/show_bug.cgi?id=27328 Signed-off-by: Jiapeng Chong Acked-by: James Morse [BH: Keep alphabetical order] Signed-off-by: Ben Horgan Reviewed-by: Gavin Shan Reviewed-by: Fenghua Yu Tested-by: Shaopeng Tan Tested-by: Peter Newman Signed-off-by: Catalin Marinas --- drivers/resctrl/mpam_internal.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h index e79c3c47259c..17cdc3080d58 100644 --- a/drivers/resctrl/mpam_internal.h +++ b/drivers/resctrl/mpam_internal.h @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include From b9f5c38e4af1a094384650d2fc79fb992d6d5e64 Mon Sep 17 00:00:00 2001 From: Ben Horgan Date: Mon, 12 Jan 2026 16:58:29 +0000 Subject: [PATCH 329/443] arm_mpam: Use non-atomic bitops when modifying feature bitmap In the test__props_mismatch() kunit test we rely on the struct mpam_props being packed to ensure memcmp doesn't consider packing. Making it packed reduces the alignment of the features bitmap and so breaks a requirement for the use of atomics. As we don't rely on the set/clear of these bits being atomic, just make them non-atomic. Reviewed-by: Jonathan Cameron Signed-off-by: Ben Horgan Fixes: 8c90dc68a5de ("arm_mpam: Probe the hardware features resctrl supports") Reviewed-by: Gavin Shan Tested-by: Shaopeng Tan Tested-by: Peter Newman Signed-off-by: Catalin Marinas --- drivers/resctrl/mpam_internal.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h index 17cdc3080d58..e8971842b124 100644 --- a/drivers/resctrl/mpam_internal.h +++ b/drivers/resctrl/mpam_internal.h @@ -200,8 +200,12 @@ struct mpam_props { } PACKED_FOR_KUNIT; #define mpam_has_feature(_feat, x) test_bit(_feat, (x)->features) -#define mpam_set_feature(_feat, x) set_bit(_feat, (x)->features) -#define mpam_clear_feature(_feat, x) clear_bit(_feat, (x)->features) +/* + * The non-atomic get/set operations are used because if struct mpam_props is + * packed, the alignment requirements for atomics aren't met. + */ +#define mpam_set_feature(_feat, x) __set_bit(_feat, (x)->features) +#define mpam_clear_feature(_feat, x) __clear_bit(_feat, (x)->features) /* The values for MSMON_CFG_MBWU_FLT.RWBW */ enum mon_filter_options { From 375629c92fd842bc2a229bb34c4453f62e097169 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 16 Jan 2026 13:13:45 +0100 Subject: [PATCH 330/443] can: dev: alloc_candev_mqs(): add missing default CAN capabilities The idea behind series 6c1f5146b214 ("Merge patch series "can: raw: better approach to instantly reject unsupported CAN frames"") is to set the capabilities of a CAN device (CAN-CC, CAN-FD, CAN-XL, and listen only) [1] and, based on these capabilities, reject unsupported CAN frames in the CAN-RAW protocol [2]. This works perfectly for CAN devices configured in CAN-FD or CAN-XL mode. CAN devices with static CAN control modes define their capabilities via can_set_static_ctrlmode() -> can_set_cap_info(). CAN devices configured by the user space for CAN-FD or CAN-XL set their capabilities via can_changelink() -> can_ctrlmode_changelink() -> can_set_cap_info(). However, in commit 166e87329ce6 ("can: propagate CAN device capabilities via ml_priv"), the capabilities of CAN devices are not initialized. This results in CAN-RAW rejecting all CAN frames on devices directly after ifup if the user space has not changed the CAN control mode. Fix this problem by setting the default capabilities to CAN-CC in alloc_candev_mqs() as soon as the CAN specific ml_priv is allocated. [1] commit 166e87329ce6 ("can: propagate CAN device capabilities via ml_priv") [2] commit faba5860fcf9 ("can: raw: instantly reject disabled CAN frames") Fixes: 166e87329ce6 ("can: propagate CAN device capabilities via ml_priv") Acked-by: Oliver Hartkopp Tested-by: Oliver Hartkopp Link: https://patch.msgid.link/20260116-can_add_missing_set_caps-v1-1-7525126d8b20@pengutronix.de [mkl: fix typo in subject] Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev/dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c index 7ab9578f5b89..769745e22a3c 100644 --- a/drivers/net/can/dev/dev.c +++ b/drivers/net/can/dev/dev.c @@ -332,6 +332,7 @@ struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max, can_ml = (void *)priv + ALIGN(sizeof_priv, NETDEV_ALIGN); can_set_ml_priv(dev, can_ml); + can_set_cap(dev, CAN_CAP_CC); if (echo_skb_max) { priv->echo_skb_max = echo_skb_max; From 79a6d1bfe1148bc921b8d7f3371a7fbce44e30f7 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 16 Jan 2026 14:10:10 +0100 Subject: [PATCH 331/443] can: gs_usb: gs_usb_receive_bulk_callback(): unanchor URL on usb_submit_urb() error In commit 7352e1d5932a ("can: gs_usb: gs_usb_receive_bulk_callback(): fix URB memory leak"), the URB was re-anchored before usb_submit_urb() in gs_usb_receive_bulk_callback() to prevent a leak of this URB during cleanup. However, this patch did not take into account that usb_submit_urb() could fail. The URB remains anchored and usb_kill_anchored_urbs(&parent->rx_submitted) in gs_can_close() loops infinitely since the anchor list never becomes empty. To fix the bug, unanchor the URB when an usb_submit_urb() error occurs, also print an info message. Fixes: 7352e1d5932a ("can: gs_usb: gs_usb_receive_bulk_callback(): fix URB memory leak") Reported-by: Jakub Kicinski Closes: https://lore.kernel.org/all/20260110223836.3890248-1-kuba@kernel.org/ Link: https://patch.msgid.link/20260116-can_usb-fix-reanchor-v1-1-9d74e7289225@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/gs_usb.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index d093babbc320..192338b481f2 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -754,6 +754,10 @@ resubmit_urb: usb_anchor_urb(urb, &parent->rx_submitted); rc = usb_submit_urb(urb, GFP_ATOMIC); + if (!rc) + return; + + usb_unanchor_urb(urb); /* USB failure take down all interfaces */ if (rc == -ENODEV) { @@ -762,6 +766,9 @@ device_detach: if (parent->canch[rc]) netif_device_detach(parent->canch[rc]->netdev); } + } else if (rc != -ESHUTDOWN && net_ratelimit()) { + netdev_info(netdev, "failed to re-submit IN URB: %pe\n", + ERR_PTR(urb->status)); } } From 0ce73a0eb5a27070957b67fd74059b6da89cc516 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Sat, 10 Jan 2026 12:52:27 +0100 Subject: [PATCH 332/443] can: ems_usb: ems_usb_read_bulk_callback(): fix URB memory leak Fix similar memory leak as in commit 7352e1d5932a ("can: gs_usb: gs_usb_receive_bulk_callback(): fix URB memory leak"). In ems_usb_open(), the URBs for USB-in transfers are allocated, added to the dev->rx_submitted anchor and submitted. In the complete callback ems_usb_read_bulk_callback(), the URBs are processed and resubmitted. In ems_usb_close() the URBs are freed by calling usb_kill_anchored_urbs(&dev->rx_submitted). However, this does not take into account that the USB framework unanchors the URB before the complete function is called. This means that once an in-URB has been completed, it is no longer anchored and is ultimately not released in ems_usb_close(). Fix the memory leak by anchoring the URB in the ems_usb_read_bulk_callback() to the dev->rx_submitted anchor. Fixes: 702171adeed3 ("ems_usb: Added support for EMS CPC-USB/ARM7 CAN/USB interface") Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260116-can_usb-fix-memory-leak-v2-1-4b8cb2915571@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/ems_usb.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index de8e212a1366..4c219a5b139b 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -486,11 +486,17 @@ resubmit_urb: urb->transfer_buffer, RX_BUFFER_SIZE, ems_usb_read_bulk_callback, dev); + usb_anchor_urb(urb, &dev->rx_submitted); + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (!retval) + return; + + usb_unanchor_urb(urb); if (retval == -ENODEV) netif_device_detach(netdev); - else if (retval) + else netdev_err(netdev, "failed resubmitting read bulk urb: %d\n", retval); } From 5a4391bdc6c8357242f62f22069c865b792406b3 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Sat, 10 Jan 2026 12:52:27 +0100 Subject: [PATCH 333/443] can: esd_usb: esd_usb_read_bulk_callback(): fix URB memory leak Fix similar memory leak as in commit 7352e1d5932a ("can: gs_usb: gs_usb_receive_bulk_callback(): fix URB memory leak"). In esd_usb_open(), the URBs for USB-in transfers are allocated, added to the dev->rx_submitted anchor and submitted. In the complete callback esd_usb_read_bulk_callback(), the URBs are processed and resubmitted. In esd_usb_close() the URBs are freed by calling usb_kill_anchored_urbs(&dev->rx_submitted). However, this does not take into account that the USB framework unanchors the URB before the complete function is called. This means that once an in-URB has been completed, it is no longer anchored and is ultimately not released in esd_usb_close(). Fix the memory leak by anchoring the URB in the esd_usb_read_bulk_callback() to the dev->rx_submitted anchor. Fixes: 96d8e90382dc ("can: Add driver for esd CAN-USB/2 device") Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260116-can_usb-fix-memory-leak-v2-2-4b8cb2915571@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/esd_usb.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c index 08da507faef4..8cc924c47042 100644 --- a/drivers/net/can/usb/esd_usb.c +++ b/drivers/net/can/usb/esd_usb.c @@ -541,13 +541,20 @@ resubmit_urb: urb->transfer_buffer, ESD_USB_RX_BUFFER_SIZE, esd_usb_read_bulk_callback, dev); + usb_anchor_urb(urb, &dev->rx_submitted); + err = usb_submit_urb(urb, GFP_ATOMIC); + if (!err) + return; + + usb_unanchor_urb(urb); + if (err == -ENODEV) { for (i = 0; i < dev->net_count; i++) { if (dev->nets[i]) netif_device_detach(dev->nets[i]->netdev); } - } else if (err) { + } else { dev_err(dev->udev->dev.parent, "failed resubmitting read bulk urb: %pe\n", ERR_PTR(err)); } From 248e8e1a125fa875158df521b30f2cc7e27eeeaa Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Sat, 10 Jan 2026 12:52:27 +0100 Subject: [PATCH 334/443] can: kvaser_usb: kvaser_usb_read_bulk_callback(): fix URB memory leak Fix similar memory leak as in commit 7352e1d5932a ("can: gs_usb: gs_usb_receive_bulk_callback(): fix URB memory leak"). In kvaser_usb_set_{,data_}bittiming() -> kvaser_usb_setup_rx_urbs(), the URBs for USB-in transfers are allocated, added to the dev->rx_submitted anchor and submitted. In the complete callback kvaser_usb_read_bulk_callback(), the URBs are processed and resubmitted. In kvaser_usb_remove_interfaces() the URBs are freed by calling usb_kill_anchored_urbs(&dev->rx_submitted). However, this does not take into account that the USB framework unanchors the URB before the complete function is called. This means that once an in-URB has been completed, it is no longer anchored and is ultimately not released in usb_kill_anchored_urbs(). Fix the memory leak by anchoring the URB in the kvaser_usb_read_bulk_callback() to the dev->rx_submitted anchor. Fixes: 080f40a6fa28 ("can: kvaser_usb: Add support for Kvaser CAN/USB devices") Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260116-can_usb-fix-memory-leak-v2-3-4b8cb2915571@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c index 62701ec34272..d0a2a2a33c1c 100644 --- a/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c +++ b/drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c @@ -361,7 +361,14 @@ resubmit_urb: urb->transfer_buffer, KVASER_USB_RX_BUFFER_SIZE, kvaser_usb_read_bulk_callback, dev); + usb_anchor_urb(urb, &dev->rx_submitted); + err = usb_submit_urb(urb, GFP_ATOMIC); + if (!err) + return; + + usb_unanchor_urb(urb); + if (err == -ENODEV) { for (i = 0; i < dev->nchannels; i++) { struct kvaser_usb_net_priv *priv; @@ -372,7 +379,7 @@ resubmit_urb: netif_device_detach(priv->netdev); } - } else if (err) { + } else { dev_err(&dev->intf->dev, "Failed resubmitting read bulk urb: %d\n", err); } From 710a7529fb13c5a470258ff5508ed3c498d54729 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Sat, 10 Jan 2026 12:52:27 +0100 Subject: [PATCH 335/443] can: mcba_usb: mcba_usb_read_bulk_callback(): fix URB memory leak Fix similar memory leak as in commit 7352e1d5932a ("can: gs_usb: gs_usb_receive_bulk_callback(): fix URB memory leak"). In mcba_usb_probe() -> mcba_usb_start(), the URBs for USB-in transfers are allocated, added to the priv->rx_submitted anchor and submitted. In the complete callback mcba_usb_read_bulk_callback(), the URBs are processed and resubmitted. In mcba_usb_close() -> mcba_urb_unlink() the URBs are freed by calling usb_kill_anchored_urbs(&priv->rx_submitted). However, this does not take into account that the USB framework unanchors the URB before the complete function is called. This means that once an in-URB has been completed, it is no longer anchored and is ultimately not released in usb_kill_anchored_urbs(). Fix the memory leak by anchoring the URB in the mcba_usb_read_bulk_callback()to the priv->rx_submitted anchor. Fixes: 51f3baad7de9 ("can: mcba_usb: Add support for Microchip CAN BUS Analyzer") Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260116-can_usb-fix-memory-leak-v2-4-4b8cb2915571@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/mcba_usb.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/usb/mcba_usb.c b/drivers/net/can/usb/mcba_usb.c index 41c0a1c399bf..04170326dc7e 100644 --- a/drivers/net/can/usb/mcba_usb.c +++ b/drivers/net/can/usb/mcba_usb.c @@ -608,11 +608,17 @@ resubmit_urb: urb->transfer_buffer, MCBA_USB_RX_BUFF_SIZE, mcba_usb_read_bulk_callback, priv); + usb_anchor_urb(urb, &priv->rx_submitted); + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (!retval) + return; + + usb_unanchor_urb(urb); if (retval == -ENODEV) netif_device_detach(netdev); - else if (retval) + else netdev_err(netdev, "failed resubmitting read bulk urb: %d\n", retval); } From f7a980b3b8f80fe367f679da376cf76e800f9480 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Sat, 10 Jan 2026 12:52:27 +0100 Subject: [PATCH 336/443] can: usb_8dev: usb_8dev_read_bulk_callback(): fix URB memory leak Fix similar memory leak as in commit 7352e1d5932a ("can: gs_usb: gs_usb_receive_bulk_callback(): fix URB memory leak"). In usb_8dev_open() -> usb_8dev_start(), the URBs for USB-in transfers are allocated, added to the priv->rx_submitted anchor and submitted. In the complete callback usb_8dev_read_bulk_callback(), the URBs are processed and resubmitted. In usb_8dev_close() -> unlink_all_urbs() the URBs are freed by calling usb_kill_anchored_urbs(&priv->rx_submitted). However, this does not take into account that the USB framework unanchors the URB before the complete function is called. This means that once an in-URB has been completed, it is no longer anchored and is ultimately not released in usb_kill_anchored_urbs(). Fix the memory leak by anchoring the URB in the usb_8dev_read_bulk_callback() to the priv->rx_submitted anchor. Fixes: 0024d8ad1639 ("can: usb_8dev: Add support for USB2CAN interface from 8 devices") Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260116-can_usb-fix-memory-leak-v2-5-4b8cb2915571@pengutronix.de Signed-off-by: Marc Kleine-Budde --- drivers/net/can/usb/usb_8dev.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c index 7449328f7cd7..3125cf59d002 100644 --- a/drivers/net/can/usb/usb_8dev.c +++ b/drivers/net/can/usb/usb_8dev.c @@ -541,11 +541,17 @@ resubmit_urb: urb->transfer_buffer, RX_BUFFER_SIZE, usb_8dev_read_bulk_callback, priv); + usb_anchor_urb(urb, &priv->rx_submitted); + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (!retval) + return; + + usb_unanchor_urb(urb); if (retval == -ENODEV) netif_device_detach(netdev); - else if (retval) + else netdev_err(netdev, "failed resubmitting read bulk urb: %d\n", retval); } From 48e6a9c4a20870e09f85ff1a3628275d6bce31c0 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 13 Jan 2026 19:51:58 -0600 Subject: [PATCH 337/443] of: platform: Use default match table for /firmware Calling of_platform_populate() without a match table will only populate the immediate child nodes under /firmware. This is usually fine, but in the case of something like a "simple-mfd" node such as "raspberrypi,bcm2835-firmware", those child nodes will not be populated. And subsequent calls won't work either because the /firmware node is marked as processed already. Switch the call to of_platform_default_populate() to solve this problem. It should be a nop for existing cases. Fixes: 3aa0582fdb82 ("of: platform: populate /firmware/ node from of_platform_default_populate_init()") Cc: stable@vger.kernel.org Reviewed-by: Sudeep Holla Link: https://patch.msgid.link/20260114015158.692170-2-robh@kernel.org Signed-off-by: Rob Herring (Arm) --- drivers/of/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/of/platform.c b/drivers/of/platform.c index f77cb19973a5..a6dca3a005aa 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -569,7 +569,7 @@ static int __init of_platform_default_populate_init(void) node = of_find_node_by_path("/firmware"); if (node) { - of_platform_populate(node, NULL, NULL, NULL); + of_platform_default_populate(node, NULL, NULL); of_node_put(node); } From a91f86e27087f250a5d9c89bb4a427b9c30fd815 Mon Sep 17 00:00:00 2001 From: Lisa Robinson Date: Sat, 17 Jan 2026 10:56:43 +0800 Subject: [PATCH 338/443] LoongArch: Fix PMU counter allocation for mixed-type event groups When validating a perf event group, validate_group() unconditionally attempts to allocate hardware PMU counters for the leader, sibling events and the new event being added. This is incorrect for mixed-type groups. If a PERF_TYPE_SOFTWARE event is part of the group, the current code still tries to allocate a hardware PMU counter for it, which can wrongly consume hardware PMU resources and cause spurious allocation failures. Fix this by only allocating PMU counters for hardware events during group validation, and skipping software events. A trimmed down reproducer is as simple as this: #include #include #include #include #include #include int main (int argc, char *argv[]) { struct perf_event_attr attr = { 0 }; int fds[5]; attr.disabled = 1; attr.exclude_kernel = 1; attr.exclude_hv = 1; attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID | PERF_FORMAT_GROUP; attr.size = sizeof (attr); attr.type = PERF_TYPE_SOFTWARE; attr.config = PERF_COUNT_SW_DUMMY; fds[0] = syscall (SYS_perf_event_open, &attr, 0, -1, -1, 0); assert (fds[0] >= 0); attr.type = PERF_TYPE_HARDWARE; attr.config = PERF_COUNT_HW_CPU_CYCLES; fds[1] = syscall (SYS_perf_event_open, &attr, 0, -1, fds[0], 0); assert (fds[1] >= 0); attr.type = PERF_TYPE_HARDWARE; attr.config = PERF_COUNT_HW_INSTRUCTIONS; fds[2] = syscall (SYS_perf_event_open, &attr, 0, -1, fds[0], 0); assert (fds[2] >= 0); attr.type = PERF_TYPE_HARDWARE; attr.config = PERF_COUNT_HW_BRANCH_MISSES; fds[3] = syscall (SYS_perf_event_open, &attr, 0, -1, fds[0], 0); assert (fds[3] >= 0); attr.type = PERF_TYPE_HARDWARE; attr.config = PERF_COUNT_HW_CACHE_REFERENCES; fds[4] = syscall (SYS_perf_event_open, &attr, 0, -1, fds[0], 0); assert (fds[4] >= 0); printf ("PASSED\n"); return 0; } Cc: stable@vger.kernel.org Fixes: b37042b2bb7c ("LoongArch: Add perf events support") Signed-off-by: Lisa Robinson Signed-off-by: Huacai Chen --- arch/loongarch/kernel/perf_event.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/arch/loongarch/kernel/perf_event.c b/arch/loongarch/kernel/perf_event.c index 9d257c8519c9..e34a6fb33e11 100644 --- a/arch/loongarch/kernel/perf_event.c +++ b/arch/loongarch/kernel/perf_event.c @@ -626,6 +626,18 @@ static const struct loongarch_perf_event *loongarch_pmu_map_cache_event(u64 conf return pev; } +static inline bool loongarch_pmu_event_requires_counter(const struct perf_event *event) +{ + switch (event->attr.type) { + case PERF_TYPE_HARDWARE: + case PERF_TYPE_HW_CACHE: + case PERF_TYPE_RAW: + return true; + default: + return false; + } +} + static int validate_group(struct perf_event *event) { struct cpu_hw_events fake_cpuc; @@ -633,15 +645,18 @@ static int validate_group(struct perf_event *event) memset(&fake_cpuc, 0, sizeof(fake_cpuc)); - if (loongarch_pmu_alloc_counter(&fake_cpuc, &leader->hw) < 0) + if (loongarch_pmu_event_requires_counter(leader) && + loongarch_pmu_alloc_counter(&fake_cpuc, &leader->hw) < 0) return -EINVAL; for_each_sibling_event(sibling, leader) { - if (loongarch_pmu_alloc_counter(&fake_cpuc, &sibling->hw) < 0) + if (loongarch_pmu_event_requires_counter(sibling) && + loongarch_pmu_alloc_counter(&fake_cpuc, &sibling->hw) < 0) return -EINVAL; } - if (loongarch_pmu_alloc_counter(&fake_cpuc, &event->hw) < 0) + if (loongarch_pmu_event_requires_counter(event) && + loongarch_pmu_alloc_counter(&fake_cpuc, &event->hw) < 0) return -EINVAL; return 0; From 762cf75bec2ad9d17899087899a34336b1757238 Mon Sep 17 00:00:00 2001 From: Yao Zi Date: Sat, 17 Jan 2026 10:56:52 +0800 Subject: [PATCH 339/443] LoongArch: dts: Describe PCI sideband IRQ through interrupt-extended SoC integrated peripherals on LS2K1000 and LS2K2000 could be discovered as PCI devices, but require sideband interrupts to function, which are previously described by interrupts and interrupt-parent properties. However, pci/pci-device.yaml allows interrupts property to only specify PCI INTx interrupts, not sideband ones. Convert these devices to use interrupt-extended property, which describes sideband interrupts used by PCI devices since dt-schema commit e6ea659d2baa ("schemas: pci-device: Allow interrupts-extended for sideband interrupts"), eliminating dtbs_check warnings. Cc: stable@vger.kernel.org Fixes: 30a5532a3206 ("LoongArch: dts: DeviceTree for Loongson-2K1000") Signed-off-by: Yao Zi Signed-off-by: Binbin Zhou Signed-off-by: Huacai Chen --- arch/loongarch/boot/dts/loongson-2k1000.dtsi | 25 ++++++--------- arch/loongarch/boot/dts/loongson-2k2000.dtsi | 32 ++++++++------------ 2 files changed, 21 insertions(+), 36 deletions(-) diff --git a/arch/loongarch/boot/dts/loongson-2k1000.dtsi b/arch/loongarch/boot/dts/loongson-2k1000.dtsi index 60ab425f793f..eee06b84951c 100644 --- a/arch/loongarch/boot/dts/loongson-2k1000.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k1000.dtsi @@ -437,54 +437,47 @@ gmac0: ethernet@3,0 { reg = <0x1800 0x0 0x0 0x0 0x0>; - interrupt-parent = <&liointc0>; - interrupts = <12 IRQ_TYPE_LEVEL_HIGH>, - <13 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&liointc0 12 IRQ_TYPE_LEVEL_HIGH>, + <&liointc0 13 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq", "eth_lpi"; status = "disabled"; }; gmac1: ethernet@3,1 { reg = <0x1900 0x0 0x0 0x0 0x0>; - interrupt-parent = <&liointc0>; - interrupts = <14 IRQ_TYPE_LEVEL_HIGH>, - <15 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&liointc0 14 IRQ_TYPE_LEVEL_HIGH>, + <&liointc0 15 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq", "eth_lpi"; status = "disabled"; }; ehci0: usb@4,1 { reg = <0x2100 0x0 0x0 0x0 0x0>; - interrupt-parent = <&liointc1>; - interrupts = <18 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&liointc1 18 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; ohci0: usb@4,2 { reg = <0x2200 0x0 0x0 0x0 0x0>; - interrupt-parent = <&liointc1>; - interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&liointc1 19 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; display@6,0 { reg = <0x3000 0x0 0x0 0x0 0x0>; - interrupt-parent = <&liointc0>; - interrupts = <28 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&liointc0 28 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; hda@7,0 { reg = <0x3800 0x0 0x0 0x0 0x0>; - interrupt-parent = <&liointc0>; - interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&liointc0 4 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; sata: sata@8,0 { reg = <0x4000 0x0 0x0 0x0 0x0>; - interrupt-parent = <&liointc0>; - interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&liointc0 19 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; diff --git a/arch/loongarch/boot/dts/loongson-2k2000.dtsi b/arch/loongarch/boot/dts/loongson-2k2000.dtsi index 6c77b86ee06c..87c45f1f7cc7 100644 --- a/arch/loongarch/boot/dts/loongson-2k2000.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k2000.dtsi @@ -291,65 +291,57 @@ gmac0: ethernet@3,0 { reg = <0x1800 0x0 0x0 0x0 0x0>; - interrupts = <12 IRQ_TYPE_LEVEL_HIGH>, - <13 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&pic 12 IRQ_TYPE_LEVEL_HIGH>, + <&pic 13 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq", "eth_lpi"; - interrupt-parent = <&pic>; status = "disabled"; }; gmac1: ethernet@3,1 { reg = <0x1900 0x0 0x0 0x0 0x0>; - interrupts = <14 IRQ_TYPE_LEVEL_HIGH>, - <15 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&pic 14 IRQ_TYPE_LEVEL_HIGH>, + <&pic 15 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq", "eth_lpi"; - interrupt-parent = <&pic>; status = "disabled"; }; gmac2: ethernet@3,2 { reg = <0x1a00 0x0 0x0 0x0 0x0>; - interrupts = <17 IRQ_TYPE_LEVEL_HIGH>, - <18 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&pic 17 IRQ_TYPE_LEVEL_HIGH>, + <&pic 18 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "macirq", "eth_lpi"; - interrupt-parent = <&pic>; status = "disabled"; }; xhci0: usb@4,0 { reg = <0x2000 0x0 0x0 0x0 0x0>; - interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; - interrupt-parent = <&pic>; + interrupts-extended = <&pic 48 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; xhci1: usb@19,0 { reg = <0xc800 0x0 0x0 0x0 0x0>; - interrupts = <22 IRQ_TYPE_LEVEL_HIGH>; - interrupt-parent = <&pic>; + interrupts-extended = <&pic 22 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; display@6,1 { reg = <0x3100 0x0 0x0 0x0 0x0>; - interrupts = <28 IRQ_TYPE_LEVEL_HIGH>; - interrupt-parent = <&pic>; + interrupts-extended = <&pic 28 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; i2s@7,0 { reg = <0x3800 0x0 0x0 0x0 0x0>; - interrupts = <78 IRQ_TYPE_LEVEL_HIGH>, - <79 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&pic 78 IRQ_TYPE_LEVEL_HIGH>, + <&pic 79 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "tx", "rx"; - interrupt-parent = <&pic>; status = "disabled"; }; sata: sata@8,0 { reg = <0x4000 0x0 0x0 0x0 0x0>; - interrupts = <16 IRQ_TYPE_LEVEL_HIGH>; - interrupt-parent = <&pic>; + interrupts-extended = <&pic 16 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; From c4461754e6fe7e12a3ff198cce4707e3e20e43d4 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Sat, 17 Jan 2026 10:56:52 +0800 Subject: [PATCH 340/443] LoongArch: dts: loongson-2k0500: Add default interrupt controller address cells Add missing address-cells 0 to the Local I/O and Extend I/O interrupt controller node to silence W=1 warning: loongson-2k0500.dtsi:513.5-51: Warning (interrupt_map): /bus@10000000/pcie@1a000000/pcie@0,0:interrupt-map: Missing property '#address-cells' in node /bus@10000000/interrupt-controller@1fe11600, using 0 as fallback Value '0' is correct because: 1. The Local I/O & Extend I/O interrupt controller do not have children, 2. interrupt-map property (in PCI node) consists of five components and the fourth component "parent unit address", which size is defined by '#address-cells' of the node pointed to by the interrupt-parent component, is not used (=0) Cc: stable@vger.kernel.org Signed-off-by: Binbin Zhou Signed-off-by: Huacai Chen --- arch/loongarch/boot/dts/loongson-2k0500.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/loongarch/boot/dts/loongson-2k0500.dtsi b/arch/loongarch/boot/dts/loongson-2k0500.dtsi index 357de4ca7555..e759fae77dcf 100644 --- a/arch/loongarch/boot/dts/loongson-2k0500.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k0500.dtsi @@ -131,6 +131,7 @@ reg-names = "main", "isr0"; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <2>; interrupt-parent = <&cpuintc>; interrupts = <2>; @@ -149,6 +150,7 @@ reg-names = "main", "isr0"; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <2>; interrupt-parent = <&cpuintc>; interrupts = <4>; @@ -164,6 +166,7 @@ compatible = "loongson,ls2k0500-eiointc"; reg = <0x0 0x1fe11600 0x0 0xea00>; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <1>; interrupt-parent = <&cpuintc>; interrupts = <3>; From 81e8cb7e504a5adbcc48f7f954bf3c2aa9b417f8 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Sat, 17 Jan 2026 10:56:53 +0800 Subject: [PATCH 341/443] LoongArch: dts: loongson-2k1000: Add default interrupt controller address cells Add missing address-cells 0 to the Local I/O interrupt controller node to silence W=1 warning: loongson-2k1000.dtsi:498.5-55: Warning (interrupt_map): /bus@10000000/pcie@1a000000/pcie@9,0:interrupt-map: Missing property '#address-cells' in node /bus@10000000/interrupt-controller@1fe01440, using 0 as fallback Value '0' is correct because: 1. The Local I/O interrupt controller does not have children, 2. interrupt-map property (in PCI node) consists of five components and the fourth component "parent unit address", which size is defined by '#address-cells' of the node pointed to by the interrupt-parent component, is not used (=0) Cc: stable@vger.kernel.org Signed-off-by: Binbin Zhou Signed-off-by: Huacai Chen --- arch/loongarch/boot/dts/loongson-2k1000.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/loongarch/boot/dts/loongson-2k1000.dtsi b/arch/loongarch/boot/dts/loongson-2k1000.dtsi index eee06b84951c..440a8f3c01f4 100644 --- a/arch/loongarch/boot/dts/loongson-2k1000.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k1000.dtsi @@ -114,6 +114,7 @@ <0x0 0x1fe01140 0x0 0x8>; reg-names = "main", "isr0", "isr1"; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <2>; interrupt-parent = <&cpuintc>; interrupts = <2>; @@ -131,6 +132,7 @@ <0x0 0x1fe01148 0x0 0x8>; reg-names = "main", "isr0", "isr1"; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <2>; interrupt-parent = <&cpuintc>; interrupts = <3>; From e65df3f77ecd59d3a8647d19df82b22a6ce210a9 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Sat, 17 Jan 2026 10:56:53 +0800 Subject: [PATCH 342/443] LoongArch: dts: loongson-2k2000: Add default interrupt controller address cells Add missing address-cells 0 to the Local I/O, Extend I/O and PCH-PIC Interrupt Controller node to silence W=1 warning: loongson-2k2000.dtsi:364.5-49: Warning (interrupt_map): /bus@10000000/pcie@1a000000/pcie@9,0:interrupt-map: Missing property '#address-cells' in node /bus@10000000/interrupt-controller@10000000, using 0 as fallback Value '0' is correct because: 1. The LIO/EIO/PCH interrupt controller does not have children, 2. interrupt-map property (in PCI node) consists of five components and the fourth component "parent unit address", which size is defined by '#address-cells' of the node pointed to by the interrupt-parent component, is not used (=0) Cc: stable@vger.kernel.org Signed-off-by: Binbin Zhou Signed-off-by: Huacai Chen --- arch/loongarch/boot/dts/loongson-2k2000.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/loongarch/boot/dts/loongson-2k2000.dtsi b/arch/loongarch/boot/dts/loongson-2k2000.dtsi index 87c45f1f7cc7..3678c084adf7 100644 --- a/arch/loongarch/boot/dts/loongson-2k2000.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k2000.dtsi @@ -126,6 +126,7 @@ reg = <0x0 0x1fe01400 0x0 0x64>; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <2>; interrupt-parent = <&cpuintc>; interrupts = <2>; @@ -140,6 +141,7 @@ compatible = "loongson,ls2k2000-eiointc"; reg = <0x0 0x1fe01600 0x0 0xea00>; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <1>; interrupt-parent = <&cpuintc>; interrupts = <3>; @@ -149,6 +151,7 @@ compatible = "loongson,pch-pic-1.0"; reg = <0x0 0x10000000 0x0 0x400>; interrupt-controller; + #address-cells = <0>; #interrupt-cells = <2>; loongson,pic-base-vec = <0>; interrupt-parent = <&eiointc>; From 14ea5a3625881d79f75418c66e3a7d98db8518e1 Mon Sep 17 00:00:00 2001 From: Binbin Zhou Date: Sat, 17 Jan 2026 10:56:53 +0800 Subject: [PATCH 343/443] LoongArch: dts: loongson-2k1000: Fix i2c-gpio node names The binding wants the node to be named "i2c-number", but those are named "i2c-gpio-number" instead. Thus rename those to i2c-0, i2c-1 to adhere to the binding and suppress dtbs_check warnings. Cc: stable@vger.kernel.org Reviewed-by: Krzysztof Kozlowski Signed-off-by: Binbin Zhou Signed-off-by: Huacai Chen --- arch/loongarch/boot/dts/loongson-2k1000.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/loongarch/boot/dts/loongson-2k1000.dtsi b/arch/loongarch/boot/dts/loongson-2k1000.dtsi index 440a8f3c01f4..be4f7d119660 100644 --- a/arch/loongarch/boot/dts/loongson-2k1000.dtsi +++ b/arch/loongarch/boot/dts/loongson-2k1000.dtsi @@ -46,7 +46,7 @@ }; /* i2c of the dvi eeprom edid */ - i2c-gpio-0 { + i2c-0 { compatible = "i2c-gpio"; scl-gpios = <&gpio0 0 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; sda-gpios = <&gpio0 1 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; @@ -57,7 +57,7 @@ }; /* i2c of the eeprom edid */ - i2c-gpio-1 { + i2c-1 { compatible = "i2c-gpio"; scl-gpios = <&gpio0 33 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; sda-gpios = <&gpio0 32 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; From 0bf58cb7288a4d3de6d8ecbb3a65928a9362bf21 Mon Sep 17 00:00:00 2001 From: Qiang Ma Date: Sat, 17 Jan 2026 10:57:02 +0800 Subject: [PATCH 344/443] LoongArch: KVM: Fix kvm_device leak in kvm_ipi_destroy() In kvm_ioctl_create_device(), kvm_device has allocated memory, kvm_device->destroy() seems to be supposed to free its kvm_device struct, but kvm_ipi_destroy() is not currently doing this, that would lead to a memory leak. So, fix it. Cc: stable@vger.kernel.org Reviewed-by: Bibo Mao Signed-off-by: Qiang Ma Signed-off-by: Huacai Chen --- arch/loongarch/kvm/intc/ipi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c index 05cefd29282e..1058c13dba7f 100644 --- a/arch/loongarch/kvm/intc/ipi.c +++ b/arch/loongarch/kvm/intc/ipi.c @@ -459,6 +459,7 @@ static void kvm_ipi_destroy(struct kvm_device *dev) ipi = kvm->arch.ipi; kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &ipi->device); kfree(ipi); + kfree(dev); } static struct kvm_device_ops kvm_ipi_dev_ops = { From 7d8553fc75aefa7ec936af0cf8443ff90b51732e Mon Sep 17 00:00:00 2001 From: Qiang Ma Date: Sat, 17 Jan 2026 10:57:02 +0800 Subject: [PATCH 345/443] LoongArch: KVM: Fix kvm_device leak in kvm_eiointc_destroy() In kvm_ioctl_create_device(), kvm_device has allocated memory, kvm_device->destroy() seems to be supposed to free its kvm_device struct, but kvm_eiointc_destroy() is not currently doing this, that would lead to a memory leak. So, fix it. Cc: stable@vger.kernel.org Reviewed-by: Bibo Mao Signed-off-by: Qiang Ma Signed-off-by: Huacai Chen --- arch/loongarch/kvm/intc/eiointc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c index 29886876143f..dfaf6ccfdd8b 100644 --- a/arch/loongarch/kvm/intc/eiointc.c +++ b/arch/loongarch/kvm/intc/eiointc.c @@ -679,6 +679,7 @@ static void kvm_eiointc_destroy(struct kvm_device *dev) kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device); kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device_vext); kfree(eiointc); + kfree(dev); } static struct kvm_device_ops kvm_eiointc_dev_ops = { From 1cf342a7c3adc5877837b53bbceb5cc9eff60bbf Mon Sep 17 00:00:00 2001 From: Qiang Ma Date: Sat, 17 Jan 2026 10:57:03 +0800 Subject: [PATCH 346/443] LoongArch: KVM: Fix kvm_device leak in kvm_pch_pic_destroy() In kvm_ioctl_create_device(), kvm_device has allocated memory, kvm_device->destroy() seems to be supposed to free its kvm_device struct, but kvm_pch_pic_destroy() is not currently doing this, that would lead to a memory leak. So, fix it. Cc: stable@vger.kernel.org Reviewed-by: Bibo Mao Signed-off-by: Qiang Ma Signed-off-by: Huacai Chen --- arch/loongarch/kvm/intc/pch_pic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c index a698a73de399..4addb34bf432 100644 --- a/arch/loongarch/kvm/intc/pch_pic.c +++ b/arch/loongarch/kvm/intc/pch_pic.c @@ -475,6 +475,7 @@ static void kvm_pch_pic_destroy(struct kvm_device *dev) /* unregister pch pic device and free it's memory */ kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &s->device); kfree(s); + kfree(dev); } static struct kvm_device_ops kvm_pch_pic_dev_ops = { From d9b40d7262a227442bf402ea0708dc94f438bb52 Mon Sep 17 00:00:00 2001 From: Bala-Vignesh-Reddy Date: Wed, 22 Oct 2025 11:59:48 +0530 Subject: [PATCH 347/443] selftests/x86: Add selftests include path for kselftest.h after centralization The previous change centralizing kselftest.h include path in lib.mk caused x86 selftests to fail, as x86 Makefile overwrites CFLAGS using ":=", dropping the include path added in lib.mk. Therefore, helpers.h could not find kselftest.h during compilation. Fix this by adding the tools/testing/sefltest to CFLAGS in x86 Makefile. [ bp: Correct commit ID in Fixes: ] Fixes: e6fbd1759c9e ("selftests: complete kselftest include centralization") Closes: https://lore.kernel.org/lkml/CA+G9fYvKjQcCBMfXA-z2YuL2L+3Qd-pJjEUDX8PDdz2-EEQd=Q@mail.gmail.com/T/#m83fd330231287fc9d6c921155bee16c591db7360 Reported-by: Linux Kernel Functional Testing Signed-off-by: Bala-Vignesh-Reddy Signed-off-by: Borislav Petkov (AMD) Tested-by: Anders Roxell Tested-by: Brendan Jackman Link: https://patch.msgid.link/20251022062948.162852-1-reddybalavignesh9979@gmail.com --- tools/testing/selftests/x86/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 83148875a12c..434065215d12 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -36,6 +36,7 @@ BINARIES_32 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_32)) BINARIES_64 := $(patsubst %,$(OUTPUT)/%,$(BINARIES_64)) CFLAGS := -O2 -g -std=gnu99 -pthread -Wall $(KHDR_INCLUDES) +CFLAGS += -I $(top_srcdir)/tools/testing/selftests/ # call32_from_64 in thunks.S uses absolute addresses. ifeq ($(CAN_BUILD_WITH_NOPIE),1) From 81122fba08fa3ccafab6ed272a5c6f2203923a7e Mon Sep 17 00:00:00 2001 From: Weigang He Date: Sat, 17 Jan 2026 09:12:38 +0000 Subject: [PATCH 348/443] of: fix reference count leak in of_alias_scan() of_find_node_by_path() returns a device_node with its refcount incremented. When kstrtoint() fails or dt_alloc() fails, the function continues to the next iteration without calling of_node_put(), causing a reference count leak. Add of_node_put(np) before continue on both error paths to properly release the device_node reference. Fixes: 611cad720148 ("dt: add of_alias_scan and of_alias_get_id") Cc: stable@vger.kernel.org Signed-off-by: Weigang He Link: https://patch.msgid.link/20260117091238.481243-1-geoffreyhe2@gmail.com Signed-off-by: Rob Herring (Arm) --- drivers/of/base.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index 0b65039ece53..57420806c1a2 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1942,13 +1942,17 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) end--; len = end - start; - if (kstrtoint(end, 10, &id) < 0) + if (kstrtoint(end, 10, &id) < 0) { + of_node_put(np); continue; + } /* Allocate an alias_prop with enough space for the stem */ ap = dt_alloc(sizeof(*ap) + len + 1, __alignof__(*ap)); - if (!ap) + if (!ap) { + of_node_put(np); continue; + } memset(ap, 0, sizeof(*ap) + len + 1); ap->alias = start; of_alias_add(ap, np, id, start, len); From a80c9d945aef55b23b54838334345f20251dad83 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Tue, 13 Jan 2026 12:10:26 -0500 Subject: [PATCH 349/443] sctp: move SCTP_CMD_ASSOC_SHKEY right after SCTP_CMD_PEER_INIT A null-ptr-deref was reported in the SCTP transmit path when SCTP-AUTH key initialization fails: ================================================================== KASAN: null-ptr-deref in range [0x0000000000000018-0x000000000000001f] CPU: 0 PID: 16 Comm: ksoftirqd/0 Tainted: G W 6.6.0 #2 RIP: 0010:sctp_packet_bundle_auth net/sctp/output.c:264 [inline] RIP: 0010:sctp_packet_append_chunk+0xb36/0x1260 net/sctp/output.c:401 Call Trace: sctp_packet_transmit_chunk+0x31/0x250 net/sctp/output.c:189 sctp_outq_flush_data+0xa29/0x26d0 net/sctp/outqueue.c:1111 sctp_outq_flush+0xc80/0x1240 net/sctp/outqueue.c:1217 sctp_cmd_interpreter.isra.0+0x19a5/0x62c0 net/sctp/sm_sideeffect.c:1787 sctp_side_effects net/sctp/sm_sideeffect.c:1198 [inline] sctp_do_sm+0x1a3/0x670 net/sctp/sm_sideeffect.c:1169 sctp_assoc_bh_rcv+0x33e/0x640 net/sctp/associola.c:1052 sctp_inq_push+0x1dd/0x280 net/sctp/inqueue.c:88 sctp_rcv+0x11ae/0x3100 net/sctp/input.c:243 sctp6_rcv+0x3d/0x60 net/sctp/ipv6.c:1127 The issue is triggered when sctp_auth_asoc_init_active_key() fails in sctp_sf_do_5_1C_ack() while processing an INIT_ACK. In this case, the command sequence is currently: - SCTP_CMD_PEER_INIT - SCTP_CMD_TIMER_STOP (T1_INIT) - SCTP_CMD_TIMER_START (T1_COOKIE) - SCTP_CMD_NEW_STATE (COOKIE_ECHOED) - SCTP_CMD_ASSOC_SHKEY - SCTP_CMD_GEN_COOKIE_ECHO If SCTP_CMD_ASSOC_SHKEY fails, asoc->shkey remains NULL, while asoc->peer.auth_capable and asoc->peer.peer_chunks have already been set by SCTP_CMD_PEER_INIT. This allows a DATA chunk with auth = 1 and shkey = NULL to be queued by sctp_datamsg_from_user(). Since command interpretation stops on failure, no COOKIE_ECHO should been sent via SCTP_CMD_GEN_COOKIE_ECHO. However, the T1_COOKIE timer has already been started, and it may enqueue a COOKIE_ECHO into the outqueue later. As a result, the DATA chunk can be transmitted together with the COOKIE_ECHO in sctp_outq_flush_data(), leading to the observed issue. Similar to the other places where it calls sctp_auth_asoc_init_active_key() right after sctp_process_init(), this patch moves the SCTP_CMD_ASSOC_SHKEY immediately after SCTP_CMD_PEER_INIT, before stopping T1_INIT and starting T1_COOKIE. This ensures that if shared key generation fails, authenticated DATA cannot be sent. It also allows the T1_INIT timer to retransmit INIT, giving the client another chance to process INIT_ACK and retry key setup. Fixes: 730fc3d05cd4 ("[SCTP]: Implete SCTP-AUTH parameter processing") Reported-by: Zhen Chen Tested-by: Zhen Chen Signed-off-by: Xin Long Link: https://patch.msgid.link/44881224b375aa8853f5e19b4055a1a56d895813.1768324226.git.lucien.xin@gmail.com Signed-off-by: Jakub Kicinski --- net/sctp/sm_statefuns.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 3755ba079d07..7b823d759141 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -603,6 +603,11 @@ enum sctp_disposition sctp_sf_do_5_1C_ack(struct net *net, sctp_add_cmd_sf(commands, SCTP_CMD_PEER_INIT, SCTP_PEER_INIT(initchunk)); + /* SCTP-AUTH: generate the association shared keys so that + * we can potentially sign the COOKIE-ECHO. + */ + sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_SHKEY, SCTP_NULL()); + /* Reset init error count upon receipt of INIT-ACK. */ sctp_add_cmd_sf(commands, SCTP_CMD_INIT_COUNTER_RESET, SCTP_NULL()); @@ -617,11 +622,6 @@ enum sctp_disposition sctp_sf_do_5_1C_ack(struct net *net, sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, SCTP_STATE(SCTP_STATE_COOKIE_ECHOED)); - /* SCTP-AUTH: generate the association shared keys so that - * we can potentially sign the COOKIE-ECHO. - */ - sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_SHKEY, SCTP_NULL()); - /* 5.1 C) "A" shall then send the State Cookie received in the * INIT ACK chunk in a COOKIE ECHO chunk, ... */ From d998b0e5afffa90d0f03770bad31083767079858 Mon Sep 17 00:00:00 2001 From: Thomas Fourier Date: Wed, 14 Jan 2026 13:31:06 +0100 Subject: [PATCH 350/443] octeontx2: Fix otx2_dma_map_page() error return code 0 is a valid DMA address [1] so using it as the error value can lead to errors. The error value of dma_map_XXX() functions is DMA_MAPPING_ERROR which is ~0. The callers of otx2_dma_map_page() use dma_mapping_error() to test the return value of otx2_dma_map_page(). This means that they would not detect an error in otx2_dma_map_page(). Make otx2_dma_map_page() return the raw value of dma_map_page_attrs(). [1] https://lore.kernel.org/all/f977f68b-cec5-4ab7-b4bd-2cf6aca46267@intel.com Fixes: caa2da34fd25 ("octeontx2-pf: Initialize and config queues") Cc: Signed-off-by: Thomas Fourier Link: https://patch.msgid.link/20260114123107.42387-2-fourier.thomas@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index e616a727a3a9..8cdfc36d79d2 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -940,13 +940,8 @@ static inline dma_addr_t otx2_dma_map_page(struct otx2_nic *pfvf, size_t offset, size_t size, enum dma_data_direction dir) { - dma_addr_t iova; - - iova = dma_map_page_attrs(pfvf->dev, page, + return dma_map_page_attrs(pfvf->dev, page, offset, size, dir, DMA_ATTR_SKIP_CPU_SYNC); - if (unlikely(dma_mapping_error(pfvf->dev, iova))) - return (dma_addr_t)NULL; - return iova; } static inline void otx2_dma_unmap_page(struct otx2_nic *pfvf, From c158f985cf6c2c36c99c4f67af2ff3f5ebe09f8f Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Wed, 14 Jan 2026 22:00:37 +0530 Subject: [PATCH 351/443] amd-xgbe: avoid misleading per-packet error log On the receive path, packet can be damaged because of buffer overflow in Rx FIFO. Avoid misleading per-packet error log when packet->errors is set, this can flood the log. Instead, rely on the standard rtnl_link_stats64 stats. Fixes: c5aa9e3b8156 ("amd-xgbe: Initial AMD 10GbE platform driver") Signed-off-by: Raju Rangoju Link: https://patch.msgid.link/20260114163037.2062606-1-Raju.Rangoju@amd.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 3ddd896d6987..b5a60a048896 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -1837,7 +1837,7 @@ static void xgbe_get_stats64(struct net_device *netdev, s->multicast = pstats->rxmulticastframes_g; s->rx_length_errors = pstats->rxlengtherror; s->rx_crc_errors = pstats->rxcrcerror; - s->rx_fifo_errors = pstats->rxfifooverflow; + s->rx_over_errors = pstats->rxfifooverflow; s->tx_packets = pstats->txframecount_gb; s->tx_bytes = pstats->txoctetcount_gb; @@ -2292,9 +2292,6 @@ read_again: goto read_again; if (error || packet->errors) { - if (packet->errors) - netif_err(pdata, rx_err, netdev, - "error in received packet\n"); dev_kfree_skb(skb); goto next_packet; } From ff7737946812eb59faad70d497b803c4f59200b9 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 15 Jan 2026 13:54:00 +0000 Subject: [PATCH 352/443] docs: netdev: refine 15-patch limit The 15 patch limit is intended by the maintainers to cover all outstanding patches on the mailing list on a per-tree basis. Not just those in a single patchset. Document this practice accordingly. Signed-off-by: Simon Horman Link: https://patch.msgid.link/20260115-15-minutes-of-fame-v2-1-70cbf0883aff@kernel.org Signed-off-by: Jakub Kicinski --- Documentation/process/maintainer-netdev.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Documentation/process/maintainer-netdev.rst b/Documentation/process/maintainer-netdev.rst index 989192421cc9..6bce4507d5d3 100644 --- a/Documentation/process/maintainer-netdev.rst +++ b/Documentation/process/maintainer-netdev.rst @@ -363,6 +363,18 @@ just do it. As a result, a sequence of smaller series gets merged quicker and with better review coverage. Re-posting large series also increases the mailing list traffic. +Limit patches outstanding on mailing list +----------------------------------------- + +Avoid having more than 15 patches, across all series, outstanding for +review on the mailing list for a single tree. In other words, a maximum of +15 patches under review on net, and a maximum of 15 patches under review on +net-next. + +This limit is intended to focus developer effort on testing patches before +upstream review. Aiding the quality of upstream submissions, and easing the +load on reviewers. + .. _rcs: Local variable ordering ("reverse xmas tree", "RCS") From 9a56796ad258786d3624eef5aefba394fc9bdded Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Thu, 15 Jan 2026 17:24:46 +0000 Subject: [PATCH 353/443] gue: Fix skb memleak with inner IP protocol 0. syzbot reported skb memleak below. [0] The repro generated a GUE packet with its inner protocol 0. gue_udp_recv() returns -guehdr->proto_ctype for "resubmit" in ip_protocol_deliver_rcu(), but this only works with non-zero protocol number. Let's drop such packets. Note that 0 is a valid number (IPv6 Hop-by-Hop Option). I think it is not practical to encap HOPOPT in GUE, so once someone starts to complain, we could pass down a resubmit flag pointer to distinguish two zeros from the upper layer: * no error * resubmit HOPOPT [0] BUG: memory leak unreferenced object 0xffff888109695a00 (size 240): comm "syz.0.17", pid 6088, jiffies 4294943096 hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 40 c2 10 81 88 ff ff 00 00 00 00 00 00 00 00 .@.............. backtrace (crc a84b336f): kmemleak_alloc_recursive include/linux/kmemleak.h:44 [inline] slab_post_alloc_hook mm/slub.c:4958 [inline] slab_alloc_node mm/slub.c:5263 [inline] kmem_cache_alloc_noprof+0x3b4/0x590 mm/slub.c:5270 __build_skb+0x23/0x60 net/core/skbuff.c:474 build_skb+0x20/0x190 net/core/skbuff.c:490 __tun_build_skb drivers/net/tun.c:1541 [inline] tun_build_skb+0x4a1/0xa40 drivers/net/tun.c:1636 tun_get_user+0xc12/0x2030 drivers/net/tun.c:1770 tun_chr_write_iter+0x71/0x120 drivers/net/tun.c:1999 new_sync_write fs/read_write.c:593 [inline] vfs_write+0x45d/0x710 fs/read_write.c:686 ksys_write+0xa7/0x170 fs/read_write.c:738 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xa4/0xf80 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f Fixes: 37dd0247797b1 ("gue: Receive side for Generic UDP Encapsulation") Reported-by: syzbot+4d8c7d16b0e95c0d0f0d@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/6965534b.050a0220.38aacd.0001.GAE@google.com/ Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/20260115172533.693652-2-kuniyu@google.com Signed-off-by: Jakub Kicinski --- net/ipv4/fou_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv4/fou_core.c b/net/ipv4/fou_core.c index 3970b6b7ace5..ab8f309f8925 100644 --- a/net/ipv4/fou_core.c +++ b/net/ipv4/fou_core.c @@ -215,6 +215,9 @@ static int gue_udp_recv(struct sock *sk, struct sk_buff *skb) return gue_control_message(skb, guehdr); proto_ctype = guehdr->proto_ctype; + if (unlikely(!proto_ctype)) + goto drop; + __skb_pull(skb, sizeof(struct udphdr) + hdrlen); skb_reset_transport_header(skb); From 68578370f9b3a2aba5964b273312d51c581b6aad Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Thu, 15 Jan 2026 17:24:47 +0000 Subject: [PATCH 354/443] tools: ynl: Specify --no-line-number in ynl-regen.sh. If grep.lineNumber is enabled in .gitconfig, [grep] lineNumber = true ynl-regen.sh fails with the following error: $ ./tools/net/ynl/ynl-regen.sh -f ... ynl_gen_c.py: error: argument --mode: invalid choice: '4:' (choose from user, kernel, uapi) GEN 4: net/ipv4/fou_nl.c Let's specify --no-line-number explicitly. Fixes: be5bea1cc0bf ("net: add basic C code generators for Netlink") Suggested-by: Jakub Kicinski Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/20260115172533.693652-3-kuniyu@google.com Signed-off-by: Jakub Kicinski --- tools/net/ynl/ynl-regen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/net/ynl/ynl-regen.sh b/tools/net/ynl/ynl-regen.sh index 81b4ecd89100..d9809276db98 100755 --- a/tools/net/ynl/ynl-regen.sh +++ b/tools/net/ynl/ynl-regen.sh @@ -21,7 +21,7 @@ files=$(git grep --files-with-matches '^/\* YNL-GEN \(kernel\|uapi\|user\)') for f in $files; do # params: 0 1 2 3 # $YAML YNL-GEN kernel $mode - params=( $(git grep -B1 -h '/\* YNL-GEN' $f | sed 's@/\*\(.*\)\*/@\1@') ) + params=( $(git grep --no-line-number -B1 -h '/\* YNL-GEN' $f | sed 's@/\*\(.*\)\*/@\1@') ) args=$(sed -n 's@/\* YNL-ARG \(.*\) \*/@\1@p' $f) if [ $f -nt ${params[0]} -a -z "$force" ]; then From 7a9bc9e3f42391e4c187e099263cf7a1c4b69ff5 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Thu, 15 Jan 2026 17:24:48 +0000 Subject: [PATCH 355/443] fou: Don't allow 0 for FOU_ATTR_IPPROTO. fou_udp_recv() has the same problem mentioned in the previous patch. If FOU_ATTR_IPPROTO is set to 0, skb is not freed by fou_udp_recv() nor "resubmit"-ted in ip_protocol_deliver_rcu(). Let's forbid 0 for FOU_ATTR_IPPROTO. Fixes: 23461551c0062 ("fou: Support for foo-over-udp RX path") Signed-off-by: Kuniyuki Iwashima Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/20260115172533.693652-4-kuniyu@google.com Signed-off-by: Jakub Kicinski --- Documentation/netlink/specs/fou.yaml | 2 ++ net/ipv4/fou_nl.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/netlink/specs/fou.yaml b/Documentation/netlink/specs/fou.yaml index 8e7974ec453f..331f1b342b3a 100644 --- a/Documentation/netlink/specs/fou.yaml +++ b/Documentation/netlink/specs/fou.yaml @@ -39,6 +39,8 @@ attribute-sets: - name: ipproto type: u8 + checks: + min: 1 - name: type type: u8 diff --git a/net/ipv4/fou_nl.c b/net/ipv4/fou_nl.c index 7a99639204b1..309d5ba983d0 100644 --- a/net/ipv4/fou_nl.c +++ b/net/ipv4/fou_nl.c @@ -15,7 +15,7 @@ const struct nla_policy fou_nl_policy[FOU_ATTR_IFINDEX + 1] = { [FOU_ATTR_PORT] = { .type = NLA_BE16, }, [FOU_ATTR_AF] = { .type = NLA_U8, }, - [FOU_ATTR_IPPROTO] = { .type = NLA_U8, }, + [FOU_ATTR_IPPROTO] = NLA_POLICY_MIN(NLA_U8, 1), [FOU_ATTR_TYPE] = { .type = NLA_U8, }, [FOU_ATTR_REMCSUM_NOPARTIAL] = { .type = NLA_FLAG, }, [FOU_ATTR_LOCAL_V4] = { .type = NLA_U32, }, From b47adaab8b3d443868096bac08fdbb3d403194ba Mon Sep 17 00:00:00 2001 From: David Yang Date: Wed, 14 Jan 2026 20:24:45 +0800 Subject: [PATCH 356/443] veth: fix data race in veth_get_ethtool_stats In veth_get_ethtool_stats(), some statistics protected by u64_stats_sync, are read and accumulated in ignorance of possible u64_stats_fetch_retry() events. These statistics, peer_tq_xdp_xmit and peer_tq_xdp_xmit_err, are already accumulated by veth_xdp_xmit(). Fix this by reading them into a temporary buffer first. Fixes: 5fe6e56776ba ("veth: rely on peer veth_rq for ndo_xdp_xmit accounting") Signed-off-by: David Yang Link: https://patch.msgid.link/20260114122450.227982-1-mmyangfl@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/veth.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 14e6f2a2fb77..9982412fd7f2 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -228,16 +228,20 @@ static void veth_get_ethtool_stats(struct net_device *dev, const struct veth_rq_stats *rq_stats = &rcv_priv->rq[i].stats; const void *base = (void *)&rq_stats->vs; unsigned int start, tx_idx = idx; + u64 buf[VETH_TQ_STATS_LEN]; size_t offset; - tx_idx += (i % dev->real_num_tx_queues) * VETH_TQ_STATS_LEN; do { start = u64_stats_fetch_begin(&rq_stats->syncp); for (j = 0; j < VETH_TQ_STATS_LEN; j++) { offset = veth_tq_stats_desc[j].offset; - data[tx_idx + j] += *(u64 *)(base + offset); + buf[j] = *(u64 *)(base + offset); } } while (u64_stats_fetch_retry(&rq_stats->syncp, start)); + + tx_idx += (i % dev->real_num_tx_queues) * VETH_TQ_STATS_LEN; + for (j = 0; j < VETH_TQ_STATS_LEN; j++) + data[tx_idx + j] += buf[j]; } pp_idx = idx + dev->real_num_tx_queues * VETH_TQ_STATS_LEN; From a92a6c50e35b75a8021265507f3c2a9084df0b94 Mon Sep 17 00:00:00 2001 From: Hamza Mahfooz Date: Tue, 13 Jan 2026 18:29:57 -0500 Subject: [PATCH 357/443] net: sfp: add potron quirk to the H-COM SPP425H-GAB4 SFP+ Stick This is another one of those XGSPON ONU sticks that's using the X-ONU-SFPP internally, thus it also requires the potron quirk to avoid tx faults. So, add an entry for it in sfp_quirks[]. Cc: stable@vger.kernel.org Signed-off-by: Hamza Mahfooz Link: https://patch.msgid.link/20260113232957.609642-1-someguy@effective-light.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/sfp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 84bef5099dda..47f095bd91ce 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -519,6 +519,8 @@ static const struct sfp_quirk sfp_quirks[] = { SFP_QUIRK_F("HALNy", "HL-GSFP", sfp_fixup_halny_gsfp), + SFP_QUIRK_F("H-COM", "SPP425H-GAB4", sfp_fixup_potron), + // HG MXPD-483II-F 2.5G supports 2500Base-X, but incorrectly reports // 2600MBd in their EERPOM SFP_QUIRK_S("HG GENUINE", "MXPD-483II", sfp_quirk_2500basex), From f40ddcc0c0ca1a0122a7f4440b429f97d5832bdf Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Tue, 13 Jan 2026 17:24:58 -0300 Subject: [PATCH 358/443] Revert "nfc/nci: Add the inconsistency check between the input data length and count" This reverts commit 068648aab72c9ba7b0597354ef4d81ffaac7b979. NFC packets may have NUL-bytes. Checking for string length is not a correct assumption here. As long as there is a check for the length copied from copy_from_user, all should be fine. The fix only prevented the syzbot reproducer from triggering the bug because the packet is not enqueued anymore and the code that triggers the bug is not exercised. The fix even broke testing/selftests/nci/nci_dev, making all tests there fail. After the revert, 6 out of 8 tests pass. Fixes: 068648aab72c ("nfc/nci: Add the inconsistency check between the input data length and count") Cc: stable@vger.kernel.org Signed-off-by: Thadeu Lima de Souza Cascardo Link: https://patch.msgid.link/20260113202458.449455-1-cascardo@igalia.com Signed-off-by: Jakub Kicinski --- drivers/nfc/virtual_ncidev.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/nfc/virtual_ncidev.c b/drivers/nfc/virtual_ncidev.c index 9ef8ef2d4363..b957fce83b7c 100644 --- a/drivers/nfc/virtual_ncidev.c +++ b/drivers/nfc/virtual_ncidev.c @@ -125,10 +125,6 @@ static ssize_t virtual_ncidev_write(struct file *file, kfree_skb(skb); return -EFAULT; } - if (strnlen(skb->data, count) != count) { - kfree_skb(skb); - return -EINVAL; - } nci_recv_frame(vdev->ndev, skb); return count; From cd16edba1c6a24af138e1a5ded2711231fffa99f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 4 Dec 2025 11:19:10 +0100 Subject: [PATCH 359/443] ext4: fix ext4_tune_sb_params padding The padding at the end of struct ext4_tune_sb_params is architecture specific and in particular is different between x86-32 and x86-64, since the __u64 member only enforces struct alignment on the latter. This shows up as a new warning when test-building the headers with -Wpadded: include/linux/ext4.h:144:1: error: padding struct size to alignment boundary with 4 bytes [-Werror=padded] All members inside the structure are naturally aligned, so the only difference here is the amount of padding at the end. Make the padding explicit, to have a consistent sizeof(struct ext4_tune_sb_params) of 232 on all architectures and avoid adding compat ioctl handling for EXT4_IOC_GET_TUNE_SB_PARAM/EXT4_IOC_SET_TUNE_SB_PARAM. This is an ABI break on x86-32 but hopefully this can go into 6.18.y early enough as a fixup so no actual users will be affected. Alternatively, the kernel could handle the ioctl commands for both sizes (232 and 228 bytes) on all architectures. Fixes: 04a91570ac67 ("ext4: implemet new ioctls to set and get superblock parameters") Signed-off-by: Arnd Bergmann Reviewed-by: Jan Kara Link: https://patch.msgid.link/20251204101914.1037148-1-arnd@kernel.org Signed-off-by: Theodore Ts'o Cc: stable@kernel.org --- include/uapi/linux/ext4.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/ext4.h b/include/uapi/linux/ext4.h index 411dcc1e4a35..9c683991c32f 100644 --- a/include/uapi/linux/ext4.h +++ b/include/uapi/linux/ext4.h @@ -139,7 +139,7 @@ struct ext4_tune_sb_params { __u32 clear_feature_incompat_mask; __u32 clear_feature_ro_compat_mask; __u8 mount_opts[64]; - __u8 pad[64]; + __u8 pad[68]; }; #define EXT4_TUNE_FL_ERRORS_BEHAVIOR 0x00000001 From 0ef7ef422730b8585214a2825735838d664ce1be Mon Sep 17 00:00:00 2001 From: Julian Sun Date: Mon, 8 Dec 2025 20:37:13 +0800 Subject: [PATCH 360/443] ext4: add missing down_write_data_sem in mext_move_extent(). Commit 962e8a01eab9 ("ext4: introduce mext_move_extent()") attempts to call ext4_swap_extents() on the failure path to recover the swapped extents, but fails to acquire locks for the two inode->i_data_sem, triggering the BUG_ON statement in ext4_swap_extents(). This issue can be fixed by calling ext4_double_down_write_data_sem() before ext4_swap_extents(). Signed-off-by: Julian Sun Reported-by: syzbot+4ea6bd8737669b423aae@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/69368649.a70a0220.38f243.0093.GAE@google.com/ Fixes: 962e8a01eab9 ("ext4: introduce mext_move_extent()") Reviewed-by: Baokun Li Reviewed-by: Jan Kara Reviewed-by: Zhang Yi Signed-off-by: Theodore Ts'o Link: https://patch.msgid.link/20251208123713.1971068-1-sunjunchao@bytedance.com Signed-off-by: Theodore Ts'o --- fs/ext4/move_extent.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c index 0550fd30fd10..635fb8a52e0c 100644 --- a/fs/ext4/move_extent.c +++ b/fs/ext4/move_extent.c @@ -393,9 +393,11 @@ out: repair_branches: ret2 = 0; + ext4_double_down_write_data_sem(orig_inode, donor_inode); r_len = ext4_swap_extents(handle, donor_inode, orig_inode, mext->donor_lblk, orig_map->m_lblk, *m_len, 0, &ret2); + ext4_double_up_write_data_sem(orig_inode, donor_inode); if (ret2 || r_len != *m_len) { ext4_error_inode_block(orig_inode, (sector_t)(orig_map->m_lblk), EIO, "Unable to copy data block, data will be lost!"); From d250bdf531d9cd4096fedbb9f172bb2ca660c868 Mon Sep 17 00:00:00 2001 From: Yang Erkun Date: Sat, 13 Dec 2025 13:57:06 +0800 Subject: [PATCH 361/443] ext4: fix iloc.bh leak in ext4_xattr_inode_update_ref The error branch for ext4_xattr_inode_update_ref forget to release the refcount for iloc.bh. Find this when review code. Fixes: 57295e835408 ("ext4: guard against EA inode refcount underflow in xattr update") Signed-off-by: Yang Erkun Reviewed-by: Baokun Li Reviewed-by: Zhang Yi Link: https://patch.msgid.link/20251213055706.3417529-1-yangerkun@huawei.com Signed-off-by: Theodore Ts'o Cc: stable@kernel.org --- fs/ext4/xattr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 2e02efbddaac..4ed8ddf2a60b 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -1037,6 +1037,7 @@ static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode, ext4_error_inode(ea_inode, __func__, __LINE__, 0, "EA inode %lu ref wraparound: ref_count=%lld ref_change=%d", ea_inode->i_ino, ref_count, ref_change); + brelse(iloc.bh); ret = -EFSCORRUPTED; goto out; } From 24d479d26b25bce5faea3ddd9fa8f3a6c3129ea7 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 18 Jan 2026 15:42:45 -0800 Subject: [PATCH 362/443] Linux 6.19-rc6 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9d38125263fb..1465f715786d 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ VERSION = 6 PATCHLEVEL = 19 SUBLEVEL = 0 -EXTRAVERSION = -rc5 +EXTRAVERSION = -rc6 NAME = Baby Opossum Posse # *DOCUMENTATION* From c198b7773ca5bc3bdfb15b85e414fb9a99a5e5ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 19 Jan 2026 16:13:26 +0100 Subject: [PATCH 363/443] pwm: Ensure ioctl() returns a negative errno on error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit copy_to_user() returns the number of bytes not copied, thus if there is a problem a positive number. However the ioctl callback is supposed to return a negative error code on error. This error is a unfortunate as strictly speaking it became ABI with the introduction of pwm character devices. However I never saw the issue in real life -- I found this by code inspection -- and it only affects an error case where readonly memory is passed to the ioctls or the address mapping changes while the ioctl is active. Also there are already error cases returning negative values, so the calling code must be prepared to see such values already. Fixes: 9c06f26ba5f5 ("pwm: Add support for pwmchip devices for faster and easier userspace access") Signed-off-by: Uwe Kleine-König Link: https://patch.msgid.link/20260119151325.571857-2-u.kleine-koenig@baylibre.com Signed-off-by: Uwe Kleine-König --- drivers/pwm/core.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index cd06229db394..ec8731515333 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -2295,8 +2295,9 @@ static long pwm_cdev_ioctl(struct file *file, unsigned int cmd, unsigned long ar .duty_offset_ns = wf.duty_offset_ns, }; - return copy_to_user((struct pwmchip_waveform __user *)arg, - &cwf, sizeof(cwf)); + ret = copy_to_user((struct pwmchip_waveform __user *)arg, + &cwf, sizeof(cwf)); + return ret ? -EFAULT : 0; } case PWM_IOCTL_GETWF: @@ -2329,8 +2330,9 @@ static long pwm_cdev_ioctl(struct file *file, unsigned int cmd, unsigned long ar .duty_offset_ns = wf.duty_offset_ns, }; - return copy_to_user((struct pwmchip_waveform __user *)arg, - &cwf, sizeof(cwf)); + ret = copy_to_user((struct pwmchip_waveform __user *)arg, + &cwf, sizeof(cwf)); + return ret ? -EFAULT : 0; } case PWM_IOCTL_SETROUNDEDWF: From 63faf32666e03a78cc985bcbae196418cf7d7938 Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Tue, 13 Jan 2026 17:39:07 +0100 Subject: [PATCH 364/443] pwm: max7360: Populate missing .sizeof_wfhw in max7360_pwm_ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sizeof_wfhw field wasn't populated in max7360_pwm_ops so it was set to 0 by default. While this is ok for now because: sizeof(struct max7360_pwm_waveform) < PWM_WFHWSIZE in the future, if struct max7360_pwm_waveform grows, it could lead to stack corruption. Fixes: d93a75d94b79 ("pwm: max7360: Add MAX7360 PWM support") Signed-off-by: Richard Genoud Link: https://patch.msgid.link/20260113163907.368919-1-richard.genoud@bootlin.com Signed-off-by: Uwe Kleine-König --- drivers/pwm/pwm-max7360.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pwm/pwm-max7360.c b/drivers/pwm/pwm-max7360.c index 16261958ce7f..732969303dd7 100644 --- a/drivers/pwm/pwm-max7360.c +++ b/drivers/pwm/pwm-max7360.c @@ -153,6 +153,7 @@ static int max7360_pwm_read_waveform(struct pwm_chip *chip, } static const struct pwm_ops max7360_pwm_ops = { + .sizeof_wfhw = sizeof(struct max7360_pwm_waveform), .request = max7360_pwm_request, .round_waveform_tohw = max7360_pwm_round_waveform_tohw, .round_waveform_fromhw = max7360_pwm_round_waveform_fromhw, From 7a29f6bf60f2590fe5e9c4decb451e19afad2bcf Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 15 Jan 2026 09:21:39 +0000 Subject: [PATCH 365/443] l2tp: avoid one data-race in l2tp_tunnel_del_work() We should read sk->sk_socket only when dealing with kernel sockets. syzbot reported the following data-race: BUG: KCSAN: data-race in l2tp_tunnel_del_work / sk_common_release write to 0xffff88811c182b20 of 8 bytes by task 5365 on cpu 0: sk_set_socket include/net/sock.h:2092 [inline] sock_orphan include/net/sock.h:2118 [inline] sk_common_release+0xae/0x230 net/core/sock.c:4003 udp_lib_close+0x15/0x20 include/net/udp.h:325 inet_release+0xce/0xf0 net/ipv4/af_inet.c:437 __sock_release net/socket.c:662 [inline] sock_close+0x6b/0x150 net/socket.c:1455 __fput+0x29b/0x650 fs/file_table.c:468 ____fput+0x1c/0x30 fs/file_table.c:496 task_work_run+0x131/0x1a0 kernel/task_work.c:233 resume_user_mode_work include/linux/resume_user_mode.h:50 [inline] __exit_to_user_mode_loop kernel/entry/common.c:44 [inline] exit_to_user_mode_loop+0x1fe/0x740 kernel/entry/common.c:75 __exit_to_user_mode_prepare include/linux/irq-entry-common.h:226 [inline] syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:256 [inline] syscall_exit_to_user_mode_work include/linux/entry-common.h:159 [inline] syscall_exit_to_user_mode include/linux/entry-common.h:194 [inline] do_syscall_64+0x1e1/0x2b0 arch/x86/entry/syscall_64.c:100 entry_SYSCALL_64_after_hwframe+0x77/0x7f read to 0xffff88811c182b20 of 8 bytes by task 827 on cpu 1: l2tp_tunnel_del_work+0x2f/0x1a0 net/l2tp/l2tp_core.c:1418 process_one_work kernel/workqueue.c:3257 [inline] process_scheduled_works+0x4ce/0x9d0 kernel/workqueue.c:3340 worker_thread+0x582/0x770 kernel/workqueue.c:3421 kthread+0x489/0x510 kernel/kthread.c:463 ret_from_fork+0x149/0x290 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:246 value changed: 0xffff88811b818000 -> 0x0000000000000000 Fixes: d00fa9adc528 ("l2tp: fix races with tunnel socket close") Reported-by: syzbot+7312e82745f7fa2526db@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/6968b029.050a0220.58bed.0016.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Cc: James Chapman Reviewed-by: Guillaume Nault Link: https://patch.msgid.link/20260115092139.3066180-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/l2tp/l2tp_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 70335667ef03..f9b0f666600f 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1416,8 +1416,6 @@ static void l2tp_tunnel_del_work(struct work_struct *work) { struct l2tp_tunnel *tunnel = container_of(work, struct l2tp_tunnel, del_work); - struct sock *sk = tunnel->sock; - struct socket *sock = sk->sk_socket; l2tp_tunnel_closeall(tunnel); @@ -1425,6 +1423,8 @@ static void l2tp_tunnel_del_work(struct work_struct *work) * the sk API to release it here. */ if (tunnel->fd < 0) { + struct socket *sock = tunnel->sock->sk_socket; + if (sock) { kernel_sock_shutdown(sock, SHUT_RDWR); sock_release(sock); From d3ba32162488283c0a4c5bedd8817aec91748802 Mon Sep 17 00:00:00 2001 From: Dmitry Skorodumov Date: Mon, 12 Jan 2026 17:24:06 +0300 Subject: [PATCH 366/443] ipvlan: Make the addrs_lock be per port Make the addrs_lock be per port, not per ipvlan dev. Initial code seems to be written in the assumption, that any address change must occur under RTNL. But it is not so for the case of IPv6. So 1) Introduce per-port addrs_lock. 2) It was needed to fix places where it was forgotten to take lock (ipvlan_open/ipvlan_close) This appears to be a very minor problem though. Since it's highly unlikely that ipvlan_add_addr() will be called on 2 CPU simultaneously. But nevertheless, this could cause: 1) False-negative of ipvlan_addr_busy(): one interface iterated through all port->ipvlans + ipvlan->addrs under some ipvlan spinlock, and another added IP under its own lock. Though this is only possible for IPv6, since looks like only ipvlan_addr6_event() can be called without rtnl_lock. 2) Race since ipvlan_ht_addr_add(port) is called under different ipvlan->addrs_lock locks This should not affect performance, since add/remove IP is a rare situation and spinlock is not taken on fast paths. Fixes: 8230819494b3 ("ipvlan: use per device spinlock to protect addrs list updates") Signed-off-by: Dmitry Skorodumov Reviewed-by: Paolo Abeni Link: https://patch.msgid.link/20260112142417.4039566-2-skorodumov.dmitry@huawei.com Signed-off-by: Jakub Kicinski --- drivers/net/ipvlan/ipvlan.h | 2 +- drivers/net/ipvlan/ipvlan_core.c | 16 +++++------ drivers/net/ipvlan/ipvlan_main.c | 49 +++++++++++++++++++------------- 3 files changed, 37 insertions(+), 30 deletions(-) diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h index 50de3ee204db..80f84fc87008 100644 --- a/drivers/net/ipvlan/ipvlan.h +++ b/drivers/net/ipvlan/ipvlan.h @@ -69,7 +69,6 @@ struct ipvl_dev { DECLARE_BITMAP(mac_filters, IPVLAN_MAC_FILTER_SIZE); netdev_features_t sfeatures; u32 msg_enable; - spinlock_t addrs_lock; }; struct ipvl_addr { @@ -90,6 +89,7 @@ struct ipvl_port { struct net_device *dev; possible_net_t pnet; struct hlist_head hlhead[IPVLAN_HASH_SIZE]; + spinlock_t addrs_lock; /* guards hash-table and addrs */ struct list_head ipvlans; u16 mode; u16 flags; diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index 2efa3ba148aa..bdb3a46b327c 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -107,17 +107,15 @@ void ipvlan_ht_addr_del(struct ipvl_addr *addr) struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan, const void *iaddr, bool is_v6) { - struct ipvl_addr *addr, *ret = NULL; + struct ipvl_addr *addr; - rcu_read_lock(); - list_for_each_entry_rcu(addr, &ipvlan->addrs, anode) { - if (addr_equal(is_v6, addr, iaddr)) { - ret = addr; - break; - } + assert_spin_locked(&ipvlan->port->addrs_lock); + + list_for_each_entry(addr, &ipvlan->addrs, anode) { + if (addr_equal(is_v6, addr, iaddr)) + return addr; } - rcu_read_unlock(); - return ret; + return NULL; } bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6) diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 660f3db11766..baccdad695fd 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -75,6 +75,7 @@ static int ipvlan_port_create(struct net_device *dev) for (idx = 0; idx < IPVLAN_HASH_SIZE; idx++) INIT_HLIST_HEAD(&port->hlhead[idx]); + spin_lock_init(&port->addrs_lock); skb_queue_head_init(&port->backlog); INIT_WORK(&port->wq, ipvlan_process_multicast); ida_init(&port->ida); @@ -181,6 +182,7 @@ static void ipvlan_uninit(struct net_device *dev) static int ipvlan_open(struct net_device *dev) { struct ipvl_dev *ipvlan = netdev_priv(dev); + struct ipvl_port *port = ipvlan->port; struct ipvl_addr *addr; if (ipvlan->port->mode == IPVLAN_MODE_L3 || @@ -189,10 +191,10 @@ static int ipvlan_open(struct net_device *dev) else dev->flags &= ~IFF_NOARP; - rcu_read_lock(); - list_for_each_entry_rcu(addr, &ipvlan->addrs, anode) + spin_lock_bh(&port->addrs_lock); + list_for_each_entry(addr, &ipvlan->addrs, anode) ipvlan_ht_addr_add(ipvlan, addr); - rcu_read_unlock(); + spin_unlock_bh(&port->addrs_lock); return 0; } @@ -206,10 +208,10 @@ static int ipvlan_stop(struct net_device *dev) dev_uc_unsync(phy_dev, dev); dev_mc_unsync(phy_dev, dev); - rcu_read_lock(); - list_for_each_entry_rcu(addr, &ipvlan->addrs, anode) + spin_lock_bh(&ipvlan->port->addrs_lock); + list_for_each_entry(addr, &ipvlan->addrs, anode) ipvlan_ht_addr_del(addr); - rcu_read_unlock(); + spin_unlock_bh(&ipvlan->port->addrs_lock); return 0; } @@ -579,7 +581,6 @@ int ipvlan_link_new(struct net_device *dev, struct rtnl_newlink_params *params, if (!tb[IFLA_MTU]) ipvlan_adjust_mtu(ipvlan, phy_dev); INIT_LIST_HEAD(&ipvlan->addrs); - spin_lock_init(&ipvlan->addrs_lock); /* TODO Probably put random address here to be presented to the * world but keep using the physical-dev address for the outgoing @@ -657,13 +658,13 @@ void ipvlan_link_delete(struct net_device *dev, struct list_head *head) struct ipvl_dev *ipvlan = netdev_priv(dev); struct ipvl_addr *addr, *next; - spin_lock_bh(&ipvlan->addrs_lock); + spin_lock_bh(&ipvlan->port->addrs_lock); list_for_each_entry_safe(addr, next, &ipvlan->addrs, anode) { ipvlan_ht_addr_del(addr); list_del_rcu(&addr->anode); kfree_rcu(addr, rcu); } - spin_unlock_bh(&ipvlan->addrs_lock); + spin_unlock_bh(&ipvlan->port->addrs_lock); ida_free(&ipvlan->port->ida, dev->dev_id); list_del_rcu(&ipvlan->pnode); @@ -817,6 +818,8 @@ static int ipvlan_add_addr(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6) { struct ipvl_addr *addr; + assert_spin_locked(&ipvlan->port->addrs_lock); + addr = kzalloc(sizeof(struct ipvl_addr), GFP_ATOMIC); if (!addr) return -ENOMEM; @@ -847,16 +850,16 @@ static void ipvlan_del_addr(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6) { struct ipvl_addr *addr; - spin_lock_bh(&ipvlan->addrs_lock); + spin_lock_bh(&ipvlan->port->addrs_lock); addr = ipvlan_find_addr(ipvlan, iaddr, is_v6); if (!addr) { - spin_unlock_bh(&ipvlan->addrs_lock); + spin_unlock_bh(&ipvlan->port->addrs_lock); return; } ipvlan_ht_addr_del(addr); list_del_rcu(&addr->anode); - spin_unlock_bh(&ipvlan->addrs_lock); + spin_unlock_bh(&ipvlan->port->addrs_lock); kfree_rcu(addr, rcu); } @@ -878,14 +881,14 @@ static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr) { int ret = -EINVAL; - spin_lock_bh(&ipvlan->addrs_lock); + spin_lock_bh(&ipvlan->port->addrs_lock); if (ipvlan_addr_busy(ipvlan->port, ip6_addr, true)) netif_err(ipvlan, ifup, ipvlan->dev, "Failed to add IPv6=%pI6c addr for %s intf\n", ip6_addr, ipvlan->dev->name); else ret = ipvlan_add_addr(ipvlan, ip6_addr, true); - spin_unlock_bh(&ipvlan->addrs_lock); + spin_unlock_bh(&ipvlan->port->addrs_lock); return ret; } @@ -924,21 +927,24 @@ static int ipvlan_addr6_validator_event(struct notifier_block *unused, struct in6_validator_info *i6vi = (struct in6_validator_info *)ptr; struct net_device *dev = (struct net_device *)i6vi->i6vi_dev->dev; struct ipvl_dev *ipvlan = netdev_priv(dev); + int ret = NOTIFY_OK; if (!ipvlan_is_valid_dev(dev)) return NOTIFY_DONE; switch (event) { case NETDEV_UP: + spin_lock_bh(&ipvlan->port->addrs_lock); if (ipvlan_addr_busy(ipvlan->port, &i6vi->i6vi_addr, true)) { NL_SET_ERR_MSG(i6vi->extack, "Address already assigned to an ipvlan device"); - return notifier_from_errno(-EADDRINUSE); + ret = notifier_from_errno(-EADDRINUSE); } + spin_unlock_bh(&ipvlan->port->addrs_lock); break; } - return NOTIFY_OK; + return ret; } #endif @@ -946,14 +952,14 @@ static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr) { int ret = -EINVAL; - spin_lock_bh(&ipvlan->addrs_lock); + spin_lock_bh(&ipvlan->port->addrs_lock); if (ipvlan_addr_busy(ipvlan->port, ip4_addr, false)) netif_err(ipvlan, ifup, ipvlan->dev, "Failed to add IPv4=%pI4 on %s intf.\n", ip4_addr, ipvlan->dev->name); else ret = ipvlan_add_addr(ipvlan, ip4_addr, false); - spin_unlock_bh(&ipvlan->addrs_lock); + spin_unlock_bh(&ipvlan->port->addrs_lock); return ret; } @@ -995,21 +1001,24 @@ static int ipvlan_addr4_validator_event(struct notifier_block *unused, struct in_validator_info *ivi = (struct in_validator_info *)ptr; struct net_device *dev = (struct net_device *)ivi->ivi_dev->dev; struct ipvl_dev *ipvlan = netdev_priv(dev); + int ret = NOTIFY_OK; if (!ipvlan_is_valid_dev(dev)) return NOTIFY_DONE; switch (event) { case NETDEV_UP: + spin_lock_bh(&ipvlan->port->addrs_lock); if (ipvlan_addr_busy(ipvlan->port, &ivi->ivi_addr, false)) { NL_SET_ERR_MSG(ivi->extack, "Address already assigned to an ipvlan device"); - return notifier_from_errno(-EADDRINUSE); + ret = notifier_from_errno(-EADDRINUSE); } + spin_unlock_bh(&ipvlan->port->addrs_lock); break; } - return NOTIFY_OK; + return ret; } static struct notifier_block ipvlan_addr4_notifier_block __read_mostly = { From 8becfe16e4a12218c703a98f5bfc15b6f0fbd99c Mon Sep 17 00:00:00 2001 From: Dmitry Skorodumov Date: Mon, 12 Jan 2026 17:24:07 +0300 Subject: [PATCH 367/443] selftests: net: simple selftest for ipvtap This is a simple ipvtap test to test handling IP-address add/remove on ipvlan interface. It creates a veth-interface and then creates several network-namespace with ipvlan0 interface in it linked to veth. Then it starts to add/remove addresses on ipvlan0 interfaces in several threads. At finish, it checks that there is no duplicated addresses. Signed-off-by: Dmitry Skorodumov Link: https://patch.msgid.link/20260112142417.4039566-3-skorodumov.dmitry@huawei.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/Makefile | 1 + tools/testing/selftests/net/config | 2 + tools/testing/selftests/net/ipvtap_test.sh | 168 +++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100755 tools/testing/selftests/net/ipvtap_test.sh diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index b66ba04f19d9..45c4ea381bc3 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -48,6 +48,7 @@ TEST_PROGS := \ ipv6_flowlabel.sh \ ipv6_force_forwarding.sh \ ipv6_route_update_soft_lockup.sh \ + ipvtap_test.sh \ l2_tos_ttl_inherit.sh \ l2tp.sh \ link_netns.py \ diff --git a/tools/testing/selftests/net/config b/tools/testing/selftests/net/config index 1e1f253118f5..b84362b9b508 100644 --- a/tools/testing/selftests/net/config +++ b/tools/testing/selftests/net/config @@ -48,6 +48,7 @@ CONFIG_IPV6_SEG6_LWTUNNEL=y CONFIG_IPV6_SIT=y CONFIG_IPV6_VTI=y CONFIG_IPVLAN=m +CONFIG_IPVTAP=m CONFIG_KALLSYMS=y CONFIG_L2TP=m CONFIG_L2TP_ETH=m @@ -116,6 +117,7 @@ CONFIG_PROC_SYSCTL=y CONFIG_PSAMPLE=m CONFIG_RPS=y CONFIG_SYSFS=y +CONFIG_TAP=m CONFIG_TCP_MD5SIG=y CONFIG_TEST_BLACKHOLE_DEV=m CONFIG_TEST_BPF=m diff --git a/tools/testing/selftests/net/ipvtap_test.sh b/tools/testing/selftests/net/ipvtap_test.sh new file mode 100755 index 000000000000..354ca7ce8584 --- /dev/null +++ b/tools/testing/selftests/net/ipvtap_test.sh @@ -0,0 +1,168 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Simple tests for ipvtap + + +# +# The testing environment looks this way: +# +# |------HNS-------| |------PHY-------| +# | veth<----------------->veth | +# |------|--|------| |----------------| +# | | +# | | |-----TST0-------| +# | |------------|----ipvlan | +# | |----------------| +# | +# | |-----TST1-------| +# |---------------|----ipvlan | +# |----------------| +# + +ALL_TESTS=" + test_ip_set +" + +source lib.sh + +DEBUG=0 + +VETH_HOST=vethtst.h +VETH_PHY=vethtst.p + +NS_COUNT=32 +IP_ITERATIONS=1024 +IPSET_TIMEOUT="60s" + +ns_run() { + ns=$1 + shift + if [[ "$ns" == "global" ]]; then + "$@" >/dev/null + else + ip netns exec "$ns" "$@" >/dev/null + fi +} + +test_ip_setup_env() { + setup_ns NS_PHY + setup_ns HST_NS + + # setup simulated other-host (phy) and host itself + ns_run "$HST_NS" ip link add $VETH_HOST type veth peer name $VETH_PHY \ + netns "$NS_PHY" >/dev/null + ns_run "$HST_NS" ip link set $VETH_HOST up + ns_run "$NS_PHY" ip link set $VETH_PHY up + + for ((i=0; i/dev/null + ip a a "fc00::$v/64" dev ipvlan0 2>/dev/null + v=$(rnd) + ip a d "172.25.0.$v/24" dev ipvlan0 2>/dev/null + ip a d "fc00::$v/64" dev ipvlan0 2>/dev/null + done +} + +test_ip_set() { + RET=0 + + trap test_ip_cleanup_env EXIT + + test_ip_setup_env + + declare -A ns_pids + for ((i=0; i Date: Wed, 14 Jan 2026 22:03:23 +0000 Subject: [PATCH 368/443] rxrpc: Fix recvmsg() unconditional requeue If rxrpc_recvmsg() fails because MSG_DONTWAIT was specified but the call at the front of the recvmsg queue already has its mutex locked, it requeues the call - whether or not the call is already queued. The call may be on the queue because MSG_PEEK was also passed and so the call was not dequeued or because the I/O thread requeued it. The unconditional requeue may then corrupt the recvmsg queue, leading to things like UAFs or refcount underruns. Fix this by only requeuing the call if it isn't already on the queue - and moving it to the front if it is already queued. If we don't queue it, we have to put the ref we obtained by dequeuing it. Also, MSG_PEEK doesn't dequeue the call so shouldn't call rxrpc_notify_socket() for the call if we didn't use up all the data on the queue, so fix that also. Fixes: 540b1c48c37a ("rxrpc: Fix deadlock between call creation and sendmsg/recvmsg") Reported-by: Faith Reported-by: Pumpkin Chang Signed-off-by: David Howells Acked-by: Marc Dionne cc: Nir Ohfeld cc: Willy Tarreau cc: Simon Horman cc: linux-afs@lists.infradead.org cc: stable@kernel.org Link: https://patch.msgid.link/95163.1768428203@warthog.procyon.org.uk Signed-off-by: Jakub Kicinski --- include/trace/events/rxrpc.h | 4 ++++ net/rxrpc/recvmsg.c | 19 +++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h index de6f6d25767c..869f97c9bf73 100644 --- a/include/trace/events/rxrpc.h +++ b/include/trace/events/rxrpc.h @@ -322,6 +322,7 @@ EM(rxrpc_call_put_kernel, "PUT kernel ") \ EM(rxrpc_call_put_poke, "PUT poke ") \ EM(rxrpc_call_put_recvmsg, "PUT recvmsg ") \ + EM(rxrpc_call_put_recvmsg_peek_nowait, "PUT peek-nwt") \ EM(rxrpc_call_put_release_recvmsg_q, "PUT rls-rcmq") \ EM(rxrpc_call_put_release_sock, "PUT rls-sock") \ EM(rxrpc_call_put_release_sock_tba, "PUT rls-sk-a") \ @@ -340,6 +341,9 @@ EM(rxrpc_call_see_input, "SEE input ") \ EM(rxrpc_call_see_notify_released, "SEE nfy-rlsd") \ EM(rxrpc_call_see_recvmsg, "SEE recvmsg ") \ + EM(rxrpc_call_see_recvmsg_requeue, "SEE recv-rqu") \ + EM(rxrpc_call_see_recvmsg_requeue_first, "SEE recv-rqF") \ + EM(rxrpc_call_see_recvmsg_requeue_move, "SEE recv-rqM") \ EM(rxrpc_call_see_release, "SEE release ") \ EM(rxrpc_call_see_userid_exists, "SEE u-exists") \ EM(rxrpc_call_see_waiting_call, "SEE q-conn ") \ diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c index 7fa7e77f6bb9..e1f7513a46db 100644 --- a/net/rxrpc/recvmsg.c +++ b/net/rxrpc/recvmsg.c @@ -518,7 +518,8 @@ try_again: if (rxrpc_call_has_failed(call)) goto call_failed; - if (!skb_queue_empty(&call->recvmsg_queue)) + if (!(flags & MSG_PEEK) && + !skb_queue_empty(&call->recvmsg_queue)) rxrpc_notify_socket(call); goto not_yet_complete; @@ -549,11 +550,21 @@ error_unlock_call: error_requeue_call: if (!(flags & MSG_PEEK)) { spin_lock_irq(&rx->recvmsg_lock); - list_add(&call->recvmsg_link, &rx->recvmsg_q); - spin_unlock_irq(&rx->recvmsg_lock); + if (list_empty(&call->recvmsg_link)) { + list_add(&call->recvmsg_link, &rx->recvmsg_q); + rxrpc_see_call(call, rxrpc_call_see_recvmsg_requeue); + spin_unlock_irq(&rx->recvmsg_lock); + } else if (list_is_first(&call->recvmsg_link, &rx->recvmsg_q)) { + spin_unlock_irq(&rx->recvmsg_lock); + rxrpc_put_call(call, rxrpc_call_see_recvmsg_requeue_first); + } else { + list_move(&call->recvmsg_link, &rx->recvmsg_q); + spin_unlock_irq(&rx->recvmsg_lock); + rxrpc_put_call(call, rxrpc_call_see_recvmsg_requeue_move); + } trace_rxrpc_recvmsg(call_debug_id, rxrpc_recvmsg_requeue, 0); } else { - rxrpc_put_call(call, rxrpc_call_put_recvmsg); + rxrpc_put_call(call, rxrpc_call_put_recvmsg_peek_nowait); } error_no_call: release_sock(&rx->sk); From ab9b218a1521133a4410722907fa7189566be9bc Mon Sep 17 00:00:00 2001 From: Alok Tiwari Date: Fri, 16 Jan 2026 08:47:12 -0800 Subject: [PATCH 369/443] octeontx2: cn10k: fix RX flowid TCAM mask handling The RX flowid programming initializes the TCAM mask to all ones, but then overwrites it when clearing the MAC DA mask bits. This results in losing the intended initialization and may affect other match fields. Update the code to clear the MAC DA bits using an AND operation, making the handling of mask[0] consistent with mask[1], where the field-specific bits are cleared after initializing the mask to ~0ULL. Fixes: 57d00d4364f3 ("octeontx2-pf: mcs: Match macsec ethertype along with DMAC") Signed-off-by: Alok Tiwari Reviewed-by: Subbaraya Sundeep Link: https://patch.msgid.link/20260116164724.2733511-1-alok.a.tiwari@oracle.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c index 4c7e0f345cb5..060c715ebad0 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k_macsec.c @@ -328,7 +328,7 @@ static int cn10k_mcs_write_rx_flowid(struct otx2_nic *pfvf, req->data[0] = FIELD_PREP(MCS_TCAM0_MAC_DA_MASK, mac_da); req->mask[0] = ~0ULL; - req->mask[0] = ~MCS_TCAM0_MAC_DA_MASK; + req->mask[0] &= ~MCS_TCAM0_MAC_DA_MASK; req->data[1] = FIELD_PREP(MCS_TCAM1_ETYPE_MASK, ETH_P_MACSEC); req->mask[1] = ~0ULL; From 50da4b9d07a7a463e2cfb738f3ad4cff6b2c9c3b Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Wed, 14 Jan 2026 11:02:41 -0500 Subject: [PATCH 370/443] net/sched: Enforce that teql can only be used as root qdisc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Design intent of teql is that it is only supposed to be used as root qdisc. We need to check for that constraint. Although not important, I will describe the scenario that unearthed this issue for the curious. GangMin Kim managed to concot a scenario as follows: ROOT qdisc 1:0 (QFQ) ├── class 1:1 (weight=15, lmax=16384) netem with delay 6.4s └── class 1:2 (weight=1, lmax=1514) teql GangMin sends a packet which is enqueued to 1:1 (netem). Any invocation of dequeue by QFQ from this class will not return a packet until after 6.4s. In the meantime, a second packet is sent and it lands on 1:2. teql's enqueue will return success and this will activate class 1:2. Main issue is that teql only updates the parent visible qlen (sch->q.qlen) at dequeue. Since QFQ will only call dequeue if peek succeeds (and teql's peek always returns NULL), dequeue will never be called and thus the qlen will remain as 0. With that in mind, when GangMin updates 1:2's lmax value, the qfq_change_class calls qfq_deact_rm_from_agg. Since the child qdisc's qlen was not incremented, qfq fails to deactivate the class, but still frees its pointers from the aggregate. So when the first packet is rescheduled after 6.4 seconds (netem's delay), a dangling pointer is accessed causing GangMin's causing a UAF. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: GangMin Kim Tested-by: Victor Nogueira Signed-off-by: Jamal Hadi Salim Link: https://patch.msgid.link/20260114160243.913069-2-jhs@mojatatu.com Signed-off-by: Jakub Kicinski --- net/sched/sch_teql.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 8badec6d82a2..6e4bdaa876ed 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -178,6 +178,11 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt, if (m->dev == dev) return -ELOOP; + if (sch->parent != TC_H_ROOT) { + NL_SET_ERR_MSG_MOD(extack, "teql can only be used as root"); + return -EOPNOTSUPP; + } + q->m = m; skb_queue_head_init(&q->q); From d837fbee92453fbb829f950c8e7cf76207d73f33 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Wed, 14 Jan 2026 11:02:42 -0500 Subject: [PATCH 371/443] net/sched: qfq: Use cl_is_active to determine whether class is active in qfq_rm_from_ag This is more of a preventive patch to make the code more consistent and to prevent possible exploits that employ child qlen manipulations on qfq. use cl_is_active instead of relying on the child qdisc's qlen to determine class activation. Fixes: 462dbc9101acd ("pkt_sched: QFQ Plus: fair-queueing service at DRR cost") Signed-off-by: Jamal Hadi Salim Link: https://patch.msgid.link/20260114160243.913069-3-jhs@mojatatu.com Signed-off-by: Jakub Kicinski --- net/sched/sch_qfq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 9d59090bbe93..e7778413e72f 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -373,7 +373,7 @@ static void qfq_rm_from_agg(struct qfq_sched *q, struct qfq_class *cl) /* Deschedule class and remove it from its parent aggregate. */ static void qfq_deact_rm_from_agg(struct qfq_sched *q, struct qfq_class *cl) { - if (cl->qdisc->q.qlen > 0) /* class is active */ + if (cl_is_active(cl)) /* class is active */ qfq_deactivate_class(q, cl); qfq_rm_from_agg(q, cl); From 2460f31e6e444a52a4e718e4fe64cff29ffaab05 Mon Sep 17 00:00:00 2001 From: Victor Nogueira Date: Wed, 14 Jan 2026 11:02:43 -0500 Subject: [PATCH 372/443] selftests/tc-testing: Try to add teql as a child qdisc Add a selftest that attempts to add a teql qdisc as a qfq child. Since teql _must_ be added as a root qdisc, the kernel should reject this. Signed-off-by: Victor Nogueira Link: https://patch.msgid.link/20260114160243.913069-4-jhs@mojatatu.com Signed-off-by: Jakub Kicinski --- .../tc-testing/tc-tests/qdiscs/teql.json | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/teql.json b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/teql.json index e5cc31f265f8..0179c57104ad 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/qdiscs/teql.json +++ b/tools/testing/selftests/tc-testing/tc-tests/qdiscs/teql.json @@ -81,5 +81,30 @@ "$TC qdisc del dev $DUMMY handle 1: root", "$IP link del dev $DUMMY" ] + }, + { + "id": "124e", + "name": "Try to add teql as a child qdisc", + "category": [ + "qdisc", + "ets", + "tbf" + ], + "plugins": { + "requires": [ + "nsPlugin" + ] + }, + "setup": [ + "$TC qdisc add dev $DUMMY root handle 1: qfq", + "$TC class add dev $DUMMY parent 1: classid 1:1 qfq weight 15 maxpkt 16384" + ], + "cmdUnderTest": "$TC qdisc add dev $DUMMY parent 1:1 handle 2:1 teql0", + "expExitCode": "2", + "verifyCmd": "$TC -s -j qdisc ls dev $DUMMY parent 1:1", + "matchJSON": [], + "teardown": [ + "$TC qdisc del dev $DUMMY root handle 1:" + ] } ] From 12a6ddfc76bb8a6d4508171d806c8632cf50a74a Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Wed, 24 Dec 2025 12:33:56 -0500 Subject: [PATCH 373/443] mm: add missing static initializer for init_mm::mm_cid.lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialize the mm_cid.lock struct member of init_mm. Link: https://lkml.kernel.org/r/20251224173358.647691-2-mathieu.desnoyers@efficios.com Fixes: 8cea569ca785 ("sched/mmcid: Use proper data structures") Signed-off-by: Mathieu Desnoyers Reviewed-by: Thomas Gleixner Cc: Aboorva Devarajan Cc: Al Viro Cc: Baolin Wang Cc: Christan König Cc: Christian Brauner Cc: Christoph Lameter Cc: David Hildenbrand Cc: David Rientjes Cc: Dennis Zhou Cc: Johannes Weiner Cc: "Liam R . Howlett" Cc: Lorenzo Stoakes Cc: Mark Brown Cc: Martin Liu Cc: Masami Hiramatsu Cc: Mateusz Guzik Cc: Matthew Wilcox Cc: Miaohe Lin Cc: Michal Hocko Cc: Mike Rapoport Cc: "Paul E. McKenney" Cc: Roman Gushchin Cc: SeongJae Park Cc: Shakeel Butt Cc: Steven Rostedt Cc: Suren Baghdasaryan Cc: Sweet Tea Dorminy Cc: Tejun Heo Cc: Vlastimil Babka Cc: Wei Yang Cc: Yu Zhao Cc: Peter Zijlstra (Intel) Cc: Signed-off-by: Andrew Morton --- mm/init-mm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/init-mm.c b/mm/init-mm.c index 4600e7605cab..a514f8ce47e3 100644 --- a/mm/init-mm.c +++ b/mm/init-mm.c @@ -44,6 +44,9 @@ struct mm_struct init_mm = { .mm_lock_seq = SEQCNT_ZERO(init_mm.mm_lock_seq), #endif .user_ns = &init_user_ns, +#ifdef CONFIG_SCHED_MM_CID + .mm_cid.lock = __RAW_SPIN_LOCK_UNLOCKED(init_mm.mm_cid.lock), +#endif .cpu_bitmap = CPU_BITS_NONE, INIT_MM_CONTEXT(init_mm) }; From 6ac433f8b2590b09ca00863d218665729ac985f7 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Wed, 24 Dec 2025 12:33:57 -0500 Subject: [PATCH 374/443] mm: rename cpu_bitmap field to flexible_array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cpu_bitmap flexible array now contains more than just the cpu_bitmap. In preparation for changing the static mm_struct definitions to cover for the additional space required, change the cpu_bitmap type from "unsigned long" to "char", require an unsigned long alignment of the flexible array, and rename the field from "cpu_bitmap" to "flexible_array". Introduce the MM_STRUCT_FLEXIBLE_ARRAY_INIT macro to statically initialize the flexible array. This covers the init_mm and efi_mm static definitions. This is a preparation step for fixing the missing mm_cid size for static mm_struct definitions. Link: https://lkml.kernel.org/r/20251224173358.647691-3-mathieu.desnoyers@efficios.com Fixes: af7f588d8f73 ("sched: Introduce per-memory-map concurrency ID") Signed-off-by: Mathieu Desnoyers Reviewed-by: Thomas Gleixner Cc: Mark Brown Cc: Aboorva Devarajan Cc: Al Viro Cc: Baolin Wang Cc: Christan König Cc: Christian Brauner Cc: Christoph Lameter Cc: David Hildenbrand Cc: David Rientjes Cc: Dennis Zhou Cc: Johannes Weiner Cc: "Liam R . Howlett" Cc: Lorenzo Stoakes Cc: Martin Liu Cc: Masami Hiramatsu Cc: Mateusz Guzik Cc: Matthew Wilcox Cc: Miaohe Lin Cc: Michal Hocko Cc: Mike Rapoport Cc: "Paul E. McKenney" Cc: Roman Gushchin Cc: SeongJae Park Cc: Shakeel Butt Cc: Steven Rostedt Cc: Suren Baghdasaryan Cc: Sweet Tea Dorminy Cc: Tejun Heo Cc: Vlastimil Babka Cc: Wei Yang Cc: Yu Zhao Cc: Peter Zijlstra (Intel) Cc: Signed-off-by: Andrew Morton --- drivers/firmware/efi/efi.c | 2 +- include/linux/mm_types.h | 13 +++++++++---- mm/init-mm.c | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index f5ff6e84a9b7..17b5f3415465 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -74,10 +74,10 @@ struct mm_struct efi_mm = { .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock), .mmlist = LIST_HEAD_INIT(efi_mm.mmlist), .user_ns = &init_user_ns, - .cpu_bitmap = { [BITS_TO_LONGS(NR_CPUS)] = 0}, #ifdef CONFIG_SCHED_MM_CID .mm_cid.lock = __RAW_SPIN_LOCK_UNLOCKED(efi_mm.mm_cid.lock), #endif + .flexible_array = MM_STRUCT_FLEXIBLE_ARRAY_INIT, }; struct workqueue_struct *efi_rts_wq; diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 42af2292951d..110b319a2ffb 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -1329,7 +1329,7 @@ struct mm_struct { * The mm_cpumask needs to be at the end of mm_struct, because it * is dynamically sized based on nr_cpu_ids. */ - unsigned long cpu_bitmap[]; + char flexible_array[] __aligned(__alignof__(unsigned long)); }; /* Copy value to the first system word of mm flags, non-atomically. */ @@ -1366,19 +1366,24 @@ static inline void __mm_flags_set_mask_bits_word(struct mm_struct *mm, MT_FLAGS_USE_RCU) extern struct mm_struct init_mm; +#define MM_STRUCT_FLEXIBLE_ARRAY_INIT \ +{ \ + [0 ... sizeof(cpumask_t)-1] = 0 \ +} + /* Pointer magic because the dynamic array size confuses some compilers. */ static inline void mm_init_cpumask(struct mm_struct *mm) { unsigned long cpu_bitmap = (unsigned long)mm; - cpu_bitmap += offsetof(struct mm_struct, cpu_bitmap); + cpu_bitmap += offsetof(struct mm_struct, flexible_array); cpumask_clear((struct cpumask *)cpu_bitmap); } /* Future-safe accessor for struct mm_struct's cpu_vm_mask. */ static inline cpumask_t *mm_cpumask(struct mm_struct *mm) { - return (struct cpumask *)&mm->cpu_bitmap; + return (struct cpumask *)&mm->flexible_array; } #ifdef CONFIG_LRU_GEN @@ -1469,7 +1474,7 @@ static inline cpumask_t *mm_cpus_allowed(struct mm_struct *mm) { unsigned long bitmap = (unsigned long)mm; - bitmap += offsetof(struct mm_struct, cpu_bitmap); + bitmap += offsetof(struct mm_struct, flexible_array); /* Skip cpu_bitmap */ bitmap += cpumask_size(); return (struct cpumask *)bitmap; diff --git a/mm/init-mm.c b/mm/init-mm.c index a514f8ce47e3..c5556bb9d5f0 100644 --- a/mm/init-mm.c +++ b/mm/init-mm.c @@ -47,7 +47,7 @@ struct mm_struct init_mm = { #ifdef CONFIG_SCHED_MM_CID .mm_cid.lock = __RAW_SPIN_LOCK_UNLOCKED(init_mm.mm_cid.lock), #endif - .cpu_bitmap = CPU_BITS_NONE, + .flexible_array = MM_STRUCT_FLEXIBLE_ARRAY_INIT, INIT_MM_CONTEXT(init_mm) }; From be31340a4cc259340044b7fc4f7e97f58c74ee8e Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Wed, 24 Dec 2025 12:33:58 -0500 Subject: [PATCH 375/443] mm: take into account mm_cid size for mm_struct static definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both init_mm and efi_mm static definitions need to make room for the 2 mm_cid cpumasks. This fixes possible out-of-bounds accesses to init_mm and efi_mm. Add a space between # and define for the mm_alloc_cid() definition to make it consistent with the coding style used in the rest of this header file. Link: https://lkml.kernel.org/r/20251224173358.647691-4-mathieu.desnoyers@efficios.com Fixes: af7f588d8f73 ("sched: Introduce per-memory-map concurrency ID") Signed-off-by: Mathieu Desnoyers Reviewed-by: Thomas Gleixner Cc: Mark Brown Cc: Aboorva Devarajan Cc: Al Viro Cc: Baolin Wang Cc: Christan König Cc: Christian Brauner Cc: Christoph Lameter Cc: David Hildenbrand Cc: David Rientjes Cc: Dennis Zhou Cc: Johannes Weiner Cc: "Liam R . Howlett" Cc: Lorenzo Stoakes Cc: Martin Liu Cc: Masami Hiramatsu Cc: Mateusz Guzik Cc: Matthew Wilcox Cc: Miaohe Lin Cc: Michal Hocko Cc: Mike Rapoport Cc: "Paul E. McKenney" Cc: Roman Gushchin Cc: SeongJae Park Cc: Shakeel Butt Cc: Steven Rostedt Cc: Suren Baghdasaryan Cc: Sweet Tea Dorminy Cc: Tejun Heo Cc: Vlastimil Babka Cc: Wei Yang Cc: Yu Zhao Cc: Peter Zijlstra (Intel) Cc: Signed-off-by: Andrew Morton --- include/linux/mm_types.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 110b319a2ffb..aa4639888f89 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -1368,7 +1368,7 @@ extern struct mm_struct init_mm; #define MM_STRUCT_FLEXIBLE_ARRAY_INIT \ { \ - [0 ... sizeof(cpumask_t)-1] = 0 \ + [0 ... sizeof(cpumask_t) + MM_CID_STATIC_SIZE - 1] = 0 \ } /* Pointer magic because the dynamic array size confuses some compilers. */ @@ -1500,7 +1500,7 @@ static inline int mm_alloc_cid_noprof(struct mm_struct *mm, struct task_struct * mm_init_cid(mm, p); return 0; } -#define mm_alloc_cid(...) alloc_hooks(mm_alloc_cid_noprof(__VA_ARGS__)) +# define mm_alloc_cid(...) alloc_hooks(mm_alloc_cid_noprof(__VA_ARGS__)) static inline void mm_destroy_cid(struct mm_struct *mm) { @@ -1514,6 +1514,8 @@ static inline unsigned int mm_cid_size(void) return cpumask_size() + bitmap_size(num_possible_cpus()); } +/* Use 2 * NR_CPUS as worse case for static allocation. */ +# define MM_CID_STATIC_SIZE (2 * sizeof(cpumask_t)) #else /* CONFIG_SCHED_MM_CID */ static inline void mm_init_cid(struct mm_struct *mm, struct task_struct *p) { } static inline int mm_alloc_cid(struct mm_struct *mm, struct task_struct *p) { return 0; } @@ -1522,6 +1524,7 @@ static inline unsigned int mm_cid_size(void) { return 0; } +# define MM_CID_STATIC_SIZE 0 #endif /* CONFIG_SCHED_MM_CID */ struct mmu_gather; From f9a49aa302a05e91ca01f69031cb79a0ea33031f Mon Sep 17 00:00:00 2001 From: Joanne Koong Date: Mon, 5 Jan 2026 13:17:27 -0800 Subject: [PATCH 376/443] fs/writeback: skip AS_NO_DATA_INTEGRITY mappings in wait_sb_inodes() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Above the while() loop in wait_sb_inodes(), we document that we must wait for all pages under writeback for data integrity. Consequently, if a mapping, like fuse, traditionally does not have data integrity semantics, there is no need to wait at all; we can simply skip these inodes. This restores fuse back to prior behavior where syncs are no-ops. This fixes a user regression where if a system is running a faulty fuse server that does not reply to issued write requests, this causes wait_sb_inodes() to wait forever. Link: https://lkml.kernel.org/r/20260105211737.4105620-2-joannelkoong@gmail.com Fixes: 0c58a97f919c ("fuse: remove tmp folio for writebacks and internal rb tree") Signed-off-by: Joanne Koong Reported-by: Athul Krishna Reported-by: J. Neuschäfer Reviewed-by: Bernd Schubert Tested-by: J. Neuschäfer Cc: Alexander Viro Cc: Bernd Schubert Cc: Bonaccorso Salvatore Cc: Christian Brauner Cc: David Hildenbrand Cc: Jan Kara Cc: "Liam R. Howlett" Cc: Lorenzo Stoakes Cc: "Matthew Wilcox (Oracle)" Cc: Michal Hocko Cc: Mike Rapoport Cc: Miklos Szeredi Cc: Suren Baghdasaryan Cc: Vlastimil Babka Cc: Signed-off-by: Andrew Morton --- fs/fs-writeback.c | 7 ++++++- fs/fuse/file.c | 4 +++- include/linux/pagemap.h | 11 +++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 6800886c4d10..baa2f2141146 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -2750,8 +2750,13 @@ static void wait_sb_inodes(struct super_block *sb) * The mapping can appear untagged while still on-list since we * do not have the mapping lock. Skip it here, wb completion * will remove it. + * + * If the mapping does not have data integrity semantics, + * there's no need to wait for the writeout to complete, as the + * mapping cannot guarantee that data is persistently stored. */ - if (!mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK)) + if (!mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK) || + mapping_no_data_integrity(mapping)) continue; spin_unlock_irq(&sb->s_inode_wblist_lock); diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 01bc894e9c2b..3b2a171e652f 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -3200,8 +3200,10 @@ void fuse_init_file_inode(struct inode *inode, unsigned int flags) inode->i_fop = &fuse_file_operations; inode->i_data.a_ops = &fuse_file_aops; - if (fc->writeback_cache) + if (fc->writeback_cache) { mapping_set_writeback_may_deadlock_on_reclaim(&inode->i_data); + mapping_set_no_data_integrity(&inode->i_data); + } INIT_LIST_HEAD(&fi->write_files); INIT_LIST_HEAD(&fi->queued_writes); diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 31a848485ad9..ec442af3f886 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -210,6 +210,7 @@ enum mapping_flags { AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9, AS_KERNEL_FILE = 10, /* mapping for a fake kernel file that shouldn't account usage to user cgroups */ + AS_NO_DATA_INTEGRITY = 11, /* no data integrity guarantees */ /* Bits 16-25 are used for FOLIO_ORDER */ AS_FOLIO_ORDER_BITS = 5, AS_FOLIO_ORDER_MIN = 16, @@ -345,6 +346,16 @@ static inline bool mapping_writeback_may_deadlock_on_reclaim(const struct addres return test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags); } +static inline void mapping_set_no_data_integrity(struct address_space *mapping) +{ + set_bit(AS_NO_DATA_INTEGRITY, &mapping->flags); +} + +static inline bool mapping_no_data_integrity(const struct address_space *mapping) +{ + return test_bit(AS_NO_DATA_INTEGRITY, &mapping->flags); +} + static inline gfp_t mapping_gfp_mask(const struct address_space *mapping) { return mapping->gfp_mask; From 90f3c123247e9564f2ecf861946ec41ceaf5e198 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Tue, 6 Jan 2026 18:33:21 +0200 Subject: [PATCH 377/443] panic: only warn about deprecated panic_print on write access The panic_print_deprecated() warning is being triggered on both read and write operations to the panic_print parameter. This causes spurious warnings when users run 'sysctl -a' to list all sysctl values, since that command reads /proc/sys/kernel/panic_print and triggers the deprecation notice. Modify the handlers to only emit the deprecation warning when the parameter is actually being set: - sysctl_panic_print_handler(): check 'write' flag before warning. - panic_print_get(): remove the deprecation call entirely. This way, users are only warned when they actively try to use the deprecated parameter, not when passively querying system state. Link: https://lkml.kernel.org/r/20260106163321.83586-1-gal@nvidia.com Fixes: ee13240cd78b ("panic: add note that panic_print sysctl interface is deprecated") Fixes: 2683df6539cb ("panic: add note that 'panic_print' parameter is deprecated") Signed-off-by: Gal Pressman Reviewed-by: Mark Bloch Reviewed-by: Nimrod Oren Cc: Feng Tang Cc: Joel Granados Cc: Petr Mladek Cc: Signed-off-by: Andrew Morton --- kernel/panic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/panic.c b/kernel/panic.c index 0d52210a9e2b..0c20fcaae98a 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -131,7 +131,8 @@ static int proc_taint(const struct ctl_table *table, int write, static int sysctl_panic_print_handler(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos) { - panic_print_deprecated(); + if (write) + panic_print_deprecated(); return proc_doulongvec_minmax(table, write, buffer, lenp, ppos); } @@ -1014,7 +1015,6 @@ static int panic_print_set(const char *val, const struct kernel_param *kp) static int panic_print_get(char *val, const struct kernel_param *kp) { - panic_print_deprecated(); return param_get_ulong(val, kp); } From b7880cb166ab62c2409046b2347261abf701530e Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Fri, 9 Jan 2026 04:13:42 +0000 Subject: [PATCH 378/443] migrate: correct lock ordering for hugetlb file folios Syzbot has found a deadlock (analyzed by Lance Yang): 1) Task (5749): Holds folio_lock, then tries to acquire i_mmap_rwsem(read lock). 2) Task (5754): Holds i_mmap_rwsem(write lock), then tries to acquire folio_lock. migrate_pages() -> migrate_hugetlbs() -> unmap_and_move_huge_page() <- Takes folio_lock! -> remove_migration_ptes() -> __rmap_walk_file() -> i_mmap_lock_read() <- Waits for i_mmap_rwsem(read lock)! hugetlbfs_fallocate() -> hugetlbfs_punch_hole() <- Takes i_mmap_rwsem(write lock)! -> hugetlbfs_zero_partial_page() -> filemap_lock_hugetlb_folio() -> filemap_lock_folio() -> __filemap_get_folio <- Waits for folio_lock! The migration path is the one taking locks in the wrong order according to the documentation at the top of mm/rmap.c. So expand the scope of the existing i_mmap_lock to cover the calls to remove_migration_ptes() too. This is (mostly) how it used to be after commit c0d0381ade79. That was removed by 336bf30eb765 for both file & anon hugetlb pages when it should only have been removed for anon hugetlb pages. Link: https://lkml.kernel.org/r/20260109041345.3863089-2-willy@infradead.org Signed-off-by: Matthew Wilcox (Oracle) Fixes: 336bf30eb765 ("hugetlbfs: fix anon huge page migration race") Reported-by: syzbot+2d9c96466c978346b55f@syzkaller.appspotmail.com Link: https://lore.kernel.org/all/68e9715a.050a0220.1186a4.000d.GAE@google.com Debugged-by: Lance Yang Acked-by: David Hildenbrand (Red Hat) Acked-by: Zi Yan Cc: Alistair Popple Cc: Byungchul Park Cc: Gregory Price Cc: Jann Horn Cc: Joshua Hahn Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Matthew Brost Cc: Rakie Kim Cc: Rik van Riel Cc: Vlastimil Babka Cc: Ying Huang Cc: Signed-off-by: Andrew Morton --- mm/migrate.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mm/migrate.c b/mm/migrate.c index 5169f9717f60..4688b9e38cd2 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -1458,6 +1458,7 @@ static int unmap_and_move_huge_page(new_folio_t get_new_folio, int page_was_mapped = 0; struct anon_vma *anon_vma = NULL; struct address_space *mapping = NULL; + enum ttu_flags ttu = 0; if (folio_ref_count(src) == 1) { /* page was freed from under us. So we are done. */ @@ -1498,8 +1499,6 @@ static int unmap_and_move_huge_page(new_folio_t get_new_folio, goto put_anon; if (folio_mapped(src)) { - enum ttu_flags ttu = 0; - if (!folio_test_anon(src)) { /* * In shared mappings, try_to_unmap could potentially @@ -1516,16 +1515,17 @@ static int unmap_and_move_huge_page(new_folio_t get_new_folio, try_to_migrate(src, ttu); page_was_mapped = 1; - - if (ttu & TTU_RMAP_LOCKED) - i_mmap_unlock_write(mapping); } if (!folio_mapped(src)) rc = move_to_new_folio(dst, src, mode); if (page_was_mapped) - remove_migration_ptes(src, !rc ? dst : src, 0); + remove_migration_ptes(src, !rc ? dst : src, + ttu ? RMP_LOCKED : 0); + + if (ttu & TTU_RMAP_LOCKED) + i_mmap_unlock_write(mapping); unlock_put_anon: folio_unlock(dst); From 605f6586ecf78395f0185ab24c368fb46a06e434 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Mon, 12 Jan 2026 15:51:43 +0000 Subject: [PATCH 379/443] mm/vma: do not leak memory when .mmap_prepare swaps the file The current implementation of mmap() is set up such that a struct file object is obtained for the input fd in ksys_mmap_pgoff() via fget(), and its reference count decremented at the end of the function via. fput(). If a merge can be achieved, we are fine to simply decrement the refcount on the file. Otherwise, in __mmap_new_file_vma(), we increment the reference count on the file via get_file() such that the fput() in ksys_mmap_pgoff() does not free the now-referenced file object. The introduction of the f_op->mmap_prepare hook changes things, as it becomes possible for a driver to replace the file object right at the beginning of the mmap operation. The current implementation is buggy if this happens because it unconditionally calls get_file() on the mapping's file whether or not it was replaced (and thus whether or not its reference count will be decremented at the end of ksys_mmap_pgoff()). This results in a memory leak, and was exposed in commit ab04945f91bc ("mm: update mem char driver to use mmap_prepare"). This patch solves the problem by explicitly tracking whether we actually need to call get_file() on the file or not, and only doing so if required. Link: https://lkml.kernel.org/r/20260112155143.661284-1-lorenzo.stoakes@oracle.com Signed-off-by: Lorenzo Stoakes Fixes: ab04945f91bc ("mm: update mem char driver to use mmap_prepare") Reported-by: syzbot+bf5de69ebb4bdf86f59f@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/6964a92b.050a0220.eaf7.008a.GAE@google.com/ Cc: Al Viro Cc: Christian Brauner Cc: Jan Kara Cc: Jann Horn Cc: Jason Gunthorpe Cc: Liam Howlett Cc: Pedro Falcato Cc: Vlastimil Babka Signed-off-by: Andrew Morton --- mm/vma.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mm/vma.c b/mm/vma.c index dc92f3dd8514..7a908a964d18 100644 --- a/mm/vma.c +++ b/mm/vma.c @@ -37,6 +37,8 @@ struct mmap_state { bool check_ksm_early :1; /* If we map new, hold the file rmap lock on mapping. */ bool hold_file_rmap_lock :1; + /* If .mmap_prepare changed the file, we don't need to pin. */ + bool file_doesnt_need_get :1; }; #define MMAP_STATE(name, mm_, vmi_, addr_, len_, pgoff_, vm_flags_, file_) \ @@ -2450,7 +2452,9 @@ static int __mmap_new_file_vma(struct mmap_state *map, struct vma_iterator *vmi = map->vmi; int error; - vma->vm_file = get_file(map->file); + vma->vm_file = map->file; + if (!map->file_doesnt_need_get) + get_file(map->file); if (!map->file->f_op->mmap) return 0; @@ -2638,7 +2642,10 @@ static int call_mmap_prepare(struct mmap_state *map, /* Update fields permitted to be changed. */ map->pgoff = desc->pgoff; - map->file = desc->vm_file; + if (desc->vm_file != map->file) { + map->file_doesnt_need_get = true; + map->file = desc->vm_file; + } map->vm_flags = desc->vm_flags; map->page_prot = desc->page_prot; /* User-defined fields. */ From b505f1944535f83d369ae68813e7634d11b990d3 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 6 Jan 2026 18:04:26 +0000 Subject: [PATCH 380/443] x86/kfence: avoid writing L1TF-vulnerable PTEs For native, the choice of PTE is fine. There's real memory backing the non-present PTE. However, for XenPV, Xen complains: (XEN) d1 L1TF-vulnerable L1e 8010000018200066 - Shadowing To explain, some background on XenPV pagetables: Xen PV guests are control their own pagetables; they choose the new PTE value, and use hypercalls to make changes so Xen can audit for safety. In addition to a regular reference count, Xen also maintains a type reference count. e.g. SegDesc (referenced by vGDT/vLDT), Writable (referenced with _PAGE_RW) or L{1..4} (referenced by vCR3 or a lower pagetable level). This is in order to prevent e.g. a page being inserted into the pagetables for which the guest has a writable mapping. For non-present mappings, all other bits become software accessible, and typically contain metadata rather a real frame address. There is nothing that a reference count could sensibly be tied to. As such, even if Xen could recognise the address as currently safe, nothing would prevent that frame from changing owner to another VM in the future. When Xen detects a PV guest writing a L1TF-PTE, it responds by activating shadow paging. This is normally only used for the live phase of migration, and comes with a reasonable overhead. KFENCE only cares about getting #PF to catch wild accesses; it doesn't care about the value for non-present mappings. Use a fully inverted PTE, to avoid hitting the slow path when running under Xen. While adjusting the logic, take the opportunity to skip all actions if the PTE is already in the right state, half the number PVOps callouts, and skip TLB maintenance on a !P -> P transition which benefits non-Xen cases too. Link: https://lkml.kernel.org/r/20260106180426.710013-1-andrew.cooper3@citrix.com Fixes: 1dc0da6e9ec0 ("x86, kfence: enable KFENCE for x86") Signed-off-by: Andrew Cooper Tested-by: Marco Elver Cc: Alexander Potapenko Cc: Marco Elver Cc: Dmitry Vyukov Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Borislav Petkov Cc: Dave Hansen Cc: "H. Peter Anvin" Cc: Jann Horn Cc: Signed-off-by: Andrew Morton --- arch/x86/include/asm/kfence.h | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/kfence.h b/arch/x86/include/asm/kfence.h index ff5c7134a37a..acf9ffa1a171 100644 --- a/arch/x86/include/asm/kfence.h +++ b/arch/x86/include/asm/kfence.h @@ -42,10 +42,34 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect) { unsigned int level; pte_t *pte = lookup_address(addr, &level); + pteval_t val; if (WARN_ON(!pte || level != PG_LEVEL_4K)) return false; + val = pte_val(*pte); + + /* + * protect requires making the page not-present. If the PTE is + * already in the right state, there's nothing to do. + */ + if (protect != !!(val & _PAGE_PRESENT)) + return true; + + /* + * Otherwise, invert the entire PTE. This avoids writing out an + * L1TF-vulnerable PTE (not present, without the high address bits + * set). + */ + set_pte(pte, __pte(~val)); + + /* + * If the page was protected (non-present) and we're making it + * present, there is no need to flush the TLB at all. + */ + if (!protect) + return true; + /* * We need to avoid IPIs, as we may get KFENCE allocations or faults * with interrupts disabled. Therefore, the below is best-effort, and @@ -53,11 +77,6 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect) * lazy fault handling takes care of faults after the page is PRESENT. */ - if (protect) - set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT)); - else - set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT)); - /* * Flush this CPU's TLB, assuming whoever did the allocation/free is * likely to continue running on this CPU. From 9c7e71c97c8cd086b148d0d3d1cd84a1deab023c Mon Sep 17 00:00:00 2001 From: Qiang Ma Date: Thu, 18 Dec 2025 16:16:18 +0800 Subject: [PATCH 381/443] btrfs: fix Wmaybe-uninitialized warning in replay_one_buffer() Warning was found when compiling using loongarch64-gcc 12.3.1: $ make CFLAGS_tree-log.o=-Wmaybe-uninitialized In file included from fs/btrfs/ctree.h:21, from fs/btrfs/tree-log.c:12: fs/btrfs/accessors.h: In function 'replay_one_buffer': fs/btrfs/accessors.h:66:16: warning: 'inode_item' may be used uninitialized [-Wmaybe-uninitialized] 66 | return btrfs_get_##bits(eb, s, offsetof(type, member)); \ | ^~~~~~~~~~ fs/btrfs/tree-log.c:2803:42: note: 'inode_item' declared here 2803 | struct btrfs_inode_item *inode_item; | ^~~~~~~~~~ Initialize the inode_item to NULL, the compiler does not seem to see the relation between the first 'wc->log_key.type == BTRFS_INODE_ITEM_KEY' check and the other one that also checks the replay phase. Signed-off-by: Qiang Ma Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/tree-log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 2d9d38b82daa..6cffcf0c3e7a 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2798,7 +2798,7 @@ static int replay_one_buffer(struct extent_buffer *eb, nritems = btrfs_header_nritems(eb); for (wc->log_slot = 0; wc->log_slot < nritems; wc->log_slot++) { - struct btrfs_inode_item *inode_item; + struct btrfs_inode_item *inode_item = NULL; btrfs_item_key_to_cpu(eb, &wc->log_key, wc->log_slot); From 0a155a8a24ddc647aaf28ce7cdb14af7270c158f Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Mon, 19 Jan 2026 21:54:58 +0100 Subject: [PATCH 382/443] MAINTAINERS: Add myself as reviewer for PWM rust drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I would like to help with reviewing the Rust part of the PWM drivers. While I maintain the Rust bindings, adding this separate entry ensures I am automatically CC-ed on the driver implementations (drivers/pwm/*.rs) Signed-off-by: Michal Wilczynski Link: https://patch.msgid.link/20260119-maintain_rust_drivers-v1-1-88711afc559e@samsung.com Signed-off-by: Uwe Kleine-König --- MAINTAINERS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5b11839cba9d..05ea9ab60e03 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21089,6 +21089,10 @@ S: Maintained F: rust/helpers/pwm.c F: rust/kernel/pwm.rs +PWM SUBSYSTEM DRIVERS [RUST] +R: Michal Wilczynski +F: drivers/pwm/*.rs + PXA GPIO DRIVER M: Robert Jarzmik L: linux-gpio@vger.kernel.org From 5dc6975566f5d142ec53eb7e97af688c45dd314d Mon Sep 17 00:00:00 2001 From: Lachlan Hodges Date: Tue, 20 Jan 2026 14:11:21 +1100 Subject: [PATCH 383/443] wifi: mac80211: don't perform DA check on S1G beacon S1G beacons don't contain the DA field as per IEEE80211-2024 9.3.4.3, so the DA broadcast check reads the SA address of the S1G beacon which will subsequently lead to the beacon being dropped. As a result, passive scanning is not possible. Fix this by only performing the check on non-S1G beacons to allow S1G long beacons to be processed during a passive scan. Fixes: ddf82e752f8a ("wifi: mac80211: Allow beacons to update BSS table regardless of scan") Signed-off-by: Lachlan Hodges Link: https://patch.msgid.link/20260120031122.309942-1-lachlan.hodges@morsemicro.com Signed-off-by: Johannes Berg --- net/mac80211/scan.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 5ef315ed3b0f..4823c8d45639 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -347,8 +347,13 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) mgmt->da)) return; } else { - /* Beacons are expected only with broadcast address */ - if (!is_broadcast_ether_addr(mgmt->da)) + /* + * Non-S1G beacons are expected only with broadcast address. + * S1G beacons only carry the SA so no DA check is required + * nor possible. + */ + if (!ieee80211_is_s1g_beacon(mgmt->frame_control) && + !is_broadcast_ether_addr(mgmt->da)) return; } From 3f3d8ff31496874a69b131866f62474eb24ed20a Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Sun, 18 Jan 2026 09:28:29 +0200 Subject: [PATCH 384/443] wifi: mac80211: don't increment crypto_tx_tailroom_needed_cnt twice In reconfig, in case the driver asks to disconnect during the reconfig, all the keys of the interface are marked as tainted. Then ieee80211_reenable_keys will loop over all the interface keys, and for each one it will a) increment crypto_tx_tailroom_needed_cnt b) call ieee80211_key_enable_hw_accel, which in turn will detect that this key is tainted, so it will mark it as "not in hardware", which is paired with crypto_tx_tailroom_needed_cnt incrementation, so we get two incrementations for each tainted key. Then we get a warning in ieee80211_free_keys. To fix it, don't increment the count in ieee80211_reenable_keys for tainted keys Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260118092821.4ca111fddcda.Id6e554f4b1c83760aa02d5a9e4e3080edb197aa2@changeid Signed-off-by: Johannes Berg --- net/mac80211/key.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/mac80211/key.c b/net/mac80211/key.c index d5da7ccea66e..04c8809173d7 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -987,7 +987,8 @@ void ieee80211_reenable_keys(struct ieee80211_sub_if_data *sdata) if (ieee80211_sdata_running(sdata)) { list_for_each_entry(key, &sdata->key_list, list) { - increment_tailroom_need_count(sdata); + if (!(key->flags & KEY_FLAG_TAINTED)) + increment_tailroom_need_count(sdata); ieee80211_key_enable_hw_accel(key); } } From 3fa2886d11d4545dc0dcfd0759ffbd03f88b5410 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Jan 2026 09:51:13 +0200 Subject: [PATCH 385/443] wifi: mac80211: parse all TTLM entries For the follow up patch, we need to properly parse TTLM entries that do not have a switch time. Change the logic so that ieee80211_parse_adv_t2l returns usable values in all non-error cases. Before the values filled in were technically incorrect but enough for ieee80211_process_adv_ttlm. Signed-off-by: Benjamin Berg Reviewed-by: Johannes Berg Reviewed-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260118093904.ccd324e2dd59.I69f0bee0a22e9b11bb95beef313e305dab17c051@changeid Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ad53dedd929c..3f6bbe4e0175 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -7015,10 +7015,6 @@ ieee80211_parse_adv_t2l(struct ieee80211_sub_if_data *sdata, pos = (void *)ttlm->optional; control = ttlm->control; - if ((control & IEEE80211_TTLM_CONTROL_DEF_LINK_MAP) || - !(control & IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT)) - return 0; - if ((control & IEEE80211_TTLM_CONTROL_DIRECTION) != IEEE80211_TTLM_DIRECTION_BOTH) { sdata_info(sdata, "Invalid advertised T2L map direction\n"); @@ -7028,21 +7024,28 @@ ieee80211_parse_adv_t2l(struct ieee80211_sub_if_data *sdata, link_map_presence = *pos; pos++; - ttlm_info->switch_time = get_unaligned_le16(pos); + if (control & IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT) { + ttlm_info->switch_time = get_unaligned_le16(pos); - /* Since ttlm_info->switch_time == 0 means no switch time, bump it - * by 1. - */ - if (!ttlm_info->switch_time) - ttlm_info->switch_time = 1; + /* Since ttlm_info->switch_time == 0 means no switch time, bump + * it by 1. + */ + if (!ttlm_info->switch_time) + ttlm_info->switch_time = 1; - pos += 2; + pos += 2; + } if (control & IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT) { ttlm_info->duration = pos[0] | pos[1] << 8 | pos[2] << 16; pos += 3; } + if (control & IEEE80211_TTLM_CONTROL_DEF_LINK_MAP) { + ttlm_info->map = 0xffff; + return 0; + } + if (control & IEEE80211_TTLM_CONTROL_LINK_MAP_SIZE) map_size = 1; else From aebc29dec67aa998a9ea6d34aacba7b5c6a74d33 Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Jan 2026 09:51:14 +0200 Subject: [PATCH 386/443] wifi: mac80211: apply advertised TTLM from association response When the AP has a disabled link that the station can include in the association, the fact that the link is dormant needs to be advertised in the TID to Link Mapping (TTLM). Section 35.3.7.2.3 ("Negotiation of TTLM") of Draft P802.11REVmf_D1.0 also states that the mapping needs to be included in the association response frame. As such, we can simply rely on the TTLM from the association response. Before this change mac80211 would not properly track that an advertised TTLM was effectively active, resulting in it not enabling the link once it became available again. For the link reconfiguration case, the data was not used at all. This behaviour is actually correct because Draft P802.11REVmf_D1.0 states in section 35.3.6.4 that we "shall operate with all the TIDs mapped to the newly added links ..." Fixes: 6d543b34dbcf ("wifi: mac80211: Support disabled links during association") Signed-off-by: Benjamin Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260118093904.43c861424543.I067f702ac46b84ac3f8b4ea16fb0db9cbbfae7e2@changeid Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 2 - net/mac80211/mlme.c | 216 ++++++++++++++++++++----------------- 2 files changed, 119 insertions(+), 99 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9d9313eee59f..bd573f8e61fb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -451,8 +451,6 @@ struct ieee80211_mgd_assoc_data { struct ieee80211_conn_settings conn; u16 status; - - bool disabled; } link[IEEE80211_MLD_MAX_NUM_LINKS]; u8 ap_addr[ETH_ALEN] __aligned(2); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3f6bbe4e0175..b72345c779c0 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -6161,6 +6161,98 @@ static bool ieee80211_get_dtim(const struct cfg80211_bss_ies *ies, return true; } +static u16 ieee80211_get_ttlm(u8 bm_size, u8 *data) +{ + if (bm_size == 1) + return *data; + + return get_unaligned_le16(data); +} + +static int +ieee80211_parse_adv_t2l(struct ieee80211_sub_if_data *sdata, + const struct ieee80211_ttlm_elem *ttlm, + struct ieee80211_adv_ttlm_info *ttlm_info) +{ + /* The element size was already validated in + * ieee80211_tid_to_link_map_size_ok() + */ + u8 control, link_map_presence, map_size, tid; + u8 *pos; + + memset(ttlm_info, 0, sizeof(*ttlm_info)); + pos = (void *)ttlm->optional; + control = ttlm->control; + + if ((control & IEEE80211_TTLM_CONTROL_DIRECTION) != + IEEE80211_TTLM_DIRECTION_BOTH) { + sdata_info(sdata, "Invalid advertised T2L map direction\n"); + return -EINVAL; + } + + link_map_presence = *pos; + pos++; + + if (control & IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT) { + ttlm_info->switch_time = get_unaligned_le16(pos); + + /* Since ttlm_info->switch_time == 0 means no switch time, bump + * it by 1. + */ + if (!ttlm_info->switch_time) + ttlm_info->switch_time = 1; + + pos += 2; + } + + if (control & IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT) { + ttlm_info->duration = pos[0] | pos[1] << 8 | pos[2] << 16; + pos += 3; + } + + if (control & IEEE80211_TTLM_CONTROL_DEF_LINK_MAP) { + ttlm_info->map = 0xffff; + return 0; + } + + if (control & IEEE80211_TTLM_CONTROL_LINK_MAP_SIZE) + map_size = 1; + else + map_size = 2; + + /* According to Draft P802.11be_D3.0 clause 35.3.7.1.7, an AP MLD shall + * not advertise a TID-to-link mapping that does not map all TIDs to the + * same link set, reject frame if not all links have mapping + */ + if (link_map_presence != 0xff) { + sdata_info(sdata, + "Invalid advertised T2L mapping presence indicator\n"); + return -EINVAL; + } + + ttlm_info->map = ieee80211_get_ttlm(map_size, pos); + if (!ttlm_info->map) { + sdata_info(sdata, + "Invalid advertised T2L map for TID 0\n"); + return -EINVAL; + } + + pos += map_size; + + for (tid = 1; tid < 8; tid++) { + u16 map = ieee80211_get_ttlm(map_size, pos); + + if (map != ttlm_info->map) { + sdata_info(sdata, "Invalid advertised T2L map for tid %d\n", + tid); + return -EINVAL; + } + + pos += map_size; + } + return 0; +} + static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, struct ieee802_11_elems *elems, @@ -6192,8 +6284,6 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, continue; valid_links |= BIT(link_id); - if (assoc_data->link[link_id].disabled) - dormant_links |= BIT(link_id); if (link_id != assoc_data->assoc_link_id) { err = ieee80211_sta_allocate_link(sta, link_id); @@ -6202,6 +6292,33 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, } } + /* + * We do not support setting a negotiated TTLM during + * association. As such, we can assume that if there is a TTLM, + * then it is the currently active advertised TTLM. + * In that case, there must be exactly one TTLM that does not + * have a switch time set. This mapping should also leave us + * with at least one usable link. + */ + if (elems->ttlm_num > 1) { + sdata_info(sdata, + "More than one advertised TTLM in association response\n"); + goto out_err; + } else if (elems->ttlm_num == 1) { + if (ieee80211_parse_adv_t2l(sdata, elems->ttlm[0], + &sdata->u.mgd.ttlm_info) || + sdata->u.mgd.ttlm_info.switch_time != 0 || + !(valid_links & sdata->u.mgd.ttlm_info.map)) { + sdata_info(sdata, + "Invalid advertised TTLM in association response\n"); + goto out_err; + } + + sdata->u.mgd.ttlm_info.active = true; + dormant_links = + valid_links & ~sdata->u.mgd.ttlm_info.map; + } + ieee80211_vif_set_links(sdata, valid_links, dormant_links); } @@ -6992,98 +7109,6 @@ static void ieee80211_tid_to_link_map_work(struct wiphy *wiphy, sdata->u.mgd.ttlm_info.switch_time = 0; } -static u16 ieee80211_get_ttlm(u8 bm_size, u8 *data) -{ - if (bm_size == 1) - return *data; - else - return get_unaligned_le16(data); -} - -static int -ieee80211_parse_adv_t2l(struct ieee80211_sub_if_data *sdata, - const struct ieee80211_ttlm_elem *ttlm, - struct ieee80211_adv_ttlm_info *ttlm_info) -{ - /* The element size was already validated in - * ieee80211_tid_to_link_map_size_ok() - */ - u8 control, link_map_presence, map_size, tid; - u8 *pos; - - memset(ttlm_info, 0, sizeof(*ttlm_info)); - pos = (void *)ttlm->optional; - control = ttlm->control; - - if ((control & IEEE80211_TTLM_CONTROL_DIRECTION) != - IEEE80211_TTLM_DIRECTION_BOTH) { - sdata_info(sdata, "Invalid advertised T2L map direction\n"); - return -EINVAL; - } - - link_map_presence = *pos; - pos++; - - if (control & IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT) { - ttlm_info->switch_time = get_unaligned_le16(pos); - - /* Since ttlm_info->switch_time == 0 means no switch time, bump - * it by 1. - */ - if (!ttlm_info->switch_time) - ttlm_info->switch_time = 1; - - pos += 2; - } - - if (control & IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT) { - ttlm_info->duration = pos[0] | pos[1] << 8 | pos[2] << 16; - pos += 3; - } - - if (control & IEEE80211_TTLM_CONTROL_DEF_LINK_MAP) { - ttlm_info->map = 0xffff; - return 0; - } - - if (control & IEEE80211_TTLM_CONTROL_LINK_MAP_SIZE) - map_size = 1; - else - map_size = 2; - - /* According to Draft P802.11be_D3.0 clause 35.3.7.1.7, an AP MLD shall - * not advertise a TID-to-link mapping that does not map all TIDs to the - * same link set, reject frame if not all links have mapping - */ - if (link_map_presence != 0xff) { - sdata_info(sdata, - "Invalid advertised T2L mapping presence indicator\n"); - return -EINVAL; - } - - ttlm_info->map = ieee80211_get_ttlm(map_size, pos); - if (!ttlm_info->map) { - sdata_info(sdata, - "Invalid advertised T2L map for TID 0\n"); - return -EINVAL; - } - - pos += map_size; - - for (tid = 1; tid < 8; tid++) { - u16 map = ieee80211_get_ttlm(map_size, pos); - - if (map != ttlm_info->map) { - sdata_info(sdata, "Invalid advertised T2L map for tid %d\n", - tid); - return -EINVAL; - } - - pos += map_size; - } - return 0; -} - static void ieee80211_process_adv_ttlm(struct ieee80211_sub_if_data *sdata, struct ieee802_11_elems *elems, u64 beacon_ts) @@ -9740,7 +9765,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, req, true, i, &assoc_data->link[i].conn); assoc_data->link[i].bss = link_cbss; - assoc_data->link[i].disabled = req->links[i].disabled; if (!bss->uapsd_supported) uapsd_supported = false; @@ -10722,8 +10746,6 @@ int ieee80211_mgd_assoc_ml_reconf(struct ieee80211_sub_if_data *sdata, &data->link[link_id].conn); data->link[link_id].bss = link_cbss; - data->link[link_id].disabled = - req->add_links[link_id].disabled; data->link[link_id].elems = (u8 *)req->add_links[link_id].elems; data->link[link_id].elems_len = From 50b359896fe55d0443ed550e1fabba71d242031a Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Sun, 18 Jan 2026 09:51:15 +0200 Subject: [PATCH 387/443] wifi: cfg80211: ignore link disabled flag from userspace When the AP has an advertised TID to Link Mapping (TTLM) it shall include the element in the association response. As such, when this element is present it needs to be used for the currently dormant links. See Draft P802.11REVmf_D1.0 section 35.3.7.2.3 ("Negotiation of TTLM") for the details. The flag is also not usable in case userspace wants to specify a negotiated TTLM during association. Note that for the link reconfiguration case, mac80211 did not use the information. Draft P802.11REVmf_D1.0 states in section 35.3.6.4 ("Link reconfiguration to the setup links) that we "shall operate with all the TIDs mapped to the newly added links ..." All this means that the flag is not needed. The implementation should parse the information from the association response. Signed-off-by: Benjamin Berg Reviewed-by: Johannes Berg Reviewed-by: Ilan Peer Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260118093904.754e057896a5.Ifd06f5ef839a93bfd54d0593dc932870f95f3242@changeid Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 3 --- include/uapi/linux/nl80211.h | 5 +++-- net/wireless/nl80211.c | 10 ---------- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 899f267b7cf9..2900202588a5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3221,8 +3221,6 @@ struct cfg80211_auth_request { * if this is %NULL for a link, that link is not requested * @elems: extra elements for the per-STA profile for this link * @elems_len: length of the elements - * @disabled: If set this link should be included during association etc. but it - * should not be used until enabled by the AP MLD. * @error: per-link error code, must be <= 0. If there is an error, then the * operation as a whole must fail. */ @@ -3230,7 +3228,6 @@ struct cfg80211_assoc_link { struct cfg80211_bss *bss; const u8 *elems; size_t elems_len; - bool disabled; int error; }; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 8134f10e4e6c..8433bac48112 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2880,8 +2880,9 @@ enum nl80211_commands { * index. If the userspace includes more RNR elements than number of * MBSSID elements then these will be added in every EMA beacon. * - * @NL80211_ATTR_MLO_LINK_DISABLED: Flag attribute indicating that the link is - * disabled. + * @NL80211_ATTR_MLO_LINK_DISABLED: Unused. It was used to indicate that a link + * is disabled during association. However, the AP will send the + * information by including a TTLM in the association response. * * @NL80211_ATTR_BSS_DUMP_INCLUDE_USE_DATA: Include BSS usage data, i.e. * include BSSes that can only be used in restricted scenarios and/or diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index c961cd42a832..03efd45c007f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -12241,9 +12241,6 @@ static int nl80211_process_links(struct cfg80211_registered_device *rdev, return -EINVAL; } } - - links[link_id].disabled = - nla_get_flag(attrs[NL80211_ATTR_MLO_LINK_DISABLED]); } return 0; @@ -12423,13 +12420,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) goto free; } - if (req.links[req.link_id].disabled) { - GENL_SET_ERR_MSG(info, - "cannot have assoc link disabled"); - err = -EINVAL; - goto free; - } - if (info->attrs[NL80211_ATTR_ASSOC_MLD_EXT_CAPA_OPS]) req.ext_mld_capa_ops = nla_get_u16(info->attrs[NL80211_ATTR_ASSOC_MLD_EXT_CAPA_OPS]); From 400928d01fb97fa86b4d82a6b65bfa82d7c19f6d Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Fri, 16 Jan 2026 11:29:56 +1030 Subject: [PATCH 388/443] MAINTAINERS: Add Andrew as M: to ARM/NUVOTON NPCM ARCHITECTURE Nuvoton's NPCM SoCs are part of their iBMC product line[1]. NPCM arch patches have historically gone through Joel's tree along with ASPEED changes due to their relevance to OpenBMC. Commit df5e674c7a99 ("MAINTAINERS: Switch ASPEED tree to shared BMC repository") does what it says on the tin - we now have bmc/linux.git on git.kernel.org, and I've picked up the maintainer role for it. Document that I'm continuing to apply NPCM arch patches from the openbmc@ list to the BMC tree for PRs to the SoC tree. Cc: Alexandre Belloni Cc: Arnd Bergmann Cc: Avi Fishman Cc: Drew Fustini Cc: Joel Stanley Cc: Krzysztof Kozlowski Cc: Linus Walleij Cc: Rob Herring Cc: Tali Perry Cc: Tomer Maimon Link: https://www.nuvoton.com/products/cloud-computing/ibmc/ [1] Signed-off-by: Andrew Jeffery Signed-off-by: Arnd Bergmann --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5dfbe58cb00f..18954f8d722d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3131,6 +3131,7 @@ F: drivers/*/*ma35* K: ma35d1 ARM/NUVOTON NPCM ARCHITECTURE +M: Andrew Jeffery M: Avi Fishman M: Tomer Maimon M: Tali Perry @@ -3139,6 +3140,7 @@ R: Nancy Yuen R: Benjamin Fair L: openbmc@lists.ozlabs.org (moderated for non-subscribers) S: Supported +T: git git://git.kernel.org/pub/scm/linux/kernel/git/bmc/linux.git F: Documentation/devicetree/bindings/*/*/*npcm* F: Documentation/devicetree/bindings/*/*npcm* F: Documentation/devicetree/bindings/rtc/nuvoton,nct3018y.yaml From 5d54aa40c7b7e9dee5746cca99e9ddbcca13e895 Mon Sep 17 00:00:00 2001 From: Michal Luczaj Date: Fri, 16 Jan 2026 09:52:36 +0100 Subject: [PATCH 389/443] vsock/test: Do not filter kallsyms by symbol type Blamed commit implemented logic to discover available vsock transports by grepping /proc/kallsyms for known symbols. It incorrectly filtered entries by type 'd'. For some kernel configs having CONFIG_VIRTIO_VSOCKETS=m CONFIG_VSOCKETS_LOOPBACK=y kallsyms reports 0000000000000000 d virtio_transport [vmw_vsock_virtio_transport] 0000000000000000 t loopback_transport Overzealous filtering might have affected vsock test suit, resulting in insufficient/misleading testing. Do not filter symbols by type. It never helped much. Fixes: 3070c05b7afd ("vsock/test: Introduce get_transports()") Signed-off-by: Michal Luczaj Reviewed-by: Stefano Garzarella Link: https://patch.msgid.link/20260116-vsock_test-kallsyms-grep-v1-1-3320bc3346f2@rbox.co Signed-off-by: Paolo Abeni --- tools/testing/vsock/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/vsock/util.h b/tools/testing/vsock/util.h index 142c02a6834a..bf633cde82b0 100644 --- a/tools/testing/vsock/util.h +++ b/tools/testing/vsock/util.h @@ -25,7 +25,7 @@ enum transport { }; static const char * const transport_ksyms[] = { - #define x(name, symbol) "d " symbol "_transport", + #define x(name, symbol) " " symbol "_transport", KNOWN_TRANSPORTS(x) #undef x }; From d1883cefd31752f0504b94c3bcfa1f6d511d6e87 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 11 Dec 2025 17:37:27 +0100 Subject: [PATCH 390/443] leds: led-class: Only Add LED to leds_list when it is fully ready Before this change the LED was added to leds_list before led_init_core() gets called adding it the list before led_classdev.set_brightness_work gets initialized. This leaves a window where led_trigger_register() of a LED's default trigger will call led_trigger_set() which calls led_set_brightness() which in turn will end up queueing the *uninitialized* led_classdev.set_brightness_work. This race gets hit by the lenovo-thinkpad-t14s EC driver which registers 2 LEDs with a default trigger provided by snd_ctl_led.ko in quick succession. The first led_classdev_register() causes an async modprobe of snd_ctl_led to run and that async modprobe manages to exactly hit the window where the second LED is on the leds_list without led_init_core() being called for it, resulting in: ------------[ cut here ]------------ WARNING: CPU: 11 PID: 5608 at kernel/workqueue.c:4234 __flush_work+0x344/0x390 Hardware name: LENOVO 21N2S01F0B/21N2S01F0B, BIOS N42ET93W (2.23 ) 09/01/2025 ... Call trace: __flush_work+0x344/0x390 (P) flush_work+0x2c/0x50 led_trigger_set+0x1c8/0x340 led_trigger_register+0x17c/0x1c0 led_trigger_register_simple+0x84/0xe8 snd_ctl_led_init+0x40/0xf88 [snd_ctl_led] do_one_initcall+0x5c/0x318 do_init_module+0x9c/0x2b8 load_module+0x7e0/0x998 Close the race window by moving the adding of the LED to leds_list to after the led_init_core() call. Cc: stable@vger.kernel.org Fixes: d23a22a74fde ("leds: delay led_set_brightness if stopping soft-blink") Signed-off-by: Hans de Goede Reviewed-by: Sebastian Reichel Link: https://patch.msgid.link/20251211163727.366441-1-johannes.goede@oss.qualcomm.com Signed-off-by: Lee Jones --- drivers/leds/led-class.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 885399ed0776..d34a19453560 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -560,11 +560,6 @@ int led_classdev_register_ext(struct device *parent, #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED led_cdev->brightness_hw_changed = -1; #endif - /* add to the list of leds */ - down_write(&leds_list_lock); - list_add_tail(&led_cdev->node, &leds_list); - up_write(&leds_list_lock); - if (!led_cdev->max_brightness) led_cdev->max_brightness = LED_FULL; @@ -574,6 +569,11 @@ int led_classdev_register_ext(struct device *parent, led_init_core(led_cdev); + /* add to the list of leds */ + down_write(&leds_list_lock); + list_add_tail(&led_cdev->node, &leds_list); + up_write(&leds_list_lock); + #ifdef CONFIG_LEDS_TRIGGERS led_trigger_set_default(led_cdev); #endif From 3f29d661e5686f3aa14e6f11537ff5c49846f2e2 Mon Sep 17 00:00:00 2001 From: Edward Adam Davis Date: Fri, 9 Jan 2026 21:02:02 +0800 Subject: [PATCH 391/443] btrfs: sync read disk super and set block size When the user performs a btrfs mount, the block device is not set correctly. The user sets the block size of the block device to 0x4000 by executing the BLKBSZSET command. Since the block size change also changes the mapping->flags value, this further affects the result of the mapping_min_folio_order() calculation. Let's analyze the following two scenarios: Scenario 1: Without executing the BLKBSZSET command, the block size is 0x1000, and mapping_min_folio_order() returns 0; Scenario 2: After executing the BLKBSZSET command, the block size is 0x4000, and mapping_min_folio_order() returns 2. do_read_cache_folio() allocates a folio before the BLKBSZSET command is executed. This results in the allocated folio having an order value of 0. Later, after BLKBSZSET is executed, the block size increases to 0x4000, and the mapping_min_folio_order() calculation result becomes 2. This leads to two undesirable consequences: 1. filemap_add_folio() triggers a VM_BUG_ON_FOLIO(folio_order(folio) < mapping_min_folio_order(mapping)) assertion. 2. The syzbot report [1] shows a null pointer dereference in create_empty_buffers() due to a buffer head allocation failure. Synchronization should be established based on the inode between the BLKBSZSET command and read cache page to prevent inconsistencies in block size or mapping flags before and after folio allocation. [1] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] RIP: 0010:create_empty_buffers+0x4d/0x480 fs/buffer.c:1694 Call Trace: folio_create_buffers+0x109/0x150 fs/buffer.c:1802 block_read_full_folio+0x14c/0x850 fs/buffer.c:2403 filemap_read_folio+0xc8/0x2a0 mm/filemap.c:2496 do_read_cache_folio+0x266/0x5c0 mm/filemap.c:4096 do_read_cache_page mm/filemap.c:4162 [inline] read_cache_page_gfp+0x29/0x120 mm/filemap.c:4195 btrfs_read_disk_super+0x192/0x500 fs/btrfs/volumes.c:1367 Reported-by: syzbot+b4a2af3000eaa84d95d5@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=b4a2af3000eaa84d95d5 Signed-off-by: Edward Adam Davis Reviewed-by: Filipe Manana Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/volumes.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index e35872149e2f..fe37ee05bf23 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1364,7 +1364,9 @@ struct btrfs_super_block *btrfs_read_disk_super(struct block_device *bdev, (bytenr + BTRFS_SUPER_INFO_SIZE) >> PAGE_SHIFT); } + filemap_invalidate_lock(mapping); page = read_cache_page_gfp(mapping, bytenr >> PAGE_SHIFT, GFP_NOFS); + filemap_invalidate_unlock(mapping); if (IS_ERR(page)) return ERR_CAST(page); From 1972f44c189c8aacde308fa9284e474c1a5cbd9f Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Wed, 14 Jan 2026 07:28:28 +1030 Subject: [PATCH 392/443] btrfs: reject new transactions if the fs is fully read-only [BUG] There is a bug report where a heavily fuzzed fs is mounted with all rescue mount options, which leads to the following warnings during unmount: BTRFS: Transaction aborted (error -22) Modules linked in: CPU: 0 UID: 0 PID: 9758 Comm: repro.out Not tainted 6.19.0-rc5-00002-gb71e635feefc #7 PREEMPT(full) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 RIP: 0010:find_free_extent_update_loop fs/btrfs/extent-tree.c:4208 [inline] RIP: 0010:find_free_extent+0x52f0/0x5d20 fs/btrfs/extent-tree.c:4611 Call Trace: btrfs_reserve_extent+0x2cd/0x790 fs/btrfs/extent-tree.c:4705 btrfs_alloc_tree_block+0x1e1/0x10e0 fs/btrfs/extent-tree.c:5157 btrfs_force_cow_block+0x578/0x2410 fs/btrfs/ctree.c:517 btrfs_cow_block+0x3c4/0xa80 fs/btrfs/ctree.c:708 btrfs_search_slot+0xcad/0x2b50 fs/btrfs/ctree.c:2130 btrfs_truncate_inode_items+0x45d/0x2350 fs/btrfs/inode-item.c:499 btrfs_evict_inode+0x923/0xe70 fs/btrfs/inode.c:5628 evict+0x5f4/0xae0 fs/inode.c:837 __dentry_kill+0x209/0x660 fs/dcache.c:670 finish_dput+0xc9/0x480 fs/dcache.c:879 shrink_dcache_for_umount+0xa0/0x170 fs/dcache.c:1661 generic_shutdown_super+0x67/0x2c0 fs/super.c:621 kill_anon_super+0x3b/0x70 fs/super.c:1289 btrfs_kill_super+0x41/0x50 fs/btrfs/super.c:2127 deactivate_locked_super+0xbc/0x130 fs/super.c:474 cleanup_mnt+0x425/0x4c0 fs/namespace.c:1318 task_work_run+0x1d4/0x260 kernel/task_work.c:233 exit_task_work include/linux/task_work.h:40 [inline] do_exit+0x694/0x22f0 kernel/exit.c:971 do_group_exit+0x21c/0x2d0 kernel/exit.c:1112 __do_sys_exit_group kernel/exit.c:1123 [inline] __se_sys_exit_group kernel/exit.c:1121 [inline] __x64_sys_exit_group+0x3f/0x40 kernel/exit.c:1121 x64_sys_call+0x2210/0x2210 arch/x86/include/generated/asm/syscalls_64.h:232 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xe8/0xf80 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x44f639 Code: Unable to access opcode bytes at 0x44f60f. RSP: 002b:00007ffc15c4e088 EFLAGS: 00000246 ORIG_RAX: 00000000000000e7 RAX: ffffffffffffffda RBX: 00000000004c32f0 RCX: 000000000044f639 RDX: 000000000000003c RSI: 00000000000000e7 RDI: 0000000000000001 RBP: 0000000000000001 R08: ffffffffffffffc0 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00000000004c32f0 R13: 0000000000000001 R14: 0000000000000000 R15: 0000000000000001 Since rescue mount options will mark the full fs read-only, there should be no new transaction triggered. But during unmount we will evict all inodes, which can trigger a new transaction, and triggers warnings on a heavily corrupted fs. [CAUSE] Btrfs allows new transaction even on a read-only fs, this is to allow log replay happen even on read-only mounts, just like what ext4/xfs do. However with rescue mount options, the fs is fully read-only and cannot be remounted read-write, thus in that case we should also reject any new transactions. [FIX] If we find the fs has rescue mount options, we should treat the fs as error, so that no new transaction can be started. Reported-by: Jiaming Zhang Link: https://lore.kernel.org/linux-btrfs/CANypQFYw8Nt8stgbhoycFojOoUmt+BoZ-z8WJOZVxcogDdwm=Q@mail.gmail.com/ Reviewed-by: Boris Burkov Reviewed-by: Johannes Thumshirn Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 13 +++++++++++++ fs/btrfs/fs.h | 8 ++++++++ 2 files changed, 21 insertions(+) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index d8ca5b6e88e0..fbd498aa9b99 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3255,6 +3255,15 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount) return 0; } +static bool fs_is_full_ro(const struct btrfs_fs_info *fs_info) +{ + if (!sb_rdonly(fs_info->sb)) + return false; + if (unlikely(fs_info->mount_opt & BTRFS_MOUNT_FULL_RO_MASK)) + return true; + return false; +} + int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_devices) { u32 sectorsize; @@ -3363,6 +3372,10 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_ERROR) WRITE_ONCE(fs_info->fs_error, -EUCLEAN); + /* If the fs has any rescue options, no transaction is allowed. */ + if (fs_is_full_ro(fs_info)) + WRITE_ONCE(fs_info->fs_error, -EROFS); + /* Set up fs_info before parsing mount options */ nodesize = btrfs_super_nodesize(disk_super); sectorsize = btrfs_super_sectorsize(disk_super); diff --git a/fs/btrfs/fs.h b/fs/btrfs/fs.h index 0f7e1ef27891..8ffbc40ebe45 100644 --- a/fs/btrfs/fs.h +++ b/fs/btrfs/fs.h @@ -264,6 +264,14 @@ enum { BTRFS_MOUNT_REF_TRACKER = (1ULL << 33), }; +/* These mount options require a full read-only fs, no new transaction is allowed. */ +#define BTRFS_MOUNT_FULL_RO_MASK \ + (BTRFS_MOUNT_NOLOGREPLAY | \ + BTRFS_MOUNT_IGNOREBADROOTS | \ + BTRFS_MOUNT_IGNOREDATACSUMS | \ + BTRFS_MOUNT_IGNOREMETACSUMS | \ + BTRFS_MOUNT_IGNORESUPERFLAGS) + /* * Compat flags that we support. If any incompat flags are set other than the * ones specified below then we will fail to mount From 1d8f69f453c2e8a2d99b158e58e02ed65031fa6d Mon Sep 17 00:00:00 2001 From: Mark Harmstone Date: Tue, 13 Jan 2026 18:37:56 +0000 Subject: [PATCH 393/443] btrfs: fix missing fields in superblock backup with BLOCK_GROUP_TREE When the BLOCK_GROUP_TREE compat_ro flag is set, the extent root and csum root fields are getting missed. This is because EXTENT_TREE_V2 treated these differently, and when they were split off this special-casing was mistakenly assigned to BGT rather than the rump EXTENT_TREE_V2. There's no reason why the existence of the block group tree should mean that we don't record the details of the last commit's extent root and csum root. Fix the code in backup_super_roots() so that the correct check gets made. Fixes: 1c56ab991903 ("btrfs: separate BLOCK_GROUP_TREE compat RO flag from EXTENT_TREE_V2") Reviewed-by: Qu Wenruo Signed-off-by: Mark Harmstone Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index fbd498aa9b99..22d706e4f341 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1661,7 +1661,7 @@ static void backup_super_roots(struct btrfs_fs_info *info) btrfs_set_backup_chunk_root_level(root_backup, btrfs_header_level(info->chunk_root->node)); - if (!btrfs_fs_compat_ro(info, BLOCK_GROUP_TREE)) { + if (!btrfs_fs_incompat(info, EXTENT_TREE_V2)) { struct btrfs_root *extent_root = btrfs_extent_root(info, 0); struct btrfs_root *csum_root = btrfs_csum_root(info, 0); From 34308187395ff01f2d54007eb8b222f843bdf445 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Mon, 12 Jan 2026 08:32:09 +1030 Subject: [PATCH 394/443] btrfs: add extra device item checks at mount [BUG] There is a bug report where after a dev-replace, the replace source device with devid 4 is properly erased (dump tree shows it's the old devid 4), but the target device is still using devid 0. When the user tries to mount the fs degraded, the mount failed with the following errors: BTRFS: device fsid 84a1ed4a-365c-45c3-a9ee-a7df525dc3c9 devid 5 transid 1394395 /dev/sda (8:0) scanned by btrfs (261) BTRFS: device fsid 84a1ed4a-365c-45c3-a9ee-a7df525dc3c9 devid 6 transid 1394395 /dev/sde (8:64) scanned by btrfs (261) BTRFS: device fsid 84a1ed4a-365c-45c3-a9ee-a7df525dc3c9 devid 0 transid 1394395 /dev/sdd (8:48) scanned by btrfs (261) BTRFS: device fsid 84a1ed4a-365c-45c3-a9ee-a7df525dc3c9 devid 3 transid 1394395 /dev/sdf (8:80) scanned by btrfs (261) BTRFS info (device sdd): first mount of filesystem 84a1ed4a-365c-45c3-a9ee-a7df525dc3c9 BTRFS info (device sdd): using crc32c (crc32c-intel) checksum algorithm BTRFS warning (device sdd): devid 4 uuid 01e2081c-9c2a-4071-b9f4-e1b27e571ff5 is missing BTRFS info (device sdd): bdev errs: wr 84994544, rd 15567, flush 65872, corrupt 0, gen 0 BTRFS info (device sdd): bdev /dev/sdd errs: wr 71489901, rd 0, flush 30001, corrupt 0, gen 0 BTRFS error (device sdd): replace without active item, run 'device scan --forget' on the target device BTRFS error (device sdd): failed to init dev_replace: -117 BTRFS error (device sdd): open_ctree failed: -117 [CAUSE] The devid 0 didn't get its devid updated is its own problem, here I'm only focusing on the mount failure itself. The mount is not caused by the missing device, as the fs has RAID1C3 for metadata and RAID10 for data, thus is completely able to tolerate one missing device. The device tree shows the dev-replace has properly finished: item 7 key (0 DEV_REPLACE 0) itemoff 15931 itemsize 72 src devid -1 cursor left 11091821199360 cursor right 11091821199360 mode ALWAYS state FINISHED write errors 0 uncorrectable read errors 0 ^^^^^^^^ And the chunk tree shows there is no devid 0: leaf 37980736602112 items 23 free space 12548 generation 1394388 owner CHUNK_TREE leaf 37980736602112 flags 0x1(WRITTEN) backref revision 1 fs uuid 84a1ed4a-365c-45c3-a9ee-a7df525dc3c9 chunk uuid d074c661-6311-4570-b59f-a5c83fd37f8e item 0 key (DEV_ITEMS DEV_ITEM 3) itemoff 16185 itemsize 98 devid 3 total_bytes 20000588955648 bytes_used 8282877984768 io_align 4096 io_width 4096 sector_size 4096 type 0 generation 0 start_offset 0 dev_group 0 seek_speed 0 bandwidth 0 uuid 0d596b69-fb0d-4031-b4af-a301d0868b8b fsid 84a1ed4a-365c-45c3-a9ee-a7df525dc3c9 ... Which shows the first device is devid 3. But there is indeed /dev/sdd with devid 0: superblock: bytenr=65536, device=/dev/sdd --------------------------------------------------------- csum_type 0 (crc32c) csum_size 4 csum 0xd4bed87e [match] bytenr 65536 flags 0x1 ( WRITTEN ) magic _BHRfS_M [match] fsid 84a1ed4a-365c-45c3-a9ee-a7df525dc3c9 ... uuid_tree_generation 1394388 dev_item.uuid ee6532ad-5442-45f7-87fb-7703e29ed934 dev_item.fsid 84a1ed4a-365c-45c3-a9ee-a7df525dc3c9 [match] dev_item.type 0 dev_item.total_bytes 20000588955648 dev_item.bytes_used 8292541661184 dev_item.io_align 0 dev_item.io_width 0 dev_item.sector_size 0 dev_item.devid 0 <<< So this means device scan will register sdd as devid 0 into the fs, then during btrfs_init_dev_replace(), we located the replace progress item, found the previous replace is finished, but we still need to check if the dev-replace target device (devid 0) exists. If that device exists, we error out showing that error message. But to be honest the end user may not really remember which device is the replace target device, thus not sure what to do in the next step. [ENHANCEMENT] To make the error more obvious, and tell the end user which devices should be unregistered: - Introduce BTRFS_DEV_STATE_ITEM_FOUND flag During device item read from the chunk tree, set the flag for each found device item. - Verify there is no device without the above flag during mount Even missing device should have that flag set. If we found a device without that flag set, it means it's an unexpected one and should be rejected. - More detailed error message on what to do next This will show all unexpected devices and tell the end user to use 'btrfs dev scan --forget' to forget them or remove them before mount. There is an example dmesg where a device of a valid filesystem is modified to have devid 0, then try degraded mount: BTRFS info (device dm-6): first mount of filesystem 7c873869-844c-4b39-bd75-a96148bf4656 BTRFS info (device dm-6): using crc32c checksum algorithm BTRFS warning (device dm-6): devid 3 uuid b4a9f35b-db42-4ac4-b55a-cbf81d3b9683 is missing BTRFS error (device dm-6): devid 0 path /dev/mapper/test-scratch3 is registered but not found in chunk tree BTRFS error (device dm-6): please remove above devices or use 'btrfs device scan --forget ' to unregister them before mount BTRFS error (device dm-6): open_ctree failed: -117 Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba --- fs/btrfs/disk-io.c | 4 ++++ fs/btrfs/volumes.c | 40 ++++++++++++++++++++++++++++++++++++++++ fs/btrfs/volumes.h | 4 ++++ 3 files changed, 48 insertions(+) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 22d706e4f341..89022e9f393b 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3502,6 +3502,10 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device fs_info->generation == btrfs_super_uuid_tree_generation(disk_super)) set_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags); + if (unlikely(btrfs_verify_dev_items(fs_info))) { + ret = -EUCLEAN; + goto fail_block_groups; + } ret = btrfs_verify_dev_extents(fs_info); if (ret) { btrfs_err(fs_info, diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index fe37ee05bf23..324852318afc 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -7262,6 +7262,7 @@ static int read_one_dev(struct extent_buffer *leaf, return -EINVAL; } } + set_bit(BTRFS_DEV_STATE_ITEM_FOUND, &device->dev_state); set_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state); if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state) && !test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state)) { @@ -8087,6 +8088,45 @@ int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info) return verify_chunk_dev_extent_mapping(fs_info); } +/* + * Ensure that all devices registered in the fs have their device items in the + * chunk tree. + * + * Return true if unexpected device is found. + * Return false otherwise. + */ +bool btrfs_verify_dev_items(const struct btrfs_fs_info *fs_info) +{ + struct btrfs_fs_devices *seed_devs; + struct btrfs_device *dev; + bool ret = false; + + mutex_lock(&uuid_mutex); + list_for_each_entry(dev, &fs_info->fs_devices->devices, dev_list) { + if (!test_bit(BTRFS_DEV_STATE_ITEM_FOUND, &dev->dev_state)) { + btrfs_err(fs_info, + "devid %llu path %s is registered but not found in chunk tree", + dev->devid, btrfs_dev_name(dev)); + ret = true; + } + } + list_for_each_entry(seed_devs, &fs_info->fs_devices->seed_list, seed_list) { + list_for_each_entry(dev, &seed_devs->devices, dev_list) { + if (!test_bit(BTRFS_DEV_STATE_ITEM_FOUND, &dev->dev_state)) { + btrfs_err(fs_info, + "devid %llu path %s is registered but not found in chunk tree", + dev->devid, btrfs_dev_name(dev)); + ret = true; + } + } + } + mutex_unlock(&uuid_mutex); + if (ret) + btrfs_err(fs_info, +"remove the above devices or use 'btrfs device scan --forget ' to unregister them before mount"); + return ret; +} + /* * Check whether the given block group or device is pinned by any inode being * used as a swapfile. diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 34b854c1a303..f20abeb16bce 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -100,6 +100,9 @@ enum btrfs_raid_types { #define BTRFS_DEV_STATE_FLUSH_SENT (4) #define BTRFS_DEV_STATE_NO_READA (5) +/* Set when the device item is found in chunk tree, used to catch unexpected registered device. */ +#define BTRFS_DEV_STATE_ITEM_FOUND (7) + /* Special value encoding failure to write primary super block. */ #define BTRFS_SUPER_PRIMARY_WRITE_ERROR (INT_MAX / 2) @@ -893,6 +896,7 @@ enum btrfs_raid_types __attribute_const__ btrfs_bg_flags_to_raid_index(u64 flags int btrfs_bg_type_to_factor(u64 flags); const char *btrfs_bg_type_to_raid_name(u64 flags); int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info); +bool btrfs_verify_dev_items(const struct btrfs_fs_info *fs_info); bool btrfs_repair_one_zone(struct btrfs_fs_info *fs_info, u64 logical); bool btrfs_pinned_by_swapfile(struct btrfs_fs_info *fs_info, void *ptr); From b97d5eedf4976cc94321243be83b39efe81a0e15 Mon Sep 17 00:00:00 2001 From: Yun Lu Date: Fri, 16 Jan 2026 17:53:08 +0800 Subject: [PATCH 395/443] netdevsim: fix a race issue related to the operation on bpf_bound_progs list The netdevsim driver lacks a protection mechanism for operations on the bpf_bound_progs list. When the nsim_bpf_create_prog() performs list_add_tail, it is possible that nsim_bpf_destroy_prog() is simultaneously performs list_del. Concurrent operations on the list may lead to list corruption and trigger a kernel crash as follows: [ 417.290971] kernel BUG at lib/list_debug.c:62! [ 417.290983] invalid opcode: 0000 [#1] PREEMPT SMP NOPTI [ 417.290992] CPU: 10 PID: 168 Comm: kworker/10:1 Kdump: loaded Not tainted 6.19.0-rc5 #1 [ 417.291003] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 417.291007] Workqueue: events bpf_prog_free_deferred [ 417.291021] RIP: 0010:__list_del_entry_valid_or_report+0xa7/0xc0 [ 417.291034] Code: a8 ff 0f 0b 48 89 fe 48 89 ca 48 c7 c7 48 a1 eb ae e8 ed fb a8 ff 0f 0b 48 89 fe 48 89 c2 48 c7 c7 80 a1 eb ae e8 d9 fb a8 ff <0f> 0b 48 89 d1 48 c7 c7 d0 a1 eb ae 48 89 f2 48 89 c6 e8 c2 fb a8 [ 417.291040] RSP: 0018:ffffb16a40807df8 EFLAGS: 00010246 [ 417.291046] RAX: 000000000000006d RBX: ffff8e589866f500 RCX: 0000000000000000 [ 417.291051] RDX: 0000000000000000 RSI: ffff8e59f7b23180 RDI: ffff8e59f7b23180 [ 417.291055] RBP: ffffb16a412c9000 R08: 0000000000000000 R09: 0000000000000003 [ 417.291059] R10: ffffb16a40807c80 R11: ffffffffaf9edce8 R12: ffff8e594427ac20 [ 417.291063] R13: ffff8e59f7b44780 R14: ffff8e58800b7a05 R15: 0000000000000000 [ 417.291074] FS: 0000000000000000(0000) GS:ffff8e59f7b00000(0000) knlGS:0000000000000000 [ 417.291079] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 417.291083] CR2: 00007fc4083efe08 CR3: 00000001c3626006 CR4: 0000000000770ee0 [ 417.291088] PKRU: 55555554 [ 417.291091] Call Trace: [ 417.291096] [ 417.291103] nsim_bpf_destroy_prog+0x31/0x80 [netdevsim] [ 417.291154] __bpf_prog_offload_destroy+0x2a/0x80 [ 417.291163] bpf_prog_dev_bound_destroy+0x6f/0xb0 [ 417.291171] bpf_prog_free_deferred+0x18e/0x1a0 [ 417.291178] process_one_work+0x18a/0x3a0 [ 417.291188] worker_thread+0x27b/0x3a0 [ 417.291197] ? __pfx_worker_thread+0x10/0x10 [ 417.291207] kthread+0xe5/0x120 [ 417.291214] ? __pfx_kthread+0x10/0x10 [ 417.291221] ret_from_fork+0x31/0x50 [ 417.291230] ? __pfx_kthread+0x10/0x10 [ 417.291236] ret_from_fork_asm+0x1a/0x30 [ 417.291246] Add a mutex lock, to prevent simultaneous addition and deletion operations on the list. Fixes: 31d3ad832948 ("netdevsim: add bpf offload support") Reported-by: Yinhao Hu Reported-by: Kaiyan Mei Signed-off-by: Yun Lu Link: https://patch.msgid.link/20260116095308.11441-1-luyun_611@163.com Signed-off-by: Paolo Abeni --- drivers/net/netdevsim/bpf.c | 6 ++++++ drivers/net/netdevsim/dev.c | 2 ++ drivers/net/netdevsim/netdevsim.h | 1 + 3 files changed, 9 insertions(+) diff --git a/drivers/net/netdevsim/bpf.c b/drivers/net/netdevsim/bpf.c index 49537d3c4120..5f17f68f3c08 100644 --- a/drivers/net/netdevsim/bpf.c +++ b/drivers/net/netdevsim/bpf.c @@ -244,7 +244,9 @@ static int nsim_bpf_create_prog(struct nsim_dev *nsim_dev, &state->state, &nsim_bpf_string_fops); debugfs_create_bool("loaded", 0400, state->ddir, &state->is_loaded); + mutex_lock(&nsim_dev->progs_list_lock); list_add_tail(&state->l, &nsim_dev->bpf_bound_progs); + mutex_unlock(&nsim_dev->progs_list_lock); prog->aux->offload->dev_priv = state; @@ -273,12 +275,16 @@ static int nsim_bpf_translate(struct bpf_prog *prog) static void nsim_bpf_destroy_prog(struct bpf_prog *prog) { struct nsim_bpf_bound_prog *state; + struct nsim_dev *nsim_dev; state = prog->aux->offload->dev_priv; + nsim_dev = state->nsim_dev; WARN(state->is_loaded, "offload state destroyed while program still bound"); debugfs_remove_recursive(state->ddir); + mutex_lock(&nsim_dev->progs_list_lock); list_del(&state->l); + mutex_unlock(&nsim_dev->progs_list_lock); kfree(state); } diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index 2683a989873e..dfd571b22107 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -1647,6 +1647,7 @@ int nsim_drv_probe(struct nsim_bus_dev *nsim_bus_dev) nsim_dev->test1 = NSIM_DEV_TEST1_DEFAULT; nsim_dev->test2 = NSIM_DEV_TEST2_DEFAULT; spin_lock_init(&nsim_dev->fa_cookie_lock); + mutex_init(&nsim_dev->progs_list_lock); dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev); @@ -1785,6 +1786,7 @@ void nsim_drv_remove(struct nsim_bus_dev *nsim_bus_dev) devl_unregister(devlink); kfree(nsim_dev->vfconfigs); kfree(nsim_dev->fa_cookie); + mutex_destroy(&nsim_dev->progs_list_lock); devl_unlock(devlink); devlink_free(devlink); dev_set_drvdata(&nsim_bus_dev->dev, NULL); diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index d1a941e2b18f..46c67983c517 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -324,6 +324,7 @@ struct nsim_dev { u32 prog_id_gen; struct list_head bpf_bound_progs; struct list_head bpf_bound_maps; + struct mutex progs_list_lock; struct netdev_phys_item_id switch_id; struct list_head port_list; bool fw_update_status; From 90888b4ae103e65e5dfd438adb8d7d7ece91afd2 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Wed, 14 Jan 2026 11:56:19 +0000 Subject: [PATCH 396/443] mm: remove unnecessary and incorrect mmap lock assert This check was introduced by commit 42fc541404f2 ("mmap locking API: add mmap_assert_locked() and mmap_assert_write_locked()") which replaced a VM_BUG_ON_VMA() over rwsem_is_locked from commit a00cc7d9dd93 ("mm, x86: add support for PUD-sized transparent hugepages"), i.e. the commit that introduced PUD THPs. These seem to be careful asserts introduced to ensure that locks are held in general, however for a zap we require that VMAs are kept stable, and this is a requirement that has held perfectly well for a long time. These were long before VMA locks and thus there appears to be no reason to think this is assert is there for anything other than 'stabilised VMA'. Asserting that the VMA under examination is stable only in the case of a THP PUD is strange and unnecessary. If we wish to be careful and assert such things, we should do so at the zap level. However in any case the current situation is already simply incorrect - a VMA lock suffices here. Remove the assert for now as it is unnecessarily, incorrect and unhelpful, subsequent work can introduce an assert in general for zapping if required. Link: https://lkml.kernel.org/r/20260114115619.1087466-1-lorenzo.stoakes@oracle.com Fixes: 2ab7f1bbafc9 ("mm/madvise: allow guard page install/remove under VMA lock") Signed-off-by: Lorenzo Stoakes Reported-by: Chris Mason Closes: https://lore.kernel.org/all/20260113220856.2358195-1-clm@meta.com/ Acked-by: David Hildenbrand (Red Hat) Cc: Liam Howlett Cc: Michal Hocko Cc: Mike Rapoport Cc: SeongJae Park Cc: Suren Baghdasaryan Cc: Vlastimil Babka Signed-off-by: Andrew Morton --- mm/memory.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index 2a55edc48a65..a0822b564cc0 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1963,10 +1963,9 @@ static inline unsigned long zap_pud_range(struct mmu_gather *tlb, do { next = pud_addr_end(addr, end); if (pud_trans_huge(*pud)) { - if (next - addr != HPAGE_PUD_SIZE) { - mmap_assert_locked(tlb->mm); + if (next - addr != HPAGE_PUD_SIZE) split_huge_pud(vma, pud, addr); - } else if (zap_huge_pud(tlb, vma, pud, addr)) + else if (zap_huge_pud(tlb, vma, pud, addr)) goto next; /* fall through */ } From ca1a47cd3f5f4c46ca188b1c9a27af87d1ab2216 Mon Sep 17 00:00:00 2001 From: "David Hildenbrand (Red Hat)" Date: Tue, 23 Dec 2025 22:40:34 +0100 Subject: [PATCH 397/443] mm/hugetlb: fix hugetlb_pmd_shared() Patch series "mm/hugetlb: fixes for PMD table sharing (incl. using mmu_gather)", v3. One functional fix, one performance regression fix, and two related comment fixes. I cleaned up my prototype I recently shared [1] for the performance fix, deferring most of the cleanups I had in the prototype to a later point. While doing that I identified the other things. The goal of this patch set is to be backported to stable trees "fairly" easily. At least patch #1 and #4. Patch #1 fixes hugetlb_pmd_shared() not detecting any sharing Patch #2 + #3 are simple comment fixes that patch #4 interacts with. Patch #4 is a fix for the reported performance regression due to excessive IPI broadcasts during fork()+exit(). The last patch is all about TLB flushes, IPIs and mmu_gather. Read: complicated There are plenty of cleanups in the future to be had + one reasonable optimization on x86. But that's all out of scope for this series. Runtime tested, with a focus on fixing the performance regression using the original reproducer [2] on x86. This patch (of 4): We switched from (wrongly) using the page count to an independent shared count. Now, shared page tables have a refcount of 1 (excluding speculative references) and instead use ptdesc->pt_share_count to identify sharing. We didn't convert hugetlb_pmd_shared(), so right now, we would never detect a shared PMD table as such, because sharing/unsharing no longer touches the refcount of a PMD table. Page migration, like mbind() or migrate_pages() would allow for migrating folios mapped into such shared PMD tables, even though the folios are not exclusive. In smaps we would account them as "private" although they are "shared", and we would be wrongly setting the PM_MMAP_EXCLUSIVE in the pagemap interface. Fix it by properly using ptdesc_pmd_is_shared() in hugetlb_pmd_shared(). Link: https://lkml.kernel.org/r/20251223214037.580860-1-david@kernel.org Link: https://lkml.kernel.org/r/20251223214037.580860-2-david@kernel.org Link: https://lore.kernel.org/all/8cab934d-4a56-44aa-b641-bfd7e23bd673@kernel.org/ [1] Link: https://lore.kernel.org/all/8cab934d-4a56-44aa-b641-bfd7e23bd673@kernel.org/ [2] Fixes: 59d9094df3d7 ("mm: hugetlb: independent PMD page table shared count") Signed-off-by: David Hildenbrand (Red Hat) Reviewed-by: Rik van Riel Reviewed-by: Lance Yang Tested-by: Lance Yang Reviewed-by: Harry Yoo Tested-by: Laurence Oberman Reviewed-by: Lorenzo Stoakes Acked-by: Oscar Salvador Cc: Liu Shixin Cc: Uschakow, Stanislav" Cc: Signed-off-by: Andrew Morton --- include/linux/hugetlb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 019a1c5281e4..03c8725efa28 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -1326,7 +1326,7 @@ static inline __init void hugetlb_cma_reserve(int order) #ifdef CONFIG_HUGETLB_PMD_PAGE_TABLE_SHARING static inline bool hugetlb_pmd_shared(pte_t *pte) { - return page_count(virt_to_page(pte)) > 1; + return ptdesc_pmd_is_shared(virt_to_ptdesc(pte)); } #else static inline bool hugetlb_pmd_shared(pte_t *pte) From 3937027caecb4f8251e82dd857ba1d749bb5a428 Mon Sep 17 00:00:00 2001 From: "David Hildenbrand (Red Hat)" Date: Tue, 23 Dec 2025 22:40:35 +0100 Subject: [PATCH 398/443] mm/hugetlb: fix two comments related to huge_pmd_unshare() Ever since we stopped using the page count to detect shared PMD page tables, these comments are outdated. The only reason we have to flush the TLB early is because once we drop the i_mmap_rwsem, the previously shared page table could get freed (to then get reallocated and used for other purpose). So we really have to flush the TLB before that could happen. So let's simplify the comments a bit. The "If we unshared PMDs, the TLB flush was not recorded in mmu_gather." part introduced as in commit a4a118f2eead ("hugetlbfs: flush TLBs correctly after huge_pmd_unshare") was confusing: sure it is recorded in the mmu_gather, otherwise tlb_flush_mmu_tlbonly() wouldn't do anything. So let's drop that comment while at it as well. We'll centralize these comments in a single helper as we rework the code next. Link: https://lkml.kernel.org/r/20251223214037.580860-3-david@kernel.org Fixes: 59d9094df3d7 ("mm: hugetlb: independent PMD page table shared count") Signed-off-by: David Hildenbrand (Red Hat) Reviewed-by: Rik van Riel Tested-by: Laurence Oberman Reviewed-by: Lorenzo Stoakes Acked-by: Oscar Salvador Reviewed-by: Harry Yoo Cc: Liu Shixin Cc: Lance Yang Cc: "Uschakow, Stanislav" Cc: Signed-off-by: Andrew Morton --- mm/hugetlb.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index e0ab14020513..67131aa24d77 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -5320,17 +5320,10 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma, tlb_end_vma(tlb, vma); /* - * If we unshared PMDs, the TLB flush was not recorded in mmu_gather. We - * could defer the flush until now, since by holding i_mmap_rwsem we - * guaranteed that the last reference would not be dropped. But we must - * do the flushing before we return, as otherwise i_mmap_rwsem will be - * dropped and the last reference to the shared PMDs page might be - * dropped as well. - * - * In theory we could defer the freeing of the PMD pages as well, but - * huge_pmd_unshare() relies on the exact page_count for the PMD page to - * detect sharing, so we cannot defer the release of the page either. - * Instead, do flush now. + * There is nothing protecting a previously-shared page table that we + * unshared through huge_pmd_unshare() from getting freed after we + * release i_mmap_rwsem, so flush the TLB now. If huge_pmd_unshare() + * succeeded, flush the range corresponding to the pud. */ if (force_flush) tlb_flush_mmu_tlbonly(tlb); @@ -6552,11 +6545,10 @@ next: cond_resched(); } /* - * Must flush TLB before releasing i_mmap_rwsem: x86's huge_pmd_unshare - * may have cleared our pud entry and done put_page on the page table: - * once we release i_mmap_rwsem, another task can do the final put_page - * and that page table be reused and filled with junk. If we actually - * did unshare a page of pmds, flush the range corresponding to the pud. + * There is nothing protecting a previously-shared page table that we + * unshared through huge_pmd_unshare() from getting freed after we + * release i_mmap_rwsem, so flush the TLB now. If huge_pmd_unshare() + * succeeded, flush the range corresponding to the pud. */ if (shared_pmd) flush_hugetlb_tlb_range(vma, range.start, range.end); From a8682d500f691b6dfaa16ae1502d990aeb86e8be Mon Sep 17 00:00:00 2001 From: "David Hildenbrand (Red Hat)" Date: Tue, 23 Dec 2025 22:40:36 +0100 Subject: [PATCH 399/443] mm/rmap: fix two comments related to huge_pmd_unshare() PMD page table unsharing no longer touches the refcount of a PMD page table. Also, it is not about dropping the refcount of a "PMD page" but the "PMD page table". Let's just simplify by saying that the PMD page table was unmapped, consequently also unmapping the folio that was mapped into this page. This code should be deduplicated in the future. Link: https://lkml.kernel.org/r/20251223214037.580860-4-david@kernel.org Fixes: 59d9094df3d7 ("mm: hugetlb: independent PMD page table shared count") Signed-off-by: David Hildenbrand (Red Hat) Reviewed-by: Rik van Riel Tested-by: Laurence Oberman Reviewed-by: Lorenzo Stoakes Acked-by: Oscar Salvador Cc: Liu Shixin Cc: Harry Yoo Cc: Lance Yang Cc: "Uschakow, Stanislav" Cc: Signed-off-by: Andrew Morton --- mm/rmap.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/mm/rmap.c b/mm/rmap.c index f955f02d570e..748f48727a16 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -2016,14 +2016,8 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma, flush_tlb_range(vma, range.start, range.end); /* - * The ref count of the PMD page was - * dropped which is part of the way map - * counting is done for shared PMDs. - * Return 'true' here. When there is - * no other sharing, huge_pmd_unshare - * returns false and we will unmap the - * actual page and drop map count - * to zero. + * The PMD table was unmapped, + * consequently unmapping the folio. */ goto walk_done; } @@ -2416,14 +2410,8 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma, range.start, range.end); /* - * The ref count of the PMD page was - * dropped which is part of the way map - * counting is done for shared PMDs. - * Return 'true' here. When there is - * no other sharing, huge_pmd_unshare - * returns false and we will unmap the - * actual page and drop map count - * to zero. + * The PMD table was unmapped, + * consequently unmapping the folio. */ page_vma_mapped_walk_done(&pvmw); break; From 8ce720d5bd91e9dc16db3604aa4b1bf76770a9a1 Mon Sep 17 00:00:00 2001 From: "David Hildenbrand (Red Hat)" Date: Tue, 23 Dec 2025 22:40:37 +0100 Subject: [PATCH 400/443] mm/hugetlb: fix excessive IPI broadcasts when unsharing PMD tables using mmu_gather As reported, ever since commit 1013af4f585f ("mm/hugetlb: fix huge_pmd_unshare() vs GUP-fast race") we can end up in some situations where we perform so many IPI broadcasts when unsharing hugetlb PMD page tables that it severely regresses some workloads. In particular, when we fork()+exit(), or when we munmap() a large area backed by many shared PMD tables, we perform one IPI broadcast per unshared PMD table. There are two optimizations to be had: (1) When we process (unshare) multiple such PMD tables, such as during exit(), it is sufficient to send a single IPI broadcast (as long as we respect locking rules) instead of one per PMD table. Locking prevents that any of these PMD tables could get reused before we drop the lock. (2) When we are not the last sharer (> 2 users including us), there is no need to send the IPI broadcast. The shared PMD tables cannot become exclusive (fully unshared) before an IPI will be broadcasted by the last sharer. Concurrent GUP-fast could walk into a PMD table just before we unshared it. It could then succeed in grabbing a page from the shared page table even after munmap() etc succeeded (and supressed an IPI). But there is not difference compared to GUP-fast just sleeping for a while after grabbing the page and re-enabling IRQs. Most importantly, GUP-fast will never walk into page tables that are no-longer shared, because the last sharer will issue an IPI broadcast. (if ever required, checking whether the PUD changed in GUP-fast after grabbing the page like we do in the PTE case could handle this) So let's rework PMD sharing TLB flushing + IPI sync to use the mmu_gather infrastructure so we can implement these optimizations and demystify the code at least a bit. Extend the mmu_gather infrastructure to be able to deal with our special hugetlb PMD table sharing implementation. To make initialization of the mmu_gather easier when working on a single VMA (in particular, when dealing with hugetlb), provide tlb_gather_mmu_vma(). We'll consolidate the handling for (full) unsharing of PMD tables in tlb_unshare_pmd_ptdesc() and tlb_flush_unshared_tables(), and track in "struct mmu_gather" whether we had (full) unsharing of PMD tables. Because locking is very special (concurrent unsharing+reuse must be prevented), we disallow deferring flushing to tlb_finish_mmu() and instead require an explicit earlier call to tlb_flush_unshared_tables(). From hugetlb code, we call huge_pmd_unshare_flush() where we make sure that the expected lock protecting us from concurrent unsharing+reuse is still held. Check with a VM_WARN_ON_ONCE() in tlb_finish_mmu() that tlb_flush_unshared_tables() was properly called earlier. Document it all properly. Notes about tlb_remove_table_sync_one() interaction with unsharing: There are two fairly tricky things: (1) tlb_remove_table_sync_one() is a NOP on architectures without CONFIG_MMU_GATHER_RCU_TABLE_FREE. Here, the assumption is that the previous TLB flush would send an IPI to all relevant CPUs. Careful: some architectures like x86 only send IPIs to all relevant CPUs when tlb->freed_tables is set. The relevant architectures should be selecting MMU_GATHER_RCU_TABLE_FREE, but x86 might not do that in stable kernels and it might have been problematic before this patch. Also, the arch flushing behavior (independent of IPIs) is different when tlb->freed_tables is set. Do we have to enlighten them to also take care of tlb->unshared_tables? So far we didn't care, so hopefully we are fine. Of course, we could be setting tlb->freed_tables as well, but that might then unnecessarily flush too much, because the semantics of tlb->freed_tables are a bit fuzzy. This patch changes nothing in this regard. (2) tlb_remove_table_sync_one() is not a NOP on architectures with CONFIG_MMU_GATHER_RCU_TABLE_FREE that actually don't need a sync. Take x86 as an example: in the common case (!pv, !X86_FEATURE_INVLPGB) we still issue IPIs during TLB flushes and don't actually need the second tlb_remove_table_sync_one(). This optimized can be implemented on top of this, by checking e.g., in tlb_remove_table_sync_one() whether we really need IPIs. But as described in (1), it really must honor tlb->freed_tables then to send IPIs to all relevant CPUs. Notes on TLB flushing changes: (1) Flushing for non-shared PMD tables We're converting from flush_hugetlb_tlb_range() to tlb_remove_huge_tlb_entry(). Given that we properly initialize the MMU gather in tlb_gather_mmu_vma() to be hugetlb aware, similar to __unmap_hugepage_range(), that should be fine. (2) Flushing for shared PMD tables We're converting from various things (flush_hugetlb_tlb_range(), tlb_flush_pmd_range(), flush_tlb_range()) to tlb_flush_pmd_range(). tlb_flush_pmd_range() achieves the same that tlb_remove_huge_tlb_entry() would achieve in these scenarios. Note that tlb_remove_huge_tlb_entry() also calls __tlb_remove_tlb_entry(), however that is only implemented on powerpc, which does not support PMD table sharing. Similar to (1), tlb_gather_mmu_vma() should make sure that TLB flushing keeps on working as expected. Further, note that the ptdesc_pmd_pts_dec() in huge_pmd_share() is not a concern, as we are holding the i_mmap_lock the whole time, preventing concurrent unsharing. That ptdesc_pmd_pts_dec() usage will be removed separately as a cleanup later. There are plenty more cleanups to be had, but they have to wait until this is fixed. [david@kernel.org: fix kerneldoc] Link: https://lkml.kernel.org/r/f223dd74-331c-412d-93fc-69e360a5006c@kernel.org Link: https://lkml.kernel.org/r/20251223214037.580860-5-david@kernel.org Fixes: 1013af4f585f ("mm/hugetlb: fix huge_pmd_unshare() vs GUP-fast race") Signed-off-by: David Hildenbrand (Red Hat) Reported-by: Uschakow, Stanislav" Closes: https://lore.kernel.org/all/4d3878531c76479d9f8ca9789dc6485d@amazon.de/ Tested-by: Laurence Oberman Acked-by: Harry Yoo Reviewed-by: Lorenzo Stoakes Cc: Lance Yang Cc: Liu Shixin Cc: Oscar Salvador Cc: Rik van Riel Cc: Signed-off-by: Andrew Morton --- include/asm-generic/tlb.h | 77 +++++++++++++++++++++++- include/linux/hugetlb.h | 15 +++-- include/linux/mm_types.h | 1 + mm/hugetlb.c | 123 ++++++++++++++++++++++---------------- mm/mmu_gather.c | 33 ++++++++++ mm/rmap.c | 25 +++++--- 6 files changed, 208 insertions(+), 66 deletions(-) diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h index 1fff717cae51..4d679d2a206b 100644 --- a/include/asm-generic/tlb.h +++ b/include/asm-generic/tlb.h @@ -46,7 +46,8 @@ * * The mmu_gather API consists of: * - * - tlb_gather_mmu() / tlb_gather_mmu_fullmm() / tlb_finish_mmu() + * - tlb_gather_mmu() / tlb_gather_mmu_fullmm() / tlb_gather_mmu_vma() / + * tlb_finish_mmu() * * start and finish a mmu_gather * @@ -364,6 +365,20 @@ struct mmu_gather { unsigned int vma_huge : 1; unsigned int vma_pfn : 1; + /* + * Did we unshare (unmap) any shared page tables? For now only + * used for hugetlb PMD table sharing. + */ + unsigned int unshared_tables : 1; + + /* + * Did we unshare any page tables such that they are now exclusive + * and could get reused+modified by the new owner? When setting this + * flag, "unshared_tables" will be set as well. For now only used + * for hugetlb PMD table sharing. + */ + unsigned int fully_unshared_tables : 1; + unsigned int batch_count; #ifndef CONFIG_MMU_GATHER_NO_GATHER @@ -400,6 +415,7 @@ static inline void __tlb_reset_range(struct mmu_gather *tlb) tlb->cleared_pmds = 0; tlb->cleared_puds = 0; tlb->cleared_p4ds = 0; + tlb->unshared_tables = 0; /* * Do not reset mmu_gather::vma_* fields here, we do not * call into tlb_start_vma() again to set them if there is an @@ -484,7 +500,7 @@ static inline void tlb_flush_mmu_tlbonly(struct mmu_gather *tlb) * these bits. */ if (!(tlb->freed_tables || tlb->cleared_ptes || tlb->cleared_pmds || - tlb->cleared_puds || tlb->cleared_p4ds)) + tlb->cleared_puds || tlb->cleared_p4ds || tlb->unshared_tables)) return; tlb_flush(tlb); @@ -773,6 +789,63 @@ static inline bool huge_pmd_needs_flush(pmd_t oldpmd, pmd_t newpmd) } #endif +#ifdef CONFIG_HUGETLB_PMD_PAGE_TABLE_SHARING +static inline void tlb_unshare_pmd_ptdesc(struct mmu_gather *tlb, struct ptdesc *pt, + unsigned long addr) +{ + /* + * The caller must make sure that concurrent unsharing + exclusive + * reuse is impossible until tlb_flush_unshared_tables() was called. + */ + VM_WARN_ON_ONCE(!ptdesc_pmd_is_shared(pt)); + ptdesc_pmd_pts_dec(pt); + + /* Clearing a PUD pointing at a PMD table with PMD leaves. */ + tlb_flush_pmd_range(tlb, addr & PUD_MASK, PUD_SIZE); + + /* + * If the page table is now exclusively owned, we fully unshared + * a page table. + */ + if (!ptdesc_pmd_is_shared(pt)) + tlb->fully_unshared_tables = true; + tlb->unshared_tables = true; +} + +static inline void tlb_flush_unshared_tables(struct mmu_gather *tlb) +{ + /* + * As soon as the caller drops locks to allow for reuse of + * previously-shared tables, these tables could get modified and + * even reused outside of hugetlb context, so we have to make sure that + * any page table walkers (incl. TLB, GUP-fast) are aware of that + * change. + * + * Even if we are not fully unsharing a PMD table, we must + * flush the TLB for the unsharer now. + */ + if (tlb->unshared_tables) + tlb_flush_mmu_tlbonly(tlb); + + /* + * Similarly, we must make sure that concurrent GUP-fast will not + * walk previously-shared page tables that are getting modified+reused + * elsewhere. So broadcast an IPI to wait for any concurrent GUP-fast. + * + * We only perform this when we are the last sharer of a page table, + * as the IPI will reach all CPUs: any GUP-fast. + * + * Note that on configs where tlb_remove_table_sync_one() is a NOP, + * the expectation is that the tlb_flush_mmu_tlbonly() would have issued + * required IPIs already for us. + */ + if (tlb->fully_unshared_tables) { + tlb_remove_table_sync_one(); + tlb->fully_unshared_tables = false; + } +} +#endif /* CONFIG_HUGETLB_PMD_PAGE_TABLE_SHARING */ + #endif /* CONFIG_MMU */ #endif /* _ASM_GENERIC__TLB_H */ diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 03c8725efa28..e51b8ef0cebd 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -240,8 +240,9 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma, pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr, unsigned long sz); unsigned long hugetlb_mask_last_page(struct hstate *h); -int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep); +int huge_pmd_unshare(struct mmu_gather *tlb, struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep); +void huge_pmd_unshare_flush(struct mmu_gather *tlb, struct vm_area_struct *vma); void adjust_range_if_pmd_sharing_possible(struct vm_area_struct *vma, unsigned long *start, unsigned long *end); @@ -300,13 +301,17 @@ static inline struct address_space *hugetlb_folio_mapping_lock_write( return NULL; } -static inline int huge_pmd_unshare(struct mm_struct *mm, - struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep) +static inline int huge_pmd_unshare(struct mmu_gather *tlb, + struct vm_area_struct *vma, unsigned long addr, pte_t *ptep) { return 0; } +static inline void huge_pmd_unshare_flush(struct mmu_gather *tlb, + struct vm_area_struct *vma) +{ +} + static inline void adjust_range_if_pmd_sharing_possible( struct vm_area_struct *vma, unsigned long *start, unsigned long *end) diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index aa4639888f89..78950eb8926d 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -1530,6 +1530,7 @@ static inline unsigned int mm_cid_size(void) struct mmu_gather; extern void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm); extern void tlb_gather_mmu_fullmm(struct mmu_gather *tlb, struct mm_struct *mm); +void tlb_gather_mmu_vma(struct mmu_gather *tlb, struct vm_area_struct *vma); extern void tlb_finish_mmu(struct mmu_gather *tlb); struct vm_fault; diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 67131aa24d77..a1832da0f623 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -5112,7 +5112,7 @@ int move_hugetlb_page_tables(struct vm_area_struct *vma, unsigned long last_addr_mask; pte_t *src_pte, *dst_pte; struct mmu_notifier_range range; - bool shared_pmd = false; + struct mmu_gather tlb; mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, mm, old_addr, old_end); @@ -5122,6 +5122,7 @@ int move_hugetlb_page_tables(struct vm_area_struct *vma, * range. */ flush_cache_range(vma, range.start, range.end); + tlb_gather_mmu_vma(&tlb, vma); mmu_notifier_invalidate_range_start(&range); last_addr_mask = hugetlb_mask_last_page(h); @@ -5138,8 +5139,7 @@ int move_hugetlb_page_tables(struct vm_area_struct *vma, if (huge_pte_none(huge_ptep_get(mm, old_addr, src_pte))) continue; - if (huge_pmd_unshare(mm, vma, old_addr, src_pte)) { - shared_pmd = true; + if (huge_pmd_unshare(&tlb, vma, old_addr, src_pte)) { old_addr |= last_addr_mask; new_addr |= last_addr_mask; continue; @@ -5150,15 +5150,16 @@ int move_hugetlb_page_tables(struct vm_area_struct *vma, break; move_huge_pte(vma, old_addr, new_addr, src_pte, dst_pte, sz); + tlb_remove_huge_tlb_entry(h, &tlb, src_pte, old_addr); } - if (shared_pmd) - flush_hugetlb_tlb_range(vma, range.start, range.end); - else - flush_hugetlb_tlb_range(vma, old_end - len, old_end); + tlb_flush_mmu_tlbonly(&tlb); + huge_pmd_unshare_flush(&tlb, vma); + mmu_notifier_invalidate_range_end(&range); i_mmap_unlock_write(mapping); hugetlb_vma_unlock_write(vma); + tlb_finish_mmu(&tlb); return len + old_addr - old_end; } @@ -5177,7 +5178,6 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma, unsigned long sz = huge_page_size(h); bool adjust_reservation; unsigned long last_addr_mask; - bool force_flush = false; WARN_ON(!is_vm_hugetlb_page(vma)); BUG_ON(start & ~huge_page_mask(h)); @@ -5200,10 +5200,8 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma, } ptl = huge_pte_lock(h, mm, ptep); - if (huge_pmd_unshare(mm, vma, address, ptep)) { + if (huge_pmd_unshare(tlb, vma, address, ptep)) { spin_unlock(ptl); - tlb_flush_pmd_range(tlb, address & PUD_MASK, PUD_SIZE); - force_flush = true; address |= last_addr_mask; continue; } @@ -5319,14 +5317,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma, } tlb_end_vma(tlb, vma); - /* - * There is nothing protecting a previously-shared page table that we - * unshared through huge_pmd_unshare() from getting freed after we - * release i_mmap_rwsem, so flush the TLB now. If huge_pmd_unshare() - * succeeded, flush the range corresponding to the pud. - */ - if (force_flush) - tlb_flush_mmu_tlbonly(tlb); + huge_pmd_unshare_flush(tlb, vma); } void __hugetlb_zap_begin(struct vm_area_struct *vma, @@ -6425,11 +6416,11 @@ long hugetlb_change_protection(struct vm_area_struct *vma, pte_t pte; struct hstate *h = hstate_vma(vma); long pages = 0, psize = huge_page_size(h); - bool shared_pmd = false; struct mmu_notifier_range range; unsigned long last_addr_mask; bool uffd_wp = cp_flags & MM_CP_UFFD_WP; bool uffd_wp_resolve = cp_flags & MM_CP_UFFD_WP_RESOLVE; + struct mmu_gather tlb; /* * In the case of shared PMDs, the area to flush could be beyond @@ -6442,6 +6433,7 @@ long hugetlb_change_protection(struct vm_area_struct *vma, BUG_ON(address >= end); flush_cache_range(vma, range.start, range.end); + tlb_gather_mmu_vma(&tlb, vma); mmu_notifier_invalidate_range_start(&range); hugetlb_vma_lock_write(vma); @@ -6468,7 +6460,7 @@ long hugetlb_change_protection(struct vm_area_struct *vma, } } ptl = huge_pte_lock(h, mm, ptep); - if (huge_pmd_unshare(mm, vma, address, ptep)) { + if (huge_pmd_unshare(&tlb, vma, address, ptep)) { /* * When uffd-wp is enabled on the vma, unshare * shouldn't happen at all. Warn about it if it @@ -6477,7 +6469,6 @@ long hugetlb_change_protection(struct vm_area_struct *vma, WARN_ON_ONCE(uffd_wp || uffd_wp_resolve); pages++; spin_unlock(ptl); - shared_pmd = true; address |= last_addr_mask; continue; } @@ -6538,22 +6529,16 @@ long hugetlb_change_protection(struct vm_area_struct *vma, pte = huge_pte_clear_uffd_wp(pte); huge_ptep_modify_prot_commit(vma, address, ptep, old_pte, pte); pages++; + tlb_remove_huge_tlb_entry(h, &tlb, ptep, address); } next: spin_unlock(ptl); cond_resched(); } - /* - * There is nothing protecting a previously-shared page table that we - * unshared through huge_pmd_unshare() from getting freed after we - * release i_mmap_rwsem, so flush the TLB now. If huge_pmd_unshare() - * succeeded, flush the range corresponding to the pud. - */ - if (shared_pmd) - flush_hugetlb_tlb_range(vma, range.start, range.end); - else - flush_hugetlb_tlb_range(vma, start, end); + + tlb_flush_mmu_tlbonly(&tlb); + huge_pmd_unshare_flush(&tlb, vma); /* * No need to call mmu_notifier_arch_invalidate_secondary_tlbs() we are * downgrading page table protection not changing it to point to a new @@ -6564,6 +6549,7 @@ next: i_mmap_unlock_write(vma->vm_file->f_mapping); hugetlb_vma_unlock_write(vma); mmu_notifier_invalidate_range_end(&range); + tlb_finish_mmu(&tlb); return pages > 0 ? (pages << h->order) : pages; } @@ -6920,18 +6906,27 @@ out: return pte; } -/* - * unmap huge page backed by shared pte. +/** + * huge_pmd_unshare - Unmap a pmd table if it is shared by multiple users + * @tlb: the current mmu_gather. + * @vma: the vma covering the pmd table. + * @addr: the address we are trying to unshare. + * @ptep: pointer into the (pmd) page table. * - * Called with page table lock held. + * Called with the page table lock held, the i_mmap_rwsem held in write mode + * and the hugetlb vma lock held in write mode. * - * returns: 1 successfully unmapped a shared pte page - * 0 the underlying pte page is not shared, or it is the last user + * Note: The caller must call huge_pmd_unshare_flush() before dropping the + * i_mmap_rwsem. + * + * Returns: 1 if it was a shared PMD table and it got unmapped, or 0 if it + * was not a shared PMD table. */ -int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep) +int huge_pmd_unshare(struct mmu_gather *tlb, struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep) { unsigned long sz = huge_page_size(hstate_vma(vma)); + struct mm_struct *mm = vma->vm_mm; pgd_t *pgd = pgd_offset(mm, addr); p4d_t *p4d = p4d_offset(pgd, addr); pud_t *pud = pud_offset(p4d, addr); @@ -6943,18 +6938,36 @@ int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma, i_mmap_assert_write_locked(vma->vm_file->f_mapping); hugetlb_vma_assert_locked(vma); pud_clear(pud); - /* - * Once our caller drops the rmap lock, some other process might be - * using this page table as a normal, non-hugetlb page table. - * Wait for pending gup_fast() in other threads to finish before letting - * that happen. - */ - tlb_remove_table_sync_one(); - ptdesc_pmd_pts_dec(virt_to_ptdesc(ptep)); + + tlb_unshare_pmd_ptdesc(tlb, virt_to_ptdesc(ptep), addr); + mm_dec_nr_pmds(mm); return 1; } +/* + * huge_pmd_unshare_flush - Complete a sequence of huge_pmd_unshare() calls + * @tlb: the current mmu_gather. + * @vma: the vma covering the pmd table. + * + * Perform necessary TLB flushes or IPI broadcasts to synchronize PMD table + * unsharing with concurrent page table walkers. + * + * This function must be called after a sequence of huge_pmd_unshare() + * calls while still holding the i_mmap_rwsem. + */ +void huge_pmd_unshare_flush(struct mmu_gather *tlb, struct vm_area_struct *vma) +{ + /* + * We must synchronize page table unsharing such that nobody will + * try reusing a previously-shared page table while it might still + * be in use by previous sharers (TLB, GUP_fast). + */ + i_mmap_assert_write_locked(vma->vm_file->f_mapping); + + tlb_flush_unshared_tables(tlb); +} + #else /* !CONFIG_HUGETLB_PMD_PAGE_TABLE_SHARING */ pte_t *huge_pmd_share(struct mm_struct *mm, struct vm_area_struct *vma, @@ -6963,12 +6976,16 @@ pte_t *huge_pmd_share(struct mm_struct *mm, struct vm_area_struct *vma, return NULL; } -int huge_pmd_unshare(struct mm_struct *mm, struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep) +int huge_pmd_unshare(struct mmu_gather *tlb, struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep) { return 0; } +void huge_pmd_unshare_flush(struct mmu_gather *tlb, struct vm_area_struct *vma) +{ +} + void adjust_range_if_pmd_sharing_possible(struct vm_area_struct *vma, unsigned long *start, unsigned long *end) { @@ -7235,6 +7252,7 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma, unsigned long sz = huge_page_size(h); struct mm_struct *mm = vma->vm_mm; struct mmu_notifier_range range; + struct mmu_gather tlb; unsigned long address; spinlock_t *ptl; pte_t *ptep; @@ -7246,6 +7264,8 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma, return; flush_cache_range(vma, start, end); + tlb_gather_mmu_vma(&tlb, vma); + /* * No need to call adjust_range_if_pmd_sharing_possible(), because * we have already done the PUD_SIZE alignment. @@ -7264,10 +7284,10 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma, if (!ptep) continue; ptl = huge_pte_lock(h, mm, ptep); - huge_pmd_unshare(mm, vma, address, ptep); + huge_pmd_unshare(&tlb, vma, address, ptep); spin_unlock(ptl); } - flush_hugetlb_tlb_range(vma, start, end); + huge_pmd_unshare_flush(&tlb, vma); if (take_locks) { i_mmap_unlock_write(vma->vm_file->f_mapping); hugetlb_vma_unlock_write(vma); @@ -7277,6 +7297,7 @@ static void hugetlb_unshare_pmds(struct vm_area_struct *vma, * Documentation/mm/mmu_notifier.rst. */ mmu_notifier_invalidate_range_end(&range); + tlb_finish_mmu(&tlb); } /* diff --git a/mm/mmu_gather.c b/mm/mmu_gather.c index 247e3f9db6c7..7468ec388455 100644 --- a/mm/mmu_gather.c +++ b/mm/mmu_gather.c @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -426,6 +427,7 @@ static void __tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, #endif tlb->vma_pfn = 0; + tlb->fully_unshared_tables = 0; __tlb_reset_range(tlb); inc_tlb_flush_pending(tlb->mm); } @@ -459,6 +461,31 @@ void tlb_gather_mmu_fullmm(struct mmu_gather *tlb, struct mm_struct *mm) __tlb_gather_mmu(tlb, mm, true); } +/** + * tlb_gather_mmu_vma - initialize an mmu_gather structure for operating on a + * single VMA + * @tlb: the mmu_gather structure to initialize + * @vma: the vm_area_struct + * + * Called to initialize an (on-stack) mmu_gather structure for operating on + * a single VMA. In contrast to tlb_gather_mmu(), calling this function will + * not require another call to tlb_start_vma(). In contrast to tlb_start_vma(), + * this function will *not* call flush_cache_range(). + * + * For hugetlb VMAs, this function will also initialize the mmu_gather + * page_size accordingly, not requiring a separate call to + * tlb_change_page_size(). + * + */ +void tlb_gather_mmu_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) +{ + tlb_gather_mmu(tlb, vma->vm_mm); + tlb_update_vma_flags(tlb, vma); + if (is_vm_hugetlb_page(vma)) + /* All entries have the same size. */ + tlb_change_page_size(tlb, huge_page_size(hstate_vma(vma))); +} + /** * tlb_finish_mmu - finish an mmu_gather structure * @tlb: the mmu_gather structure to finish @@ -468,6 +495,12 @@ void tlb_gather_mmu_fullmm(struct mmu_gather *tlb, struct mm_struct *mm) */ void tlb_finish_mmu(struct mmu_gather *tlb) { + /* + * We expect an earlier huge_pmd_unshare_flush() call to sort this out, + * due to complicated locking requirements with page table unsharing. + */ + VM_WARN_ON_ONCE(tlb->fully_unshared_tables); + /* * If there are parallel threads are doing PTE changes on same range * under non-exclusive lock (e.g., mmap_lock read-side) but defer TLB diff --git a/mm/rmap.c b/mm/rmap.c index 748f48727a16..7b9879ef442d 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -76,7 +76,7 @@ #include #include -#include +#include #define CREATE_TRACE_POINTS #include @@ -2008,13 +2008,17 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma, * if unsuccessful. */ if (!anon) { + struct mmu_gather tlb; + VM_BUG_ON(!(flags & TTU_RMAP_LOCKED)); if (!hugetlb_vma_trylock_write(vma)) goto walk_abort; - if (huge_pmd_unshare(mm, vma, address, pvmw.pte)) { + + tlb_gather_mmu_vma(&tlb, vma); + if (huge_pmd_unshare(&tlb, vma, address, pvmw.pte)) { hugetlb_vma_unlock_write(vma); - flush_tlb_range(vma, - range.start, range.end); + huge_pmd_unshare_flush(&tlb, vma); + tlb_finish_mmu(&tlb); /* * The PMD table was unmapped, * consequently unmapping the folio. @@ -2022,6 +2026,7 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma, goto walk_done; } hugetlb_vma_unlock_write(vma); + tlb_finish_mmu(&tlb); } pteval = huge_ptep_clear_flush(vma, address, pvmw.pte); if (pte_dirty(pteval)) @@ -2398,17 +2403,20 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma, * fail if unsuccessful. */ if (!anon) { + struct mmu_gather tlb; + VM_BUG_ON(!(flags & TTU_RMAP_LOCKED)); if (!hugetlb_vma_trylock_write(vma)) { page_vma_mapped_walk_done(&pvmw); ret = false; break; } - if (huge_pmd_unshare(mm, vma, address, pvmw.pte)) { - hugetlb_vma_unlock_write(vma); - flush_tlb_range(vma, - range.start, range.end); + tlb_gather_mmu_vma(&tlb, vma); + if (huge_pmd_unshare(&tlb, vma, address, pvmw.pte)) { + hugetlb_vma_unlock_write(vma); + huge_pmd_unshare_flush(&tlb, vma); + tlb_finish_mmu(&tlb); /* * The PMD table was unmapped, * consequently unmapping the folio. @@ -2417,6 +2425,7 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma, break; } hugetlb_vma_unlock_write(vma); + tlb_finish_mmu(&tlb); } /* Nuke the hugetlb page table entry */ pteval = huge_ptep_clear_flush(vma, address, pvmw.pte); From 35e247032606f06c2f19d90a6562bc315206b7a7 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Wed, 14 Jan 2026 11:00:06 +0000 Subject: [PATCH 401/443] mm: do not copy page tables unnecessarily for VM_UFFD_WP Commit ab04b530e7e8 ("mm: introduce copy-on-fork VMAs and make VM_MAYBE_GUARD one") aggregates flags checks in vma_needs_copy(), including VM_UFFD_WP. However in doing so, it incorrectly performed this check against src_vma. This check was done on the assumption that all relevant flags are copied upon fork. However the userfaultfd logic is very innovative in that it implements custom logic on fork in dup_userfaultfd(), including a rather well hidden case where lacking UFFD_FEATURE_EVENT_FORK causes VM_UFFD_WP to not be propagated to the destination VMA. And indeed, vma_needs_copy(), prior to this patch, did check this property on dst_vma, not src_vma. Since all the other relevant flags are copied on fork, we can simply fix this by checking against dst_vma. While we're here, we fix a comment against VM_COPY_ON_FORK (noting that it did indeed already reference dst_vma) to make it abundantly clear that we must check against the destination VMA. Link: https://lkml.kernel.org/r/20260114110006.1047071-1-lorenzo.stoakes@oracle.com Fixes: ab04b530e7e8 ("mm: introduce copy-on-fork VMAs and make VM_MAYBE_GUARD one") Signed-off-by: Lorenzo Stoakes Reported-by: Chris Mason Closes: https://lore.kernel.org/all/20260113231257.3002271-1-clm@meta.com/ Acked-by: David Hildenbrand (Red Hat) Acked-by: Pedro Falcato Cc: Liam Howlett Cc: Michal Hocko Cc: Mike Rapoport Cc: Suren Baghdasaryan Cc: Vlastimil Babka Signed-off-by: Andrew Morton --- include/linux/mm.h | 6 +++++- mm/memory.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 6f959d8ca4b4..f0d5be9dc736 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -608,7 +608,11 @@ enum { /* * Flags which should result in page tables being copied on fork. These are * flags which indicate that the VMA maps page tables which cannot be - * reconsistuted upon page fault, so necessitate page table copying upon + * reconsistuted upon page fault, so necessitate page table copying upon fork. + * + * Note that these flags should be compared with the DESTINATION VMA not the + * source, as VM_UFFD_WP may not be propagated to destination, while all other + * flags will be. * * VM_PFNMAP / VM_MIXEDMAP - These contain kernel-mapped data which cannot be * reasonably reconstructed on page fault. diff --git a/mm/memory.c b/mm/memory.c index a0822b564cc0..da360a6eb8a4 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1465,7 +1465,11 @@ copy_p4d_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma, static bool vma_needs_copy(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma) { - if (src_vma->vm_flags & VM_COPY_ON_FORK) + /* + * We check against dst_vma as while sane VMA flags will have been + * copied, VM_UFFD_WP may be set only on dst_vma. + */ + if (dst_vma->vm_flags & VM_COPY_ON_FORK) return true; /* * The presence of an anon_vma indicates an anonymous VMA has page From cb7d761bf5d4b1600564efdd42653b821eb2ec8e Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Fri, 16 Jan 2026 10:44:23 -0800 Subject: [PATCH 402/443] Docs/mm/allocation-profiling: describe sysctrl limitations in debug mode When CONFIG_MEM_ALLOC_PROFILING_DEBUG=y, /proc/sys/vm/mem_profiling is read-only to avoid debug warnings in a scenario when an allocation is made while profiling is disabled (allocation does not get an allocation tag), then profiling gets enabled and allocation gets freed (warning due to the allocation missing allocation tag). Link: https://lkml.kernel.org/r/20260116184423.2708363-1-surenb@google.com Fixes: ebdf9ad4ca98 ("memprofiling: documentation") Reported-by: Andrew Morton Signed-off-by: Suren Baghdasaryan Acked-by: SeongJae Park Cc: Jonathan Corbet Cc: Kent Overstreet Cc: Matthew Wilcox (Oracle) Cc: Ran Xiaokai Cc: SeongJae Park Signed-off-by: Andrew Morton --- Documentation/admin-guide/sysctl/vm.rst | 4 ++++ Documentation/mm/allocation-profiling.rst | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/Documentation/admin-guide/sysctl/vm.rst b/Documentation/admin-guide/sysctl/vm.rst index 4d71211fdad8..245bf6394935 100644 --- a/Documentation/admin-guide/sysctl/vm.rst +++ b/Documentation/admin-guide/sysctl/vm.rst @@ -494,6 +494,10 @@ memory allocations. The default value depends on CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT. +When CONFIG_MEM_ALLOC_PROFILING_DEBUG=y, this control is read-only to avoid +warnings produced by allocations made while profiling is disabled and freed +when it's enabled. + memory_failure_early_kill ========================= diff --git a/Documentation/mm/allocation-profiling.rst b/Documentation/mm/allocation-profiling.rst index 316311240e6a..5389d241176a 100644 --- a/Documentation/mm/allocation-profiling.rst +++ b/Documentation/mm/allocation-profiling.rst @@ -33,6 +33,16 @@ Boot parameter: sysctl: /proc/sys/vm/mem_profiling + 1: Enable memory profiling. + + 0: Disable memory profiling. + + The default value depends on CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT. + + When CONFIG_MEM_ALLOC_PROFILING_DEBUG=y, this control is read-only to avoid + warnings produced by allocations made while profiling is disabled and freed + when it's enabled. + Runtime info: /proc/allocinfo From 9bc9ccbf4c935852e4916081dbce4c25a585ec7d Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Fri, 16 Jan 2026 06:10:11 -0800 Subject: [PATCH 403/443] mm/kfence: fix potential deadlock in reboot notifier The reboot notifier callback can deadlock when calling cancel_delayed_work_sync() if toggle_allocation_gate() is blocked in wait_event_idle() waiting for allocations, that might not happen on shutdown path. The issue is that cancel_delayed_work_sync() waits for the work to complete, but the work is waiting for kfence_allocation_gate > 0 which requires allocations to happen (each allocation is increased by 1) - allocations that may have stopped during shutdown. Fix this by: 1. Using cancel_delayed_work() (non-sync) to avoid blocking. Now the callback succeeds and return. 2. Adding wake_up() to unblock any waiting toggle_allocation_gate() 3. Adding !kfence_enabled to the wait condition so the wake succeeds The static_branch_disable() IPI will still execute after the wake, but at this early point in shutdown (reboot notifier runs with INT_MAX priority), the system is still functional and CPUs can respond to IPIs. Link: https://lkml.kernel.org/r/20260116-kfence_fix-v1-1-4165a055933f@debian.org Fixes: ce2bba89566b ("mm/kfence: add reboot notifier to disable KFENCE on shutdown") Signed-off-by: Breno Leitao Reported-by: Chris Mason Closes: https://lore.kernel.org/all/20260113140234.677117-1-clm@meta.com/ Reviewed-by: Marco Elver Cc: Alexander Potapenko Cc: Breno Leitao Cc: Chris Mason Cc: Dmitriy Vyukov Signed-off-by: Andrew Morton --- mm/kfence/core.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index 577a1699c553..da0f5b6f5744 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -823,6 +823,9 @@ static struct notifier_block kfence_check_canary_notifier = { static struct delayed_work kfence_timer; #ifdef CONFIG_KFENCE_STATIC_KEYS +/* Wait queue to wake up allocation-gate timer task. */ +static DECLARE_WAIT_QUEUE_HEAD(allocation_wait); + static int kfence_reboot_callback(struct notifier_block *nb, unsigned long action, void *data) { @@ -832,7 +835,12 @@ static int kfence_reboot_callback(struct notifier_block *nb, */ WRITE_ONCE(kfence_enabled, false); /* Cancel any pending timer work */ - cancel_delayed_work_sync(&kfence_timer); + cancel_delayed_work(&kfence_timer); + /* + * Wake up any blocked toggle_allocation_gate() so it can complete + * early while the system is still able to handle IPIs. + */ + wake_up(&allocation_wait); return NOTIFY_OK; } @@ -842,9 +850,6 @@ static struct notifier_block kfence_reboot_notifier = { .priority = INT_MAX, /* Run early to stop timers ASAP */ }; -/* Wait queue to wake up allocation-gate timer task. */ -static DECLARE_WAIT_QUEUE_HEAD(allocation_wait); - static void wake_up_kfence_timer(struct irq_work *work) { wake_up(&allocation_wait); @@ -873,7 +878,9 @@ static void toggle_allocation_gate(struct work_struct *work) /* Enable static key, and await allocation to happen. */ static_branch_enable(&kfence_allocation_key); - wait_event_idle(allocation_wait, atomic_read(&kfence_allocation_gate) > 0); + wait_event_idle(allocation_wait, + atomic_read(&kfence_allocation_gate) > 0 || + !READ_ONCE(kfence_enabled)); /* Disable static key and reset timer. */ static_branch_disable(&kfence_allocation_key); From 16aca2c98a6fdf071e5a1a765a295995d7c7e346 Mon Sep 17 00:00:00 2001 From: Yosry Ahmed Date: Fri, 16 Jan 2026 20:52:47 +0000 Subject: [PATCH 404/443] mm: restore per-memcg proactive reclaim with !CONFIG_NUMA Commit 2b7226af730c ("mm/memcg: make memory.reclaim interface generic") moved proactive reclaim logic from memory.reclaim handler to a generic user_proactive_reclaim() helper to be used for per-node proactive reclaim. However, user_proactive_reclaim() was only defined under CONFIG_NUMA, with a stub always returning 0 otherwise. This broke memory.reclaim on !CONFIG_NUMA configs, causing it to report success without actually attempting reclaim. Move the definition of user_proactive_reclaim() outside CONFIG_NUMA, and instead define a stub for __node_reclaim() in the !CONFIG_NUMA case. __node_reclaim() is only called from user_proactive_reclaim() when a write is made to sys/devices/system/node/nodeX/reclaim, which is only defined with CONFIG_NUMA. Link: https://lkml.kernel.org/r/20260116205247.928004-1-yosry.ahmed@linux.dev Fixes: 2b7226af730c ("mm/memcg: make memory.reclaim interface generic") Signed-off-by: Yosry Ahmed Acked-by: Shakeel Butt Acked-by: Michal Hocko Cc: Axel Rasmussen Cc: David Hildenbrand Cc: Davidlohr Bueso Cc: Johannes Weiner Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Mike Rapoport Cc: Qi Zheng Cc: Suren Baghdasaryan Cc: Vlastimil Babka Cc: Wei Xu Cc: Yuanchu Xie Cc: Signed-off-by: Andrew Morton --- mm/internal.h | 8 -------- mm/vmscan.c | 13 +++++++++++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/mm/internal.h b/mm/internal.h index e430da900430..f35dbcf99a86 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -538,16 +538,8 @@ extern unsigned long highest_memmap_pfn; bool folio_isolate_lru(struct folio *folio); void folio_putback_lru(struct folio *folio); extern void reclaim_throttle(pg_data_t *pgdat, enum vmscan_throttle_state reason); -#ifdef CONFIG_NUMA int user_proactive_reclaim(char *buf, struct mem_cgroup *memcg, pg_data_t *pgdat); -#else -static inline int user_proactive_reclaim(char *buf, - struct mem_cgroup *memcg, pg_data_t *pgdat) -{ - return 0; -} -#endif /* * in mm/rmap.c: diff --git a/mm/vmscan.c b/mm/vmscan.c index 670fe9fae5ba..614ccf39fe3f 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -7707,6 +7707,17 @@ int node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned int order) return ret; } +#else + +static unsigned long __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, + unsigned long nr_pages, + struct scan_control *sc) +{ + return 0; +} + +#endif + enum { MEMORY_RECLAIM_SWAPPINESS = 0, MEMORY_RECLAIM_SWAPPINESS_MAX, @@ -7814,8 +7825,6 @@ int user_proactive_reclaim(char *buf, return 0; } -#endif - /** * check_move_unevictable_folios - Move evictable folios to appropriate zone * lru list From f406220eb8e227ca344eef1a6d30aff53706b196 Mon Sep 17 00:00:00 2001 From: Cody Haas Date: Fri, 12 Dec 2025 16:22:26 -0800 Subject: [PATCH 405/443] ice: Fix persistent failure in ice_get_rxfh Several ioctl functions have the ability to call ice_get_rxfh, however all of these ioctl functions do not provide all of the expected information in ethtool_rxfh_param. For example, ethtool_get_rxfh_indir does not provide an rss_key. This previously caused ethtool_get_rxfh_indir to always fail with -EINVAL. This change draws inspiration from i40e_get_rss to handle this situation, by only calling the appropriate rss helpers when the necessary information has been provided via ethtool_rxfh_param. Fixes: b66a972abb6b ("ice: Refactor ice_set/get_rss into LUT and key specific functions") Signed-off-by: Cody Haas Closes: https://lore.kernel.org/intel-wired-lan/CAH7f-UKkJV8MLY7zCdgCrGE55whRhbGAXvgkDnwgiZ9gUZT7_w@mail.gmail.com/ Reviewed-by: Aleksandr Loktionov Reviewed-by: Przemek Kitszel Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice.h | 1 + drivers/net/ethernet/intel/ice/ice_ethtool.c | 6 +---- drivers/net/ethernet/intel/ice/ice_main.c | 28 ++++++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 147aaee192a7..00f75d87c73f 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -979,6 +979,7 @@ void ice_map_xdp_rings(struct ice_vsi *vsi); int ice_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames, u32 flags); +int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size); int ice_set_rss_lut(struct ice_vsi *vsi, u8 *lut, u16 lut_size); int ice_get_rss_lut(struct ice_vsi *vsi, u8 *lut, u16 lut_size); int ice_set_rss_key(struct ice_vsi *vsi, u8 *seed); diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 969d4f8f9c02..3565a5d96c6d 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -3626,11 +3626,7 @@ ice_get_rxfh(struct net_device *netdev, struct ethtool_rxfh_param *rxfh) if (!lut) return -ENOMEM; - err = ice_get_rss_key(vsi, rxfh->key); - if (err) - goto out; - - err = ice_get_rss_lut(vsi, lut, vsi->rss_table_size); + err = ice_get_rss(vsi, rxfh->key, lut, vsi->rss_table_size); if (err) goto out; diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 4bb68e7a00f5..6a9278487ccb 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -7988,6 +7988,34 @@ int ice_get_rss_key(struct ice_vsi *vsi, u8 *seed) return status; } +/** + * ice_get_rss - Get RSS LUT and/or key + * @vsi: Pointer to VSI structure + * @seed: Buffer to store the key in + * @lut: Buffer to store the lookup table entries + * @lut_size: Size of buffer to store the lookup table entries + * + * Return: 0 on success, negative on failure + */ +int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) +{ + int err; + + if (seed) { + err = ice_get_rss_key(vsi, seed); + if (err) + return err; + } + + if (lut) { + err = ice_get_rss_lut(vsi, lut, lut_size); + if (err) + return err; + } + + return 0; +} + /** * ice_set_rss_hfunc - Set RSS HASH function * @vsi: Pointer to VSI structure From 42fb5f3deb582cb96440e4683745017dbabb83d6 Mon Sep 17 00:00:00 2001 From: Paul Greenwalt Date: Thu, 18 Dec 2025 08:36:53 -0500 Subject: [PATCH 406/443] ice: add missing ice_deinit_hw() in devlink reinit path devlink-reload results in ice_init_hw failed error, and then removing the ice driver causes a NULL pointer dereference. [ +0.102213] ice 0000:ca:00.0: ice_init_hw failed: -16 ... [ +0.000001] Call Trace: [ +0.000003] [ +0.000006] ice_unload+0x8f/0x100 [ice] [ +0.000081] ice_remove+0xba/0x300 [ice] Commit 1390b8b3d2be ("ice: remove duplicate call to ice_deinit_hw() on error paths") removed ice_deinit_hw() from ice_deinit_dev(). As a result ice_devlink_reinit_down() no longer calls ice_deinit_hw(), but ice_devlink_reinit_up() still calls ice_init_hw(). Since the control queues are not uninitialized, ice_init_hw() fails with -EBUSY. Add ice_deinit_hw() to ice_devlink_reinit_down() to correspond with ice_init_hw() in ice_devlink_reinit_up(). Fixes: 1390b8b3d2be ("ice: remove duplicate call to ice_deinit_hw() on error paths") Reviewed-by: Aleksandr Loktionov Reviewed-by: Przemek Kitszel Signed-off-by: Paul Greenwalt Reviewed-by: Paul Menzel Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/devlink/devlink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink.c b/drivers/net/ethernet/intel/ice/devlink/devlink.c index d88b7f3fd1f9..2ef39cc70c21 100644 --- a/drivers/net/ethernet/intel/ice/devlink/devlink.c +++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c @@ -460,6 +460,7 @@ static void ice_devlink_reinit_down(struct ice_pf *pf) ice_vsi_decfg(ice_get_main_vsi(pf)); rtnl_unlock(); ice_deinit_pf(pf); + ice_deinit_hw(&pf->hw); ice_deinit_dev(pf); } From d3f867e7a04678640ebcbfb81893c59f4af48586 Mon Sep 17 00:00:00 2001 From: Paul Greenwalt Date: Mon, 29 Dec 2025 03:52:34 -0500 Subject: [PATCH 407/443] ice: fix devlink reload call trace Commit 4da71a77fc3b ("ice: read internal temperature sensor") introduced internal temperature sensor reading via HWMON. ice_hwmon_init() was added to ice_init_feature() and ice_hwmon_exit() was added to ice_remove(). As a result if devlink reload is used to reinit the device and then the driver is removed, a call trace can occur. BUG: unable to handle page fault for address: ffffffffc0fd4b5d Call Trace: string+0x48/0xe0 vsnprintf+0x1f9/0x650 sprintf+0x62/0x80 name_show+0x1f/0x30 dev_attr_show+0x19/0x60 The call trace repeats approximately every 10 minutes when system monitoring tools (e.g., sadc) attempt to read the orphaned hwmon sysfs attributes that reference freed module memory. The sequence is: 1. Driver load, ice_hwmon_init() gets called from ice_init_feature() 2. Devlink reload down, flow does not call ice_remove() 3. Devlink reload up, ice_hwmon_init() gets called from ice_init_feature() resulting in a second instance 4. Driver unload, ice_hwmon_exit() called from ice_remove() leaving the first hwmon instance orphaned with dangling pointer Fix this by moving ice_hwmon_exit() from ice_remove() to ice_deinit_features() to ensure proper cleanup symmetry with ice_hwmon_init(). Fixes: 4da71a77fc3b ("ice: read internal temperature sensor") Reviewed-by: Aleksandr Loktionov Signed-off-by: Paul Greenwalt Reviewed-by: Paul Menzel Tested-by: Rinitha S (A Contingent worker at Intel) Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ice/ice_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 6a9278487ccb..de488185cd4a 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4836,6 +4836,7 @@ static void ice_deinit_features(struct ice_pf *pf) ice_dpll_deinit(pf); if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) xa_destroy(&pf->eswitch.reprs); + ice_hwmon_exit(pf); } static void ice_init_wakeup(struct ice_pf *pf) @@ -5437,8 +5438,6 @@ static void ice_remove(struct pci_dev *pdev) ice_free_vfs(pf); } - ice_hwmon_exit(pf); - if (!ice_is_safe_mode(pf)) ice_remove_arfs(pf); From bdfc7b55adcd04834ccc1b6b13e55e3fd7eaa789 Mon Sep 17 00:00:00 2001 From: Mina Almasry Date: Thu, 11 Dec 2025 10:19:29 +0000 Subject: [PATCH 408/443] idpf: read lower clock bits inside the time sandwich PCIe reads need to be done inside the time sandwich because PCIe writes may get buffered in the PCIe fabric and posted to the device after the _postts completes. Doing the PCIe read inside the time sandwich guarantees that the write gets flushed before the _postts timestamp is taken. Cc: lrizzo@google.com Cc: namangulati@google.com Cc: willemb@google.com Cc: intel-wired-lan@lists.osuosl.org Cc: milena.olech@intel.com Cc: jacob.e.keller@intel.com Fixes: 5cb8805d2366 ("idpf: negotiate PTP capabilities and get PTP clock") Suggested-by: Shachar Raindel Signed-off-by: Mina Almasry Reviewed-by: Jacob Keller Reviewed-by: Aleksandr Loktionov Tested-by: Samuel Salin Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/idpf/idpf_ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_ptp.c index 3e1052d070cf..0a8b50350b86 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ptp.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ptp.c @@ -108,11 +108,11 @@ static u64 idpf_ptp_read_src_clk_reg_direct(struct idpf_adapter *adapter, ptp_read_system_prets(sts); idpf_ptp_enable_shtime(adapter); + lo = readl(ptp->dev_clk_regs.dev_clk_ns_l); /* Read the system timestamp post PHC read */ ptp_read_system_postts(sts); - lo = readl(ptp->dev_clk_regs.dev_clk_ns_l); hi = readl(ptp->dev_clk_regs.dev_clk_ns_h); spin_unlock(&ptp->read_dev_clk_lock); From 79912b256e14054e6ba177d7e7e631485ce23dbe Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 19 Jan 2026 00:41:54 +0000 Subject: [PATCH 409/443] net: phy: intel-xway: fix OF node refcount leakage Automated review spotted am OF node reference count leakage when checking if the 'leds' child node exists. Call of_put_node() to correctly maintain the refcount. Link: https://netdev-ai.bots.linux.dev/ai-review.html?id=20f173ba-0c64-422b-a663-fea4b4ad01d0 Fixes: 1758af47b98c1 ("net: phy: intel-xway: add support for PHY LEDs") Signed-off-by: Daniel Golle Link: https://patch.msgid.link/e3275e1c1cdca7e6426bb9c11f33bd84b8d900c8.1768783208.git.daniel@makrotopia.org Signed-off-by: Jakub Kicinski --- drivers/net/phy/intel-xway.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/intel-xway.c b/drivers/net/phy/intel-xway.c index 9766dd99afaa..12ff4c1f285d 100644 --- a/drivers/net/phy/intel-xway.c +++ b/drivers/net/phy/intel-xway.c @@ -277,7 +277,7 @@ static int xway_gphy_init_leds(struct phy_device *phydev) static int xway_gphy_config_init(struct phy_device *phydev) { - struct device_node *np = phydev->mdio.dev.of_node; + struct device_node *np; int err; /* Mask all interrupts */ @@ -286,7 +286,10 @@ static int xway_gphy_config_init(struct phy_device *phydev) return err; /* Use default LED configuration if 'leds' node isn't defined */ - if (!of_get_child_by_name(np, "leds")) + np = of_get_child_by_name(phydev->mdio.dev.of_node, "leds"); + if (np) + of_node_put(np); + else xway_gphy_init_leds(phydev); /* Clear all pending interrupts */ From a9f470594c50ab1ddf25b21a00ca4d3166057f3b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 18 Jan 2026 10:48:23 +0100 Subject: [PATCH 410/443] nfc: MAINTAINERS: Orphan the NFC and look for new maintainers NFC stack in Linux is in poor shape, with several bugs being discovered last years via fuzzing, not much new development happening and limited review and testing. It requires some more effort than drive-by reviews I have been offering last one or two years. I don't have much time nor business interests to keep looking at NFC, so let's drop me from the maintainers to clearly indicate that more hands are needed. Acked-by: Mark Greer Signed-off-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260118094822.10126-2-krzysztof.kozlowski@oss.qualcomm.com Signed-off-by: Jakub Kicinski --- CREDITS | 4 ++++ MAINTAINERS | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CREDITS b/CREDITS index 383809bc4b7a..ec8a2acf1947 100644 --- a/CREDITS +++ b/CREDITS @@ -2231,6 +2231,10 @@ S: Markham, Ontario S: L3R 8B2 S: Canada +N: Krzysztof Kozlowski +E: krzk@kernel.org +D: NFC network subsystem and drivers maintainer + N: Christian Krafft D: PowerPC Cell support diff --git a/MAINTAINERS b/MAINTAINERS index 61bc5c566552..69be4c98e43e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18481,9 +18481,8 @@ F: include/uapi/linux/nexthop.h F: net/ipv4/nexthop.c NFC SUBSYSTEM -M: Krzysztof Kozlowski L: netdev@vger.kernel.org -S: Maintained +S: Orphan F: Documentation/devicetree/bindings/net/nfc/ F: drivers/nfc/ F: include/net/nfc/ From a917cd0a23fae160a85b0e8a0dd1d548c5d5242e Mon Sep 17 00:00:00 2001 From: Michel Lind Date: Fri, 16 Jan 2026 21:21:58 +0000 Subject: [PATCH 411/443] tools/net/ynl: Makefile's install target now installs ynltool This tool is built by default, but was not being installed by default when running `make install`. Fix this by calling ynltool's install target. Signed-off-by: Michel Lind Link: https://patch.msgid.link/aWqr9gUT4hWZwwcI@mbp-m3-fedora.vm Signed-off-by: Jakub Kicinski --- tools/net/ynl/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/Makefile b/tools/net/ynl/Makefile index c2f3e8b3f2ac..9b692f368be7 100644 --- a/tools/net/ynl/Makefile +++ b/tools/net/ynl/Makefile @@ -41,7 +41,7 @@ clean distclean: rm -rf pyynl.egg-info rm -rf build -install: libynl.a lib/*.h +install: libynl.a lib/*.h ynltool @echo -e "\tINSTALL libynl.a" @$(INSTALL) -d $(DESTDIR)$(libdir) @$(INSTALL) -m 0644 libynl.a $(DESTDIR)$(libdir)/libynl.a @@ -51,6 +51,7 @@ install: libynl.a lib/*.h @echo -e "\tINSTALL pyynl" @pip install --prefix=$(DESTDIR)$(prefix) . @make -C generated install + @make -C ynltool install run_tests: @$(MAKE) -C tests run_tests From 748a81c8ceda1fdbdcd0af595947422e810442aa Mon Sep 17 00:00:00 2001 From: David Yang Date: Tue, 20 Jan 2026 00:07:37 +0800 Subject: [PATCH 412/443] net: hns3: fix data race in hns3_fetch_stats In hns3_fetch_stats(), ring statistics, protected by u64_stats_sync, are read and accumulated in ignorance of possible u64_stats_fetch_retry() events. These statistics are already accumulated by hns3_ring_stats_update(). Fix this by reading them into a temporary buffer first. Fixes: b20d7fe51e0d ("net: hns3: add some statitics info to tx process") Signed-off-by: David Yang Link: https://patch.msgid.link/20260119160759.1455950-1-mmyangfl@gmail.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/hisilicon/hns3/hns3_enet.c | 69 ++++++++++--------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 7a0654e2d3dd..7a9573dcab74 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2529,44 +2529,47 @@ static netdev_features_t hns3_features_check(struct sk_buff *skb, static void hns3_fetch_stats(struct rtnl_link_stats64 *stats, struct hns3_enet_ring *ring, bool is_tx) { + struct ring_stats ring_stats; unsigned int start; do { start = u64_stats_fetch_begin(&ring->syncp); - if (is_tx) { - stats->tx_bytes += ring->stats.tx_bytes; - stats->tx_packets += ring->stats.tx_pkts; - stats->tx_dropped += ring->stats.sw_err_cnt; - stats->tx_dropped += ring->stats.tx_vlan_err; - stats->tx_dropped += ring->stats.tx_l4_proto_err; - stats->tx_dropped += ring->stats.tx_l2l3l4_err; - stats->tx_dropped += ring->stats.tx_tso_err; - stats->tx_dropped += ring->stats.over_max_recursion; - stats->tx_dropped += ring->stats.hw_limitation; - stats->tx_dropped += ring->stats.copy_bits_err; - stats->tx_dropped += ring->stats.skb2sgl_err; - stats->tx_dropped += ring->stats.map_sg_err; - stats->tx_errors += ring->stats.sw_err_cnt; - stats->tx_errors += ring->stats.tx_vlan_err; - stats->tx_errors += ring->stats.tx_l4_proto_err; - stats->tx_errors += ring->stats.tx_l2l3l4_err; - stats->tx_errors += ring->stats.tx_tso_err; - stats->tx_errors += ring->stats.over_max_recursion; - stats->tx_errors += ring->stats.hw_limitation; - stats->tx_errors += ring->stats.copy_bits_err; - stats->tx_errors += ring->stats.skb2sgl_err; - stats->tx_errors += ring->stats.map_sg_err; - } else { - stats->rx_bytes += ring->stats.rx_bytes; - stats->rx_packets += ring->stats.rx_pkts; - stats->rx_dropped += ring->stats.l2_err; - stats->rx_errors += ring->stats.l2_err; - stats->rx_errors += ring->stats.l3l4_csum_err; - stats->rx_crc_errors += ring->stats.l2_err; - stats->multicast += ring->stats.rx_multicast; - stats->rx_length_errors += ring->stats.err_pkt_len; - } + ring_stats = ring->stats; } while (u64_stats_fetch_retry(&ring->syncp, start)); + + if (is_tx) { + stats->tx_bytes += ring_stats.tx_bytes; + stats->tx_packets += ring_stats.tx_pkts; + stats->tx_dropped += ring_stats.sw_err_cnt; + stats->tx_dropped += ring_stats.tx_vlan_err; + stats->tx_dropped += ring_stats.tx_l4_proto_err; + stats->tx_dropped += ring_stats.tx_l2l3l4_err; + stats->tx_dropped += ring_stats.tx_tso_err; + stats->tx_dropped += ring_stats.over_max_recursion; + stats->tx_dropped += ring_stats.hw_limitation; + stats->tx_dropped += ring_stats.copy_bits_err; + stats->tx_dropped += ring_stats.skb2sgl_err; + stats->tx_dropped += ring_stats.map_sg_err; + stats->tx_errors += ring_stats.sw_err_cnt; + stats->tx_errors += ring_stats.tx_vlan_err; + stats->tx_errors += ring_stats.tx_l4_proto_err; + stats->tx_errors += ring_stats.tx_l2l3l4_err; + stats->tx_errors += ring_stats.tx_tso_err; + stats->tx_errors += ring_stats.over_max_recursion; + stats->tx_errors += ring_stats.hw_limitation; + stats->tx_errors += ring_stats.copy_bits_err; + stats->tx_errors += ring_stats.skb2sgl_err; + stats->tx_errors += ring_stats.map_sg_err; + } else { + stats->rx_bytes += ring_stats.rx_bytes; + stats->rx_packets += ring_stats.rx_pkts; + stats->rx_dropped += ring_stats.l2_err; + stats->rx_errors += ring_stats.l2_err; + stats->rx_errors += ring_stats.l3l4_csum_err; + stats->rx_crc_errors += ring_stats.l2_err; + stats->multicast += ring_stats.rx_multicast; + stats->rx_length_errors += ring_stats.err_pkt_len; + } } static void hns3_nic_get_stats64(struct net_device *netdev, From 5fbe395cd1fdbc883584e7f38369e4ba5ca778d2 Mon Sep 17 00:00:00 2001 From: David Yang Date: Tue, 20 Jan 2026 00:27:16 +0800 Subject: [PATCH 413/443] idpf: Fix data race in idpf_net_dim In idpf_net_dim(), some statistics protected by u64_stats_sync, are read and accumulated in ignorance of possible u64_stats_fetch_retry() events. The correct way to copy statistics is already illustrated by idpf_add_queue_stats(). Fix this by reading them into temporary variables first. Fixes: c2d548cad150 ("idpf: add TX splitq napi poll support") Fixes: 3a8845af66ed ("idpf: add RX splitq napi poll support") Signed-off-by: David Yang Reviewed-by: Eric Dumazet Link: https://patch.msgid.link/20260119162720.1463859-1-mmyangfl@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 7f3933ca9edc..f58f616d87fc 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -3941,7 +3941,7 @@ static void idpf_update_dim_sample(struct idpf_q_vector *q_vector, static void idpf_net_dim(struct idpf_q_vector *q_vector) { struct dim_sample dim_sample = { }; - u64 packets, bytes; + u64 packets, bytes, pkts, bts; u32 i; if (!IDPF_ITR_IS_DYNAMIC(q_vector->tx_intr_mode)) @@ -3953,9 +3953,12 @@ static void idpf_net_dim(struct idpf_q_vector *q_vector) do { start = u64_stats_fetch_begin(&txq->stats_sync); - packets += u64_stats_read(&txq->q_stats.packets); - bytes += u64_stats_read(&txq->q_stats.bytes); + pkts = u64_stats_read(&txq->q_stats.packets); + bts = u64_stats_read(&txq->q_stats.bytes); } while (u64_stats_fetch_retry(&txq->stats_sync, start)); + + packets += pkts; + bytes += bts; } idpf_update_dim_sample(q_vector, &dim_sample, &q_vector->tx_dim, @@ -3972,9 +3975,12 @@ check_rx_itr: do { start = u64_stats_fetch_begin(&rxq->stats_sync); - packets += u64_stats_read(&rxq->q_stats.packets); - bytes += u64_stats_read(&rxq->q_stats.bytes); + pkts = u64_stats_read(&rxq->q_stats.packets); + bts = u64_stats_read(&rxq->q_stats.bytes); } while (u64_stats_fetch_retry(&rxq->stats_sync, start)); + + packets += pkts; + bytes += bts; } idpf_update_dim_sample(q_vector, &dim_sample, &q_vector->rx_dim, From 302e5b481caa7b3d11ec0e058434c1fc95195e50 Mon Sep 17 00:00:00 2001 From: David Yang Date: Mon, 19 Jan 2026 23:34:36 +0800 Subject: [PATCH 414/443] be2net: fix data race in be_get_new_eqd In be_get_new_eqd(), statistics of pkts, protected by u64_stats_sync, are read and accumulated in ignorance of possible u64_stats_fetch_retry() events. Before the commit in question, these statistics were retrieved one by one directly from queues. Fix this by reading them into temporary variables first. Fixes: 209477704187 ("be2net: set interrupt moderation for Skyhawk-R using EQ-DB") Signed-off-by: David Yang Reviewed-by: Vadim Fedorenko Link: https://patch.msgid.link/20260119153440.1440578-1-mmyangfl@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/emulex/benet/be_main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 5bb31c8fab39..995c159003d7 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -2141,7 +2141,7 @@ static int be_get_new_eqd(struct be_eq_obj *eqo) struct be_aic_obj *aic; struct be_rx_obj *rxo; struct be_tx_obj *txo; - u64 rx_pkts = 0, tx_pkts = 0; + u64 rx_pkts = 0, tx_pkts = 0, pkts; ulong now; u32 pps, delta; int i; @@ -2157,15 +2157,17 @@ static int be_get_new_eqd(struct be_eq_obj *eqo) for_all_rx_queues_on_eq(adapter, eqo, rxo, i) { do { start = u64_stats_fetch_begin(&rxo->stats.sync); - rx_pkts += rxo->stats.rx_pkts; + pkts = rxo->stats.rx_pkts; } while (u64_stats_fetch_retry(&rxo->stats.sync, start)); + rx_pkts += pkts; } for_all_tx_queues_on_eq(adapter, eqo, txo, i) { do { start = u64_stats_fetch_begin(&txo->stats.sync); - tx_pkts += txo->stats.tx_reqs; + pkts = txo->stats.tx_reqs; } while (u64_stats_fetch_retry(&txo->stats.sync, start)); + tx_pkts += pkts; } /* Skip, if wrapped around or first calculation */ From 5228e9faaed4e55f6291e1bd138bffea90252fbd Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Mon, 19 Jan 2026 14:21:36 +0000 Subject: [PATCH 415/443] net: stmmac: fix resume: calculate tso last_segment Tao Wang reports that sometimes, after resume, stmmac can watchdog: NETDEV WATCHDOG: CPU: x: transmit queue x timed out xx ms When this occurs, the DMA transmit descriptors contain: eth0: 221 [0x0000000876d10dd0]: 0x73660cbe 0x8 0x42 0xb04416a0 eth0: 222 [0x0000000876d10de0]: 0x77731d40 0x8 0x16a0 0x90000000 where descriptor 221 is the TSO header and 222 is the TSO payload. tdes3 for descriptor 221 (0xb04416a0) has both bit 29 (first descriptor) and bit 28 (last descriptor) set, which is incorrect. The following packet also has bit 28 set, but isn't marked as a first descriptor, and this causes the transmit DMA to stall. This occurs because stmmac_tso_allocator() populates the first descriptor, but does not set .last_segment correctly. There are two places where this matters: one is later in stmmac_tso_xmit() where we use it to update the TSO header descriptor. The other is in the ring/chain mode clean_desc3() which is a performance optimisation. Rather than using tx_q->tx_skbuff_dma[].last_segment to determine whether the first descriptor entry is the only segment, calculate the number of descriptor entries used. If there is only one descriptor, then the first is also the last, so mark it as such. Further work will be necessary to either eliminate .last_segment entirely or set it correctly. Code analysis also indicates that a similar issue exists with .is_jumbo. These will be the subject of a future patch. Reported-by: Tao Wang Fixes: c2837423cb54 ("net: stmmac: Rework TX Coalesce logic") Signed-off-by: Russell King (Oracle) Link: https://patch.msgid.link/E1vhq8O-00000005N5s-0Ke5@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index b3730312aeed..3f42843cd9ed 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4359,11 +4359,11 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) unsigned int first_entry, tx_packets; struct stmmac_txq_stats *txq_stats; struct stmmac_tx_queue *tx_q; + bool set_ic, is_last_segment; u32 pay_len, mss, queue; int i, first_tx, nfrags; u8 proto_hdr_len, hdr; dma_addr_t des; - bool set_ic; /* Always insert VLAN tag to SKB payload for TSO frames. * @@ -4551,10 +4551,16 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) stmmac_enable_tx_timestamp(priv, first); } + /* If we only have one entry used, then the first entry is the last + * segment. + */ + is_last_segment = ((tx_q->cur_tx - first_entry) & + (priv->dma_conf.dma_tx_size - 1)) == 1; + /* Complete the first descriptor before granting the DMA */ stmmac_prepare_tso_tx_desc(priv, first, 1, proto_hdr_len, 0, 1, - tx_q->tx_skbuff_dma[first_entry].last_segment, - hdr / 4, (skb->len - proto_hdr_len)); + is_last_segment, hdr / 4, + skb->len - proto_hdr_len); /* If context desc is used to change MSS */ if (mss_desc) { From d57c67c956a1bad15115eba6e59d77a6dfeba01d Mon Sep 17 00:00:00 2001 From: Jijie Shao Date: Mon, 19 Jan 2026 21:28:39 +0800 Subject: [PATCH 416/443] net: hns3: fix wrong GENMASK() for HCLGE_FD_AD_COUNTER_NUM_M HCLGE_FD_AD_COUNTER_NUM_M should be at GENMASK(19, 13), rather than at GENMASK(20, 13), because bit 20 is HCLGE_FD_AD_NXT_STEP_B. This patch corrects the wrong definition. Fixes: 117328680288 ("net: hns3: Add input key and action config support for flow director") Signed-off-by: Jijie Shao Link: https://patch.msgid.link/20260119132840.410513-2-shaojijie@huawei.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 9bb708fa42f2..416e02e7b995 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -731,7 +731,7 @@ struct hclge_fd_tcam_config_3_cmd { #define HCLGE_FD_AD_QID_M GENMASK(11, 2) #define HCLGE_FD_AD_USE_COUNTER_B 12 #define HCLGE_FD_AD_COUNTER_NUM_S 13 -#define HCLGE_FD_AD_COUNTER_NUM_M GENMASK(20, 13) +#define HCLGE_FD_AD_COUNTER_NUM_M GENMASK(19, 13) #define HCLGE_FD_AD_NXT_STEP_B 20 #define HCLGE_FD_AD_NXT_KEY_S 21 #define HCLGE_FD_AD_NXT_KEY_M GENMASK(25, 21) From f87e034d16e43af984380a95c32c25201b7759a7 Mon Sep 17 00:00:00 2001 From: Jijie Shao Date: Mon, 19 Jan 2026 21:28:40 +0800 Subject: [PATCH 417/443] net: hns3: fix the HCLGE_FD_AD_NXT_KEY error setting issue Use next_input_key instead of counter_id to set HCLGE_FD_AD_NXT_KEY. Fixes: 117328680288 ("net: hns3: Add input key and action config support for flow director") Signed-off-by: Jijie Shao Link: https://patch.msgid.link/20260119132840.410513-3-shaojijie@huawei.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index c589baea7c77..b8e2aa19f9e6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5690,7 +5690,7 @@ static int hclge_fd_ad_config(struct hclge_dev *hdev, u8 stage, int loc, HCLGE_FD_AD_COUNTER_NUM_S, action->counter_id); hnae3_set_bit(ad_data, HCLGE_FD_AD_NXT_STEP_B, action->use_next_stage); hnae3_set_field(ad_data, HCLGE_FD_AD_NXT_KEY_M, HCLGE_FD_AD_NXT_KEY_S, - action->counter_id); + action->next_input_key); req->ad_data = cpu_to_le64(ad_data); ret = hclge_cmd_send(&hdev->hw, &desc, 1); From 3d778e65b4f44c6af4901d83020bb8a0a010f39e Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Mon, 19 Jan 2026 14:59:35 +0800 Subject: [PATCH 418/443] net: txgbe: remove the redundant data return in SW-FW mailbox For these two firmware mailbox commands, in txgbe_test_hostif() and txgbe_set_phy_link_hostif(), there is no need to read data from the buffer. Under the current setting, OEM firmware will cause the driver to fail to probe. Because OEM firmware returns more link information, with a larger OEM structure txgbe_hic_ephy_getlink. However, the current driver does not support the OEM function. So just fix it in the way that does not involve reading the returned data. Fixes: d84a3ff9aae8 ("net: txgbe: Restrict the use of mismatched FW versions") Cc: stable@vger.kernel.org Signed-off-by: Jiawen Wu Link: https://patch.msgid.link/2914AB0BC6158DDA+20260119065935.6015-1-jiawenwu@trustnetic.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c index 62d7f47d4f8d..f0514251d4f3 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c @@ -70,7 +70,7 @@ int txgbe_test_hostif(struct wx *wx) buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED; return wx_host_interface_command(wx, (u32 *)&buffer, sizeof(buffer), - WX_HI_COMMAND_TIMEOUT, true); + WX_HI_COMMAND_TIMEOUT, false); } int txgbe_read_eeprom_hostif(struct wx *wx, @@ -148,7 +148,7 @@ static int txgbe_set_phy_link_hostif(struct wx *wx, int speed, int autoneg, int buffer.duplex = duplex; return wx_host_interface_command(wx, (u32 *)&buffer, sizeof(buffer), - WX_HI_COMMAND_TIMEOUT, true); + WX_HI_COMMAND_TIMEOUT, false); } static void txgbe_get_link_capabilities(struct wx *wx, int *speed, From 8175dbf174d487afab81e936a862a8d9b8a1ccb6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 18 Jan 2026 13:25:28 +0000 Subject: [PATCH 419/443] mISDN: annotate data-race around dev->work dev->work can re read locklessly in mISDN_read() and mISDN_poll(). Add READ_ONCE()/WRITE_ONCE() annotations. BUG: KCSAN: data-race in mISDN_ioctl / mISDN_read write to 0xffff88812d848280 of 4 bytes by task 10864 on cpu 1: misdn_add_timer drivers/isdn/mISDN/timerdev.c:175 [inline] mISDN_ioctl+0x2fb/0x550 drivers/isdn/mISDN/timerdev.c:233 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:597 [inline] __se_sys_ioctl+0xce/0x140 fs/ioctl.c:583 __x64_sys_ioctl+0x43/0x50 fs/ioctl.c:583 x64_sys_call+0x14b0/0x3000 arch/x86/include/generated/asm/syscalls_64.h:17 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xd8/0x2c0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f read to 0xffff88812d848280 of 4 bytes by task 10857 on cpu 0: mISDN_read+0x1f2/0x470 drivers/isdn/mISDN/timerdev.c:112 do_loop_readv_writev fs/read_write.c:847 [inline] vfs_readv+0x3fb/0x690 fs/read_write.c:1020 do_readv+0xe7/0x210 fs/read_write.c:1080 __do_sys_readv fs/read_write.c:1165 [inline] __se_sys_readv fs/read_write.c:1162 [inline] __x64_sys_readv+0x45/0x50 fs/read_write.c:1162 x64_sys_call+0x2831/0x3000 arch/x86/include/generated/asm/syscalls_64.h:20 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xd8/0x2c0 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f value changed: 0x00000000 -> 0x00000001 Fixes: 1b2b03f8e514 ("Add mISDN core files") Reported-by: syzbot Signed-off-by: Eric Dumazet Link: https://patch.msgid.link/20260118132528.2349573-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- drivers/isdn/mISDN/timerdev.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c index df98144a9539..33521c328a82 100644 --- a/drivers/isdn/mISDN/timerdev.c +++ b/drivers/isdn/mISDN/timerdev.c @@ -109,14 +109,14 @@ mISDN_read(struct file *filep, char __user *buf, size_t count, loff_t *off) spin_unlock_irq(&dev->lock); if (filep->f_flags & O_NONBLOCK) return -EAGAIN; - wait_event_interruptible(dev->wait, (dev->work || + wait_event_interruptible(dev->wait, (READ_ONCE(dev->work) || !list_empty(list))); if (signal_pending(current)) return -ERESTARTSYS; spin_lock_irq(&dev->lock); } if (dev->work) - dev->work = 0; + WRITE_ONCE(dev->work, 0); if (!list_empty(list)) { timer = list_first_entry(list, struct mISDNtimer, list); list_del(&timer->list); @@ -141,13 +141,16 @@ mISDN_poll(struct file *filep, poll_table *wait) if (*debug & DEBUG_TIMER) printk(KERN_DEBUG "%s(%p, %p)\n", __func__, filep, wait); if (dev) { + u32 work; + poll_wait(filep, &dev->wait, wait); mask = 0; - if (dev->work || !list_empty(&dev->expired)) + work = READ_ONCE(dev->work); + if (work || !list_empty(&dev->expired)) mask |= (EPOLLIN | EPOLLRDNORM); if (*debug & DEBUG_TIMER) printk(KERN_DEBUG "%s work(%d) empty(%d)\n", __func__, - dev->work, list_empty(&dev->expired)); + work, list_empty(&dev->expired)); } return mask; } @@ -172,7 +175,7 @@ misdn_add_timer(struct mISDNtimerdev *dev, int timeout) struct mISDNtimer *timer; if (!timeout) { - dev->work = 1; + WRITE_ONCE(dev->work, 1); wake_up_interruptible(&dev->wait); id = 0; } else { From 9a063f96d87efc3a6cc667f8de096a3d38d74bb5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 18 Jan 2026 15:29:41 +0000 Subject: [PATCH 420/443] ipv6: annotate data-race in ndisc_router_discovery() syzbot found that ndisc_router_discovery() could read and write in6_dev->ra_mtu without holding a lock [1] This looks fine, IFLA_INET6_RA_MTU is best effort. Add READ_ONCE()/WRITE_ONCE() to document the race. Note that we might also reject illegal MTU values (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) in a future patch. [1] BUG: KCSAN: data-race in ndisc_router_discovery / ndisc_router_discovery read to 0xffff888119809c20 of 4 bytes by task 25817 on cpu 1: ndisc_router_discovery+0x151d/0x1c90 net/ipv6/ndisc.c:1558 ndisc_rcv+0x2ad/0x3d0 net/ipv6/ndisc.c:1841 icmpv6_rcv+0xe5a/0x12f0 net/ipv6/icmp.c:989 ip6_protocol_deliver_rcu+0xb2a/0x10d0 net/ipv6/ip6_input.c:438 ip6_input_finish+0xf0/0x1d0 net/ipv6/ip6_input.c:489 NF_HOOK include/linux/netfilter.h:318 [inline] ip6_input+0x5e/0x140 net/ipv6/ip6_input.c:500 ip6_mc_input+0x27c/0x470 net/ipv6/ip6_input.c:590 dst_input include/net/dst.h:474 [inline] ip6_rcv_finish+0x336/0x340 net/ipv6/ip6_input.c:79 ... write to 0xffff888119809c20 of 4 bytes by task 25816 on cpu 0: ndisc_router_discovery+0x155a/0x1c90 net/ipv6/ndisc.c:1559 ndisc_rcv+0x2ad/0x3d0 net/ipv6/ndisc.c:1841 icmpv6_rcv+0xe5a/0x12f0 net/ipv6/icmp.c:989 ip6_protocol_deliver_rcu+0xb2a/0x10d0 net/ipv6/ip6_input.c:438 ip6_input_finish+0xf0/0x1d0 net/ipv6/ip6_input.c:489 NF_HOOK include/linux/netfilter.h:318 [inline] ip6_input+0x5e/0x140 net/ipv6/ip6_input.c:500 ip6_mc_input+0x27c/0x470 net/ipv6/ip6_input.c:590 dst_input include/net/dst.h:474 [inline] ip6_rcv_finish+0x336/0x340 net/ipv6/ip6_input.c:79 ... value changed: 0x00000000 -> 0xe5400659 Fixes: 49b99da2c9ce ("ipv6: add IFLA_INET6_RA_MTU to expose mtu value") Reported-by: syzbot Signed-off-by: Eric Dumazet Cc: Rocco Yue Link: https://patch.msgid.link/20260118152941.2563857-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/ipv6/ndisc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 59d17b6f06bf..f6a5d8c73af9 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1555,8 +1555,8 @@ skip_routeinfo: memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu)); mtu = ntohl(n); - if (in6_dev->ra_mtu != mtu) { - in6_dev->ra_mtu = mtu; + if (READ_ONCE(in6_dev->ra_mtu) != mtu) { + WRITE_ONCE(in6_dev->ra_mtu, mtu); send_ifinfo_notify = true; } From c7159e960f1472a5493ac99aff0086ab1d683594 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Mon, 19 Jan 2026 08:55:18 +0100 Subject: [PATCH 421/443] usbnet: limit max_mtu based on device's hard_mtu The usbnet driver initializes net->max_mtu to ETH_MAX_MTU before calling the device's bind() callback. When the bind() callback sets dev->hard_mtu based the device's actual capability (from CDC Ethernet's wMaxSegmentSize descriptor), max_mtu is never updated to reflect this hardware limitation). This allows userspace (DHCP or IPv6 RA) to configure MTU larger than the device can handle, leading to silent packet drops when the backend sends packet exceeding the device's buffer size. Fix this by limiting net->max_mtu to the device's hard_mtu after the bind callback returns. See https://gitlab.com/qemu-project/qemu/-/issues/3268 and https://bugs.passt.top/attachment.cgi?bugid=189 Fixes: f77f0aee4da4 ("net: use core MTU range checking in USB NIC drivers") Signed-off-by: Laurent Vivier Link: https://bugs.passt.top/show_bug.cgi?id=189 Reviewed-by: Stefano Brivio Link: https://patch.msgid.link/20260119075518.2774373-1-lvivier@redhat.com Signed-off-by: Jakub Kicinski --- drivers/net/usb/usbnet.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 35789ff4dd55..9280ef544bbb 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1821,9 +1821,12 @@ usbnet_probe(struct usb_interface *udev, const struct usb_device_id *prod) if ((dev->driver_info->flags & FLAG_NOARP) != 0) net->flags |= IFF_NOARP; - /* maybe the remote can't receive an Ethernet MTU */ - if (net->mtu > (dev->hard_mtu - net->hard_header_len)) - net->mtu = dev->hard_mtu - net->hard_header_len; + if (net->max_mtu > (dev->hard_mtu - net->hard_header_len)) + net->max_mtu = dev->hard_mtu - net->hard_header_len; + + if (net->mtu > net->max_mtu) + net->mtu = net->max_mtu; + } else if (!info->in || !info->out) status = usbnet_get_endpoints(dev, udev); else { From cdf8de9c6bfe94508d251cb290ee66e34e6f3368 Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Mon, 19 Jan 2026 15:32:22 +0530 Subject: [PATCH 422/443] Octeontx2-pf: Update xdp features In recent testing, verification of XDP_REDIRECT and zero-copy features failed because the driver is not setting the corresponding feature flags. Fixes: efabce290151 ("octeontx2-pf: AF_XDP zero copy receive support") Fixes: 66c0e13ad236 ("drivers: net: turn on XDP features") Signed-off-by: Hariprasad Kelam Link: https://patch.msgid.link/20260119100222.2267925-1-hkelam@marvell.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c index a7feb4c392b3..6b2d8559f0eb 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c @@ -3249,7 +3249,9 @@ static int otx2_probe(struct pci_dev *pdev, const struct pci_device_id *id) netdev->watchdog_timeo = OTX2_TX_TIMEOUT; netdev->netdev_ops = &otx2_netdev_ops; - netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT; + netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_NDO_XMIT | + NETDEV_XDP_ACT_XSK_ZEROCOPY; netdev->min_mtu = OTX2_MIN_MTU; netdev->max_mtu = otx2_get_max_mtu(pf); From ba1096c315283ee3292765f6aea4cca15816c4f7 Mon Sep 17 00:00:00 2001 From: Jeongjun Park Date: Mon, 19 Jan 2026 15:33:59 +0900 Subject: [PATCH 423/443] netrom: fix double-free in nr_route_frame() In nr_route_frame(), old_skb is immediately freed without checking if nr_neigh->ax25 pointer is NULL. Therefore, if nr_neigh->ax25 is NULL, the caller function will free old_skb again, causing a double-free bug. Therefore, to prevent this, we need to modify it to check whether nr_neigh->ax25 is NULL before freeing old_skb. Cc: Reported-by: syzbot+999115c3bf275797dc27@syzkaller.appspotmail.com Closes: https://lore.kernel.org/all/69694d6f.050a0220.58bed.0029.GAE@google.com/ Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Jeongjun Park Link: https://patch.msgid.link/20260119063359.10604-1-aha310510@gmail.com Signed-off-by: Jakub Kicinski --- net/netrom/nr_route.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c index b94cb2ffbaf8..9cc29ae85b06 100644 --- a/net/netrom/nr_route.c +++ b/net/netrom/nr_route.c @@ -752,7 +752,7 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25) unsigned char *dptr; ax25_cb *ax25s; int ret; - struct sk_buff *skbn; + struct sk_buff *nskb, *oskb; /* * Reject malformed packets early. Check that it contains at least 2 @@ -811,14 +811,16 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25) /* We are going to change the netrom headers so we should get our own skb, we also did not know until now how much header space we had to reserve... - RXQ */ - if ((skbn=skb_copy_expand(skb, dev->hard_header_len, 0, GFP_ATOMIC)) == NULL) { + nskb = skb_copy_expand(skb, dev->hard_header_len, 0, GFP_ATOMIC); + + if (!nskb) { nr_node_unlock(nr_node); nr_node_put(nr_node); dev_put(dev); return 0; } - kfree_skb(skb); - skb=skbn; + oskb = skb; + skb = nskb; skb->data[14]--; dptr = skb_push(skb, 1); @@ -837,6 +839,9 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25) nr_node_unlock(nr_node); nr_node_put(nr_node); + if (ret) + kfree_skb(oskb); + return ret; } From 99a3e3a1cfc93b8fe318c0a3a5cfb01f1d4ad53c Mon Sep 17 00:00:00 2001 From: Swaraj Gaikwad Date: Tue, 13 Jan 2026 20:36:39 +0530 Subject: [PATCH 424/443] slab: fix kmalloc_nolock() context check for PREEMPT_RT On PREEMPT_RT kernels, local_lock becomes a sleeping lock. The current check in kmalloc_nolock() only verifies we're not in NMI or hard IRQ context, but misses the case where preemption is disabled. When a BPF program runs from a tracepoint with preemption disabled (preempt_count > 0), kmalloc_nolock() proceeds to call local_lock_irqsave() which attempts to acquire a sleeping lock, triggering: BUG: sleeping function called from invalid context in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 6128 preempt_count: 2, expected: 0 Fix this by checking !preemptible() on PREEMPT_RT, which directly expresses the constraint that we cannot take a sleeping lock when preemption is disabled. This encompasses the previous checks for NMI and hard IRQ contexts while also catching cases where preemption is disabled. Fixes: af92793e52c3 ("slab: Introduce kmalloc_nolock() and kfree_nolock().") Reported-by: syzbot+b1546ad4a95331b2101e@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=b1546ad4a95331b2101e Signed-off-by: Swaraj Gaikwad Acked-by: Sebastian Andrzej Siewior Acked-by: Alexei Starovoitov Acked-by: Harry Yoo Link: https://patch.msgid.link/20260113150639.48407-1-swarajgaikwad1925@gmail.co Cc: Signed-off-by: Vlastimil Babka --- mm/slub.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index 861592ac5425..f77b7407c51b 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -5694,8 +5694,12 @@ void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node) if (unlikely(!size)) return ZERO_SIZE_PTR; - if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq())) - /* kmalloc_nolock() in PREEMPT_RT is not supported from irq */ + if (IS_ENABLED(CONFIG_PREEMPT_RT) && !preemptible()) + /* + * kmalloc_nolock() in PREEMPT_RT is not supported from + * non-preemptible context because local_lock becomes a + * sleeping lock on RT. + */ return NULL; retry: if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) From 2030c4358bd8451583f2e010108607de5cdac5dc Mon Sep 17 00:00:00 2001 From: Slark Xiao Date: Tue, 20 Jan 2026 15:20:18 +0800 Subject: [PATCH 425/443] Revert "net: wwan: mhi_wwan_mbim: Avoid -Wflex-array-member-not-at-end warning" This reverts commit eeecf5d3a3a484cedfa3f2f87e6d51a7390ed960. This change lead to MHI WWAN device can't connect to internet. I found a netwrok issue with kernel 6.19-rc4, but network works well with kernel 6.18-rc1. After checking, this commit is the root cause. Before appliing this serial changes on MHI WWAN network, we shall revert this change in case of v6.19 being impacted. Fixes: eeecf5d3a3a4 ("net: wwan: mhi_wwan_mbim: Avoid -Wflex-array-member-not-at-end warning") Signed-off-by: Slark Xiao Link: https://patch.msgid.link/20260120072018.29375-1-slark_xiao@163.com Signed-off-by: Jakub Kicinski --- drivers/net/wwan/mhi_wwan_mbim.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/net/wwan/mhi_wwan_mbim.c b/drivers/net/wwan/mhi_wwan_mbim.c index 0dace12f5ad0..f8bc9a39bfa3 100644 --- a/drivers/net/wwan/mhi_wwan_mbim.c +++ b/drivers/net/wwan/mhi_wwan_mbim.c @@ -78,9 +78,8 @@ struct mhi_mbim_context { struct mbim_tx_hdr { struct usb_cdc_ncm_nth16 nth16; - - /* Must be last as it ends in a flexible-array member. */ struct usb_cdc_ncm_ndp16 ndp16; + struct usb_cdc_ncm_dpe16 dpe16[2]; } __packed; static struct mhi_mbim_link *mhi_mbim_get_link_rcu(struct mhi_mbim_context *mbim, @@ -108,20 +107,20 @@ static int mhi_mbim_get_link_mux_id(struct mhi_controller *cntrl) static struct sk_buff *mbim_tx_fixup(struct sk_buff *skb, unsigned int session, u16 tx_seq) { - DEFINE_RAW_FLEX(struct mbim_tx_hdr, mbim_hdr, ndp16.dpe16, 2); unsigned int dgram_size = skb->len; struct usb_cdc_ncm_nth16 *nth16; struct usb_cdc_ncm_ndp16 *ndp16; + struct mbim_tx_hdr *mbim_hdr; /* Only one NDP is sent, containing the IP packet (no aggregation) */ /* Ensure we have enough headroom for crafting MBIM header */ - if (skb_cow_head(skb, __struct_size(mbim_hdr))) { + if (skb_cow_head(skb, sizeof(struct mbim_tx_hdr))) { dev_kfree_skb_any(skb); return NULL; } - mbim_hdr = skb_push(skb, __struct_size(mbim_hdr)); + mbim_hdr = skb_push(skb, sizeof(struct mbim_tx_hdr)); /* Fill NTB header */ nth16 = &mbim_hdr->nth16; @@ -134,11 +133,12 @@ static struct sk_buff *mbim_tx_fixup(struct sk_buff *skb, unsigned int session, /* Fill the unique NDP */ ndp16 = &mbim_hdr->ndp16; ndp16->dwSignature = cpu_to_le32(USB_CDC_MBIM_NDP16_IPS_SIGN | (session << 24)); - ndp16->wLength = cpu_to_le16(struct_size(ndp16, dpe16, 2)); + ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + + sizeof(struct usb_cdc_ncm_dpe16) * 2); ndp16->wNextNdpIndex = 0; /* Datagram follows the mbim header */ - ndp16->dpe16[0].wDatagramIndex = cpu_to_le16(__struct_size(mbim_hdr)); + ndp16->dpe16[0].wDatagramIndex = cpu_to_le16(sizeof(struct mbim_tx_hdr)); ndp16->dpe16[0].wDatagramLength = cpu_to_le16(dgram_size); /* null termination */ @@ -584,8 +584,7 @@ static void mhi_mbim_setup(struct net_device *ndev) { ndev->header_ops = NULL; /* No header */ ndev->type = ARPHRD_RAWIP; - ndev->needed_headroom = - struct_size_t(struct mbim_tx_hdr, ndp16.dpe16, 2); + ndev->needed_headroom = sizeof(struct mbim_tx_hdr); ndev->hard_header_len = 0; ndev->addr_len = 0; ndev->flags = IFF_POINTOPOINT | IFF_NOARP; From 8215794403d264739cc676668087512950b2ff31 Mon Sep 17 00:00:00 2001 From: Andrey Vatoropin Date: Tue, 20 Jan 2026 11:37:47 +0000 Subject: [PATCH 426/443] be2net: Fix NULL pointer dereference in be_cmd_get_mac_from_list When the parameter pmac_id_valid argument of be_cmd_get_mac_from_list() is set to false, the driver may request the PMAC_ID from the firmware of the network card, and this function will store that PMAC_ID at the provided address pmac_id. This is the contract of this function. However, there is a location within the driver where both pmac_id_valid == false and pmac_id == NULL are being passed. This could result in dereferencing a NULL pointer. To resolve this issue, it is necessary to pass the address of a stub variable to the function. Fixes: 95046b927a54 ("be2net: refactor MAC-addr setup code") Signed-off-by: Andrey Vatoropin Link: https://patch.msgid.link/20260120113734.20193-1-a.vatoropin@crpt.ru Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/emulex/benet/be_cmds.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index bb5d2fa15736..8ed45bceb537 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -3801,6 +3801,7 @@ int be_cmd_get_perm_mac(struct be_adapter *adapter, u8 *mac) { int status; bool pmac_valid = false; + u32 pmac_id; eth_zero_addr(mac); @@ -3813,7 +3814,7 @@ int be_cmd_get_perm_mac(struct be_adapter *adapter, u8 *mac) adapter->if_handle, 0); } else { status = be_cmd_get_mac_from_list(adapter, mac, &pmac_valid, - NULL, adapter->if_handle, 0); + &pmac_id, adapter->if_handle, 0); } return status; From 04708606fd7bdc34b69089a4ff848ff36d7088f9 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Tue, 20 Jan 2026 13:39:30 +0000 Subject: [PATCH 427/443] selftests: net: amt: wait longer for connection before sending packets Both send_mcast4() and send_mcast6() use sleep 2 to wait for the tunnel connection between the gateway and the relay, and for the listener socket to be created in the LISTENER namespace. However, tests sometimes fail because packets are sent before the connection is fully established. Increase the waiting time to make the tests more reliable, and use wait_local_port_listen() to explicitly wait for the listener socket. Fixes: c08e8baea78e ("selftests: add amt interface selftest script") Signed-off-by: Taehee Yoo Link: https://patch.msgid.link/20260120133930.863845-1-ap420073@gmail.com Signed-off-by: Jakub Kicinski --- tools/testing/selftests/net/amt.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/amt.sh b/tools/testing/selftests/net/amt.sh index 3ef209cacb8e..663744305e52 100755 --- a/tools/testing/selftests/net/amt.sh +++ b/tools/testing/selftests/net/amt.sh @@ -73,6 +73,8 @@ # +------------------------+ #============================================================================== +source lib.sh + readonly LISTENER=$(mktemp -u listener-XXXXXXXX) readonly GATEWAY=$(mktemp -u gateway-XXXXXXXX) readonly RELAY=$(mktemp -u relay-XXXXXXXX) @@ -246,14 +248,15 @@ test_ipv6_forward() send_mcast4() { - sleep 2 + sleep 5 + wait_local_port_listen ${LISTENER} 4000 udp ip netns exec "${SOURCE}" bash -c \ 'printf "%s %128s" 172.17.0.2 | nc -w 1 -u 239.0.0.1 4000' & } send_mcast6() { - sleep 2 + wait_local_port_listen ${LISTENER} 6000 udp ip netns exec "${SOURCE}" bash -c \ 'printf "%s %128s" 2001:db8:3::2 | nc -w 1 -u ff0e::5:6 6000' & } From 5f9b329096596b7e53e07d041d7fca4cbe1be752 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 20 Jan 2026 16:17:44 +0000 Subject: [PATCH 428/443] bonding: provide a net pointer to __skb_flow_dissect() After 3cbf4ffba5ee ("net: plumb network namespace into __skb_flow_dissect") we have to provide a net pointer to __skb_flow_dissect(), either via skb->dev, skb->sk, or a user provided pointer. In the following case, syzbot was able to cook a bare skb. WARNING: net/core/flow_dissector.c:1131 at __skb_flow_dissect+0xb57/0x68b0 net/core/flow_dissector.c:1131, CPU#1: syz.2.1418/11053 Call Trace: bond_flow_dissect drivers/net/bonding/bond_main.c:4093 [inline] __bond_xmit_hash+0x2d7/0xba0 drivers/net/bonding/bond_main.c:4157 bond_xmit_hash_xdp drivers/net/bonding/bond_main.c:4208 [inline] bond_xdp_xmit_3ad_xor_slave_get drivers/net/bonding/bond_main.c:5139 [inline] bond_xdp_get_xmit_slave+0x1fd/0x710 drivers/net/bonding/bond_main.c:5515 xdp_master_redirect+0x13f/0x2c0 net/core/filter.c:4388 bpf_prog_run_xdp include/net/xdp.h:700 [inline] bpf_test_run+0x6b2/0x7d0 net/bpf/test_run.c:421 bpf_prog_test_run_xdp+0x795/0x10e0 net/bpf/test_run.c:1390 bpf_prog_test_run+0x2c7/0x340 kernel/bpf/syscall.c:4703 __sys_bpf+0x562/0x860 kernel/bpf/syscall.c:6182 __do_sys_bpf kernel/bpf/syscall.c:6274 [inline] __se_sys_bpf kernel/bpf/syscall.c:6272 [inline] __x64_sys_bpf+0x7c/0x90 kernel/bpf/syscall.c:6272 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xec/0xf80 arch/x86/entry/syscall_64.c:94 Fixes: 58deb77cc52d ("bonding: balance ICMP echoes in layer3+4 mode") Reported-by: syzbot+c46409299c70a221415e@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/696faa23.050a0220.4cb9c.001f.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Cc: Matteo Croce Acked-by: Stanislav Fomichev Link: https://patch.msgid.link/20260120161744.1893263-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- drivers/net/bonding/bond_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 0aca6c937297..e7caf400a59c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4096,8 +4096,9 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, const v case BOND_XMIT_POLICY_ENCAP23: case BOND_XMIT_POLICY_ENCAP34: memset(fk, 0, sizeof(*fk)); - return __skb_flow_dissect(NULL, skb, &flow_keys_bonding, - fk, data, l2_proto, nhoff, hlen, 0); + return __skb_flow_dissect(dev_net(bond->dev), skb, + &flow_keys_bonding, fk, data, + l2_proto, nhoff, hlen, 0); default: break; } From bbb11b8d758d17a4ce34b8ed0b49de150568265b Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Tue, 20 Jan 2026 11:23:39 -0800 Subject: [PATCH 429/443] net: bcmasp: Fix network filter wake for asp-3.0 We need to apply the tx_chan_offset to the netfilter cfg channel or the output channel will be incorrect for asp-3.0 and newer. Fixes: e9f31435ee7d ("net: bcmasp: Add support for asp-v3.0") Signed-off-by: Justin Chen Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20260120192339.2031648-1-justin.chen@broadcom.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/asp2/bcmasp.c | 5 +++-- drivers/net/ethernet/broadcom/asp2/bcmasp.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.c b/drivers/net/ethernet/broadcom/asp2/bcmasp.c index fd35f4b4dc50..014340f33345 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.c @@ -156,7 +156,7 @@ static void bcmasp_netfilt_hw_en_wake(struct bcmasp_priv *priv, ASP_RX_FILTER_NET_OFFSET_L4(32), ASP_RX_FILTER_NET_OFFSET(nfilt->hw_index + 1)); - rx_filter_core_wl(priv, ASP_RX_FILTER_NET_CFG_CH(nfilt->port + 8) | + rx_filter_core_wl(priv, ASP_RX_FILTER_NET_CFG_CH(nfilt->ch) | ASP_RX_FILTER_NET_CFG_EN | ASP_RX_FILTER_NET_CFG_L2_EN | ASP_RX_FILTER_NET_CFG_L3_EN | @@ -166,7 +166,7 @@ static void bcmasp_netfilt_hw_en_wake(struct bcmasp_priv *priv, ASP_RX_FILTER_NET_CFG_UMC(nfilt->port), ASP_RX_FILTER_NET_CFG(nfilt->hw_index)); - rx_filter_core_wl(priv, ASP_RX_FILTER_NET_CFG_CH(nfilt->port + 8) | + rx_filter_core_wl(priv, ASP_RX_FILTER_NET_CFG_CH(nfilt->ch) | ASP_RX_FILTER_NET_CFG_EN | ASP_RX_FILTER_NET_CFG_L2_EN | ASP_RX_FILTER_NET_CFG_L3_EN | @@ -714,6 +714,7 @@ struct bcmasp_net_filter *bcmasp_netfilt_get_init(struct bcmasp_intf *intf, nfilter = &priv->net_filters[open_index]; nfilter->claimed = true; nfilter->port = intf->port; + nfilter->ch = intf->channel + priv->tx_chan_offset; nfilter->hw_index = open_index; } diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.h b/drivers/net/ethernet/broadcom/asp2/bcmasp.h index 74adfdb50e11..e238507be40a 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.h +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.h @@ -348,6 +348,7 @@ struct bcmasp_net_filter { bool wake_filter; int port; + int ch; unsigned int hw_index; }; From dfca045cd4d0ea07ff4198ba392be3e718acaddc Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 20 Jan 2026 23:10:39 +0200 Subject: [PATCH 430/443] net: dsa: fix off-by-one in maximum bridge ID determination Prior to the blamed commit, the bridge_num range was from 0 to ds->max_num_bridges - 1. After the commit, it is from 1 to ds->max_num_bridges. So this check: if (bridge_num >= max) return 0; must be updated to: if (bridge_num > max) return 0; in order to allow the last bridge_num value (==max) to be used. This is easiest visible when a driver sets ds->max_num_bridges=1. The observed behaviour is that even the first created bridge triggers the netlink extack "Range of offloadable bridges exceeded" warning, and is handled in software rather than being offloaded. Fixes: 3f9bb0301d50 ("net: dsa: make dp->bridge_num one-based") Signed-off-by: Vladimir Oltean Link: https://patch.msgid.link/20260120211039.3228999-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski --- net/dsa/dsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 99ede37698ac..35ce3941fae3 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -158,7 +158,7 @@ unsigned int dsa_bridge_num_get(const struct net_device *bridge_dev, int max) bridge_num = find_next_zero_bit(&dsa_fwd_offloading_bridges, DSA_MAX_NUM_OFFLOADING_BRIDGES, 1); - if (bridge_num >= max) + if (bridge_num > max) return 0; set_bit(bridge_num, &dsa_fwd_offloading_bridges); From 5d5fe8bcd331f1e34e0943ec7c18432edfcf0e8b Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 20 Jan 2026 10:13:05 +0000 Subject: [PATCH 431/443] rxrpc: Fix data-race warning and potential load/store tearing Fix the following: BUG: KCSAN: data-race in rxrpc_peer_keepalive_worker / rxrpc_send_data_packet which is reporting an issue with the reads and writes to ->last_tx_at in: conn->peer->last_tx_at = ktime_get_seconds(); and: keepalive_at = peer->last_tx_at + RXRPC_KEEPALIVE_TIME; The lockless accesses to these to values aren't actually a problem as the read only needs an approximate time of last transmission for the purposes of deciding whether or not the transmission of a keepalive packet is warranted yet. Also, as ->last_tx_at is a 64-bit value, tearing can occur on a 32-bit arch. Fix both of these by switching to an unsigned int for ->last_tx_at and only storing the LSW of the time64_t. It can then be reconstructed at need provided no more than 68 years has elapsed since the last transmission. Fixes: ace45bec6d77 ("rxrpc: Fix firewall route keepalive") Reported-by: syzbot+6182afad5045e6703b3d@syzkaller.appspotmail.com Closes: https://lore.kernel.org/r/695e7cfb.050a0220.1c677c.036b.GAE@google.com/ Signed-off-by: David Howells cc: Marc Dionne cc: Simon Horman cc: linux-afs@lists.infradead.org cc: stable@kernel.org Link: https://patch.msgid.link/1107124.1768903985@warthog.procyon.org.uk Signed-off-by: Jakub Kicinski --- net/rxrpc/ar-internal.h | 9 ++++++++- net/rxrpc/conn_event.c | 2 +- net/rxrpc/output.c | 14 +++++++------- net/rxrpc/peer_event.c | 17 ++++++++++++++++- net/rxrpc/proc.c | 4 ++-- net/rxrpc/rxgk.c | 2 +- net/rxrpc/rxkad.c | 2 +- 7 files changed, 36 insertions(+), 14 deletions(-) diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 5b7342d43486..36d6ca0d1089 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -387,7 +387,7 @@ struct rxrpc_peer { struct rb_root service_conns; /* Service connections */ struct list_head keepalive_link; /* Link in net->peer_keepalive[] */ unsigned long app_data; /* Application data (e.g. afs_server) */ - time64_t last_tx_at; /* Last time packet sent here */ + unsigned int last_tx_at; /* Last time packet sent here (time64_t LSW) */ seqlock_t service_conn_lock; spinlock_t lock; /* access lock */ int debug_id; /* debug ID for printks */ @@ -1379,6 +1379,13 @@ void rxrpc_peer_keepalive_worker(struct work_struct *); void rxrpc_input_probe_for_pmtud(struct rxrpc_connection *conn, rxrpc_serial_t acked_serial, bool sendmsg_fail); +/* Update the last transmission time on a peer for keepalive purposes. */ +static inline void rxrpc_peer_mark_tx(struct rxrpc_peer *peer) +{ + /* To avoid tearing on 32-bit systems, we only keep the LSW. */ + WRITE_ONCE(peer->last_tx_at, ktime_get_seconds()); +} + /* * peer_object.c */ diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c index 232b6986da83..98ad9b51ca2c 100644 --- a/net/rxrpc/conn_event.c +++ b/net/rxrpc/conn_event.c @@ -194,7 +194,7 @@ void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn, } ret = kernel_sendmsg(conn->local->socket, &msg, iov, ioc, len); - conn->peer->last_tx_at = ktime_get_seconds(); + rxrpc_peer_mark_tx(conn->peer); if (ret < 0) trace_rxrpc_tx_fail(chan->call_debug_id, serial, ret, rxrpc_tx_point_call_final_resend); diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index 8b5903b6e481..d70db367e358 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -275,7 +275,7 @@ static void rxrpc_send_ack_packet(struct rxrpc_call *call, int nr_kv, size_t len rxrpc_local_dont_fragment(conn->local, why == rxrpc_propose_ack_ping_for_mtu_probe); ret = do_udp_sendmsg(conn->local->socket, &msg, len); - call->peer->last_tx_at = ktime_get_seconds(); + rxrpc_peer_mark_tx(call->peer); if (ret < 0) { trace_rxrpc_tx_fail(call->debug_id, serial, ret, rxrpc_tx_point_call_ack); @@ -411,7 +411,7 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call) iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, sizeof(pkt)); ret = do_udp_sendmsg(conn->local->socket, &msg, sizeof(pkt)); - conn->peer->last_tx_at = ktime_get_seconds(); + rxrpc_peer_mark_tx(conn->peer); if (ret < 0) trace_rxrpc_tx_fail(call->debug_id, serial, ret, rxrpc_tx_point_call_abort); @@ -698,7 +698,7 @@ void rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_send_data_req ret = 0; trace_rxrpc_tx_data(call, txb->seq, txb->serial, txb->flags, rxrpc_txdata_inject_loss); - conn->peer->last_tx_at = ktime_get_seconds(); + rxrpc_peer_mark_tx(conn->peer); goto done; } } @@ -711,7 +711,7 @@ void rxrpc_send_data_packet(struct rxrpc_call *call, struct rxrpc_send_data_req */ rxrpc_inc_stat(call->rxnet, stat_tx_data_send); ret = do_udp_sendmsg(conn->local->socket, &msg, len); - conn->peer->last_tx_at = ktime_get_seconds(); + rxrpc_peer_mark_tx(conn->peer); if (ret == -EMSGSIZE) { rxrpc_inc_stat(call->rxnet, stat_tx_data_send_msgsize); @@ -797,7 +797,7 @@ void rxrpc_send_conn_abort(struct rxrpc_connection *conn) trace_rxrpc_tx_packet(conn->debug_id, &whdr, rxrpc_tx_point_conn_abort); - conn->peer->last_tx_at = ktime_get_seconds(); + rxrpc_peer_mark_tx(conn->peer); } /* @@ -917,7 +917,7 @@ void rxrpc_send_keepalive(struct rxrpc_peer *peer) trace_rxrpc_tx_packet(peer->debug_id, &whdr, rxrpc_tx_point_version_keepalive); - peer->last_tx_at = ktime_get_seconds(); + rxrpc_peer_mark_tx(peer); _leave(""); } @@ -973,7 +973,7 @@ void rxrpc_send_response(struct rxrpc_connection *conn, struct sk_buff *response if (ret < 0) goto fail; - conn->peer->last_tx_at = ktime_get_seconds(); + rxrpc_peer_mark_tx(conn->peer); return; fail: diff --git a/net/rxrpc/peer_event.c b/net/rxrpc/peer_event.c index 7f4729234957..9d02448ac062 100644 --- a/net/rxrpc/peer_event.c +++ b/net/rxrpc/peer_event.c @@ -237,6 +237,21 @@ static void rxrpc_distribute_error(struct rxrpc_peer *peer, struct sk_buff *skb, spin_unlock_irq(&peer->lock); } +/* + * Reconstruct the last transmission time. The difference calculated should be + * valid provided no more than ~68 years elapsed since the last transmission. + */ +static time64_t rxrpc_peer_get_tx_mark(const struct rxrpc_peer *peer, time64_t base) +{ + s32 last_tx_at = READ_ONCE(peer->last_tx_at); + s32 base_lsw = base; + s32 diff = last_tx_at - base_lsw; + + diff = clamp(diff, -RXRPC_KEEPALIVE_TIME, RXRPC_KEEPALIVE_TIME); + + return diff + base; +} + /* * Perform keep-alive pings. */ @@ -265,7 +280,7 @@ static void rxrpc_peer_keepalive_dispatch(struct rxrpc_net *rxnet, spin_unlock_bh(&rxnet->peer_hash_lock); if (use) { - keepalive_at = peer->last_tx_at + RXRPC_KEEPALIVE_TIME; + keepalive_at = rxrpc_peer_get_tx_mark(peer, base) + RXRPC_KEEPALIVE_TIME; slot = keepalive_at - base; _debug("%02x peer %u t=%d {%pISp}", cursor, peer->debug_id, slot, &peer->srx.transport); diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c index d803562ca0ac..59292f7f9205 100644 --- a/net/rxrpc/proc.c +++ b/net/rxrpc/proc.c @@ -296,13 +296,13 @@ static int rxrpc_peer_seq_show(struct seq_file *seq, void *v) now = ktime_get_seconds(); seq_printf(seq, - "UDP %-47.47s %-47.47s %3u %4u %5u %6llus %8d %8d\n", + "UDP %-47.47s %-47.47s %3u %4u %5u %6ds %8d %8d\n", lbuff, rbuff, refcount_read(&peer->ref), peer->cong_ssthresh, peer->max_data, - now - peer->last_tx_at, + (s32)now - (s32)READ_ONCE(peer->last_tx_at), READ_ONCE(peer->recent_srtt_us), READ_ONCE(peer->recent_rto_us)); diff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c index dce5a3d8a964..43cbf9efd89f 100644 --- a/net/rxrpc/rxgk.c +++ b/net/rxrpc/rxgk.c @@ -678,7 +678,7 @@ static int rxgk_issue_challenge(struct rxrpc_connection *conn) ret = do_udp_sendmsg(conn->local->socket, &msg, len); if (ret > 0) - conn->peer->last_tx_at = ktime_get_seconds(); + rxrpc_peer_mark_tx(conn->peer); __free_page(page); if (ret < 0) { diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c index 3657c0661cdc..a756855a0a62 100644 --- a/net/rxrpc/rxkad.c +++ b/net/rxrpc/rxkad.c @@ -694,7 +694,7 @@ static int rxkad_issue_challenge(struct rxrpc_connection *conn) return -EAGAIN; } - conn->peer->last_tx_at = ktime_get_seconds(); + rxrpc_peer_mark_tx(conn->peer); trace_rxrpc_tx_packet(conn->debug_id, &whdr, rxrpc_tx_point_rxkad_challenge); _leave(" = 0"); From e8ca461f7d19464b47c64fe4cf2f83162421bcc0 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 21 Jan 2026 02:23:17 +0000 Subject: [PATCH 432/443] net: pcs: pcs-mtk-lynxi: report in-band capability for 2500Base-X It turns out that 2500Base-X actually works fine with in-band status on MediaTek's LynxI PCS -- I wrongly concluded it didn't because it is broken in all the copper SFP modules and GPON sticks I used for testing. Hence report LINK_INBAND_ENABLE also for 2500Base-X mode. This reverts most of commit a003c38d9bbb ("net: pcs: pcs-mtk-lynxi: correctly report in-band status capabilities"). The removal of the QSGMII interface mode was correct and is left untouched. Link: https://github.com/openwrt/openwrt/issues/21436 Fixes: a003c38d9bbb ("net: pcs: pcs-mtk-lynxi: correctly report in-band status capabilities") Signed-off-by: Daniel Golle Link: https://patch.msgid.link/b1cf26157b63fee838be09ae810497fb22fd8104.1768961746.git.daniel@makrotopia.org Signed-off-by: Jakub Kicinski --- drivers/net/pcs/pcs-mtk-lynxi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c index 149ddf51d785..87df3a9dfc9b 100644 --- a/drivers/net/pcs/pcs-mtk-lynxi.c +++ b/drivers/net/pcs/pcs-mtk-lynxi.c @@ -93,12 +93,10 @@ static unsigned int mtk_pcs_lynxi_inband_caps(struct phylink_pcs *pcs, { switch (interface) { case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: case PHY_INTERFACE_MODE_SGMII: return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE; - case PHY_INTERFACE_MODE_2500BASEX: - return LINK_INBAND_DISABLE; - default: return 0; } From 19e4175e997a5b85eab97d522f00cc99abd1873c Mon Sep 17 00:00:00 2001 From: Ratheesh Kannoth Date: Wed, 21 Jan 2026 09:09:34 +0530 Subject: [PATCH 433/443] octeontx2-af: Fix error handling This commit adds error handling and rollback logic to rvu_mbox_handler_attach_resources() to properly clean up partially attached resources when rvu_attach_block() fails. Fixes: 746ea74241fa0 ("octeontx2-af: Add RVU block LF provisioning support") Signed-off-by: Ratheesh Kannoth Link: https://patch.msgid.link/20260121033934.1900761-1-rkannoth@marvell.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/marvell/octeontx2/af/rvu.c | 86 ++++++++++++++----- 1 file changed, 64 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 2d78e08f985f..747fbdf2a908 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -1551,8 +1551,8 @@ static int rvu_get_attach_blkaddr(struct rvu *rvu, int blktype, return -ENODEV; } -static void rvu_attach_block(struct rvu *rvu, int pcifunc, int blktype, - int num_lfs, struct rsrc_attach *attach) +static int rvu_attach_block(struct rvu *rvu, int pcifunc, int blktype, + int num_lfs, struct rsrc_attach *attach) { struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc); struct rvu_hwinfo *hw = rvu->hw; @@ -1562,21 +1562,21 @@ static void rvu_attach_block(struct rvu *rvu, int pcifunc, int blktype, u64 cfg; if (!num_lfs) - return; + return -EINVAL; blkaddr = rvu_get_attach_blkaddr(rvu, blktype, pcifunc, attach); if (blkaddr < 0) - return; + return -EFAULT; block = &hw->block[blkaddr]; if (!block->lf.bmap) - return; + return -ESRCH; for (slot = 0; slot < num_lfs; slot++) { /* Allocate the resource */ lf = rvu_alloc_rsrc(&block->lf); if (lf < 0) - return; + return -EFAULT; cfg = (1ULL << 63) | (pcifunc << 8) | slot; rvu_write64(rvu, blkaddr, block->lfcfg_reg | @@ -1587,6 +1587,8 @@ static void rvu_attach_block(struct rvu *rvu, int pcifunc, int blktype, /* Set start MSIX vector for this LF within this PF/VF */ rvu_set_msix_offset(rvu, pfvf, block, lf); } + + return 0; } static int rvu_check_rsrc_availability(struct rvu *rvu, @@ -1724,22 +1726,31 @@ int rvu_mbox_handler_attach_resources(struct rvu *rvu, int err; /* If first request, detach all existing attached resources */ - if (!attach->modify) - rvu_detach_rsrcs(rvu, NULL, pcifunc); + if (!attach->modify) { + err = rvu_detach_rsrcs(rvu, NULL, pcifunc); + if (err) + return err; + } mutex_lock(&rvu->rsrc_lock); /* Check if the request can be accommodated */ err = rvu_check_rsrc_availability(rvu, attach, pcifunc); if (err) - goto exit; + goto fail1; /* Now attach the requested resources */ - if (attach->npalf) - rvu_attach_block(rvu, pcifunc, BLKTYPE_NPA, 1, attach); + if (attach->npalf) { + err = rvu_attach_block(rvu, pcifunc, BLKTYPE_NPA, 1, attach); + if (err) + goto fail1; + } - if (attach->nixlf) - rvu_attach_block(rvu, pcifunc, BLKTYPE_NIX, 1, attach); + if (attach->nixlf) { + err = rvu_attach_block(rvu, pcifunc, BLKTYPE_NIX, 1, attach); + if (err) + goto fail2; + } if (attach->sso) { /* RVU func doesn't know which exact LF or slot is attached @@ -1749,33 +1760,64 @@ int rvu_mbox_handler_attach_resources(struct rvu *rvu, */ if (attach->modify) rvu_detach_block(rvu, pcifunc, BLKTYPE_SSO); - rvu_attach_block(rvu, pcifunc, BLKTYPE_SSO, - attach->sso, attach); + err = rvu_attach_block(rvu, pcifunc, BLKTYPE_SSO, + attach->sso, attach); + if (err) + goto fail3; } if (attach->ssow) { if (attach->modify) rvu_detach_block(rvu, pcifunc, BLKTYPE_SSOW); - rvu_attach_block(rvu, pcifunc, BLKTYPE_SSOW, - attach->ssow, attach); + err = rvu_attach_block(rvu, pcifunc, BLKTYPE_SSOW, + attach->ssow, attach); + if (err) + goto fail4; } if (attach->timlfs) { if (attach->modify) rvu_detach_block(rvu, pcifunc, BLKTYPE_TIM); - rvu_attach_block(rvu, pcifunc, BLKTYPE_TIM, - attach->timlfs, attach); + err = rvu_attach_block(rvu, pcifunc, BLKTYPE_TIM, + attach->timlfs, attach); + if (err) + goto fail5; } if (attach->cptlfs) { if (attach->modify && rvu_attach_from_same_block(rvu, BLKTYPE_CPT, attach)) rvu_detach_block(rvu, pcifunc, BLKTYPE_CPT); - rvu_attach_block(rvu, pcifunc, BLKTYPE_CPT, - attach->cptlfs, attach); + err = rvu_attach_block(rvu, pcifunc, BLKTYPE_CPT, + attach->cptlfs, attach); + if (err) + goto fail6; } -exit: + mutex_unlock(&rvu->rsrc_lock); + return 0; + +fail6: + if (attach->timlfs) + rvu_detach_block(rvu, pcifunc, BLKTYPE_TIM); + +fail5: + if (attach->ssow) + rvu_detach_block(rvu, pcifunc, BLKTYPE_SSOW); + +fail4: + if (attach->sso) + rvu_detach_block(rvu, pcifunc, BLKTYPE_SSO); + +fail3: + if (attach->nixlf) + rvu_detach_block(rvu, pcifunc, BLKTYPE_NIX); + +fail2: + if (attach->npalf) + rvu_detach_block(rvu, pcifunc, BLKTYPE_NPA); + +fail1: mutex_unlock(&rvu->rsrc_lock); return err; } From cc4816bdb08639e5cd9acb295a02d6f0f09736b4 Mon Sep 17 00:00:00 2001 From: David Yang Date: Wed, 21 Jan 2026 15:29:26 +0800 Subject: [PATCH 434/443] net: openvswitch: fix data race in ovs_vport_get_upcall_stats In ovs_vport_get_upcall_stats(), some statistics protected by u64_stats_sync, are read and accumulated in ignorance of possible u64_stats_fetch_retry() events. These statistics are already accumulated by u64_stats_inc(). Fix this by reading them into temporary variables first. Fixes: 1933ea365aa7 ("net: openvswitch: Add support to count upcall packets") Signed-off-by: David Yang Acked-by: Ilya Maximets Reviewed-by: Eric Dumazet Reviewed-by: Aaron Conole Link: https://patch.msgid.link/20260121072932.2360971-1-mmyangfl@gmail.com Signed-off-by: Paolo Abeni --- net/openvswitch/vport.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 6bbbc16ab778..f0ce8ce1dce0 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -310,22 +310,23 @@ void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats) */ int ovs_vport_get_upcall_stats(struct vport *vport, struct sk_buff *skb) { + u64 tx_success = 0, tx_fail = 0; struct nlattr *nla; int i; - __u64 tx_success = 0; - __u64 tx_fail = 0; - for_each_possible_cpu(i) { const struct vport_upcall_stats_percpu *stats; + u64 n_success, n_fail; unsigned int start; stats = per_cpu_ptr(vport->upcall_stats, i); do { start = u64_stats_fetch_begin(&stats->syncp); - tx_success += u64_stats_read(&stats->n_success); - tx_fail += u64_stats_read(&stats->n_fail); + n_success = u64_stats_read(&stats->n_success); + n_fail = u64_stats_read(&stats->n_fail); } while (u64_stats_fetch_retry(&stats->syncp, start)); + tx_success += n_success; + tx_fail += n_fail; } nla = nla_nest_start_noflag(skb, OVS_VPORT_ATTR_UPCALL_STATS); From ca1bb3fedf26a08ed31974131bc0064d4fe33649 Mon Sep 17 00:00:00 2001 From: Clemens Gruber Date: Wed, 21 Jan 2026 09:37:51 +0100 Subject: [PATCH 435/443] net: fec: account for VLAN header in frame length calculations The MAX_FL (maximum frame length) and related calculations used ETH_HLEN, which does not account for the 4-byte VLAN tag in tagged frames. This caused the hardware to reject valid VLAN frames as oversized, resulting in RX errors and dropped packets. Use VLAN_ETH_HLEN instead of ETH_HLEN in the MAX_FL register setup, cut-through mode threshold, buffer allocation, and max_mtu calculation. Cc: stable@kernel.org # v6.18+ Fixes: 62b5bb7be7bc ("net: fec: update MAX_FL based on the current MTU") Fixes: d466c16026e9 ("net: fec: enable the Jumbo frame support for i.MX8QM") Fixes: 59e9bf037d75 ("net: fec: add change_mtu to support dynamic buffer allocation") Fixes: ec2a1681ed4f ("net: fec: use a member variable for maximum buffer size") Signed-off-by: Clemens Gruber Reviewed-by: Wei Fang Link: https://patch.msgid.link/20260121083751.66997-1-mail@clemensgruber.at Signed-off-by: Paolo Abeni --- drivers/net/ethernet/freescale/fec_main.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index a753265961af..797ef6899657 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1150,7 +1150,7 @@ fec_restart(struct net_device *ndev) u32 rcntl = FEC_RCR_MII; if (OPT_ARCH_HAS_MAX_FL) - rcntl |= (fep->netdev->mtu + ETH_HLEN + ETH_FCS_LEN) << 16; + rcntl |= (fep->netdev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN) << 16; if (fep->bufdesc_ex) fec_ptp_save_state(fep); @@ -1285,12 +1285,13 @@ fec_restart(struct net_device *ndev) /* When Jumbo Frame is enabled, the FIFO may not be large enough * to hold an entire frame. In such cases, if the MTU exceeds - * (PKT_MAXBUF_SIZE - ETH_HLEN - ETH_FCS_LEN), configure the interface - * to operate in cut-through mode, triggered by the FIFO threshold. + * (PKT_MAXBUF_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN), configure + * the interface to operate in cut-through mode, triggered by + * the FIFO threshold. * Otherwise, enable the ENET store-and-forward mode. */ if ((fep->quirks & FEC_QUIRK_JUMBO_FRAME) && - (ndev->mtu > (PKT_MAXBUF_SIZE - ETH_HLEN - ETH_FCS_LEN))) + (ndev->mtu > (PKT_MAXBUF_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN))) writel(0xF, fep->hwp + FEC_X_WMRK); else writel(FEC_TXWMRK_STRFWD, fep->hwp + FEC_X_WMRK); @@ -4037,7 +4038,7 @@ static int fec_change_mtu(struct net_device *ndev, int new_mtu) if (netif_running(ndev)) return -EBUSY; - order = get_order(new_mtu + ETH_HLEN + ETH_FCS_LEN + order = get_order(new_mtu + VLAN_ETH_HLEN + ETH_FCS_LEN + FEC_DRV_RESERVE_SPACE); fep->rx_frame_size = (PAGE_SIZE << order) - FEC_DRV_RESERVE_SPACE; fep->pagepool_order = order; @@ -4588,7 +4589,7 @@ fec_probe(struct platform_device *pdev) else fep->max_buf_size = PKT_MAXBUF_SIZE; - ndev->max_mtu = fep->max_buf_size - ETH_HLEN - ETH_FCS_LEN; + ndev->max_mtu = fep->max_buf_size - VLAN_ETH_HLEN - ETH_FCS_LEN; ret = register_netdev(ndev); if (ret) From 3ef3d52a1a9860d094395c7a3e593f3aa26ff012 Mon Sep 17 00:00:00 2001 From: Melbin K Mathew Date: Wed, 21 Jan 2026 10:36:25 +0100 Subject: [PATCH 436/443] vsock/virtio: fix potential underflow in virtio_transport_get_credit() The credit calculation in virtio_transport_get_credit() uses unsigned arithmetic: ret = vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt); If the peer shrinks its advertised buffer (peer_buf_alloc) while bytes are in flight, the subtraction can underflow and produce a large positive value, potentially allowing more data to be queued than the peer can handle. Reuse virtio_transport_has_space() which already handles this case and add a comment to make it clear why we are doing that. Fixes: 06a8fc78367d ("VSOCK: Introduce virtio_vsock_common.ko") Suggested-by: Stefano Garzarella Signed-off-by: Melbin K Mathew [Stefano: use virtio_transport_has_space() instead of duplicating the code] [Stefano: tweak the commit message] Signed-off-by: Stefano Garzarella Reviewed-by: Luigi Leonardi Link: https://patch.msgid.link/20260121093628.9941-2-sgarzare@redhat.com Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Abeni --- net/vmw_vsock/virtio_transport_common.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c index 26b979ad71f0..6175124d63d3 100644 --- a/net/vmw_vsock/virtio_transport_common.c +++ b/net/vmw_vsock/virtio_transport_common.c @@ -28,6 +28,7 @@ static void virtio_transport_cancel_close_work(struct vsock_sock *vsk, bool cancel_timeout); +static s64 virtio_transport_has_space(struct virtio_vsock_sock *vvs); static const struct virtio_transport * virtio_transport_get_ops(struct vsock_sock *vsk) @@ -499,9 +500,7 @@ u32 virtio_transport_get_credit(struct virtio_vsock_sock *vvs, u32 credit) return 0; spin_lock_bh(&vvs->tx_lock); - ret = vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt); - if (ret > credit) - ret = credit; + ret = min_t(u32, credit, virtio_transport_has_space(vvs)); vvs->tx_cnt += ret; vvs->bytes_unsent += ret; spin_unlock_bh(&vvs->tx_lock); @@ -877,11 +876,14 @@ u32 virtio_transport_seqpacket_has_data(struct vsock_sock *vsk) } EXPORT_SYMBOL_GPL(virtio_transport_seqpacket_has_data); -static s64 virtio_transport_has_space(struct vsock_sock *vsk) +static s64 virtio_transport_has_space(struct virtio_vsock_sock *vvs) { - struct virtio_vsock_sock *vvs = vsk->trans; s64 bytes; + /* Use s64 arithmetic so if the peer shrinks peer_buf_alloc while + * we have bytes in flight (tx_cnt - peer_fwd_cnt), the subtraction + * does not underflow. + */ bytes = (s64)vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt); if (bytes < 0) bytes = 0; @@ -895,7 +897,7 @@ s64 virtio_transport_stream_has_space(struct vsock_sock *vsk) s64 bytes; spin_lock_bh(&vvs->tx_lock); - bytes = virtio_transport_has_space(vsk); + bytes = virtio_transport_has_space(vvs); spin_unlock_bh(&vvs->tx_lock); return bytes; @@ -1492,7 +1494,7 @@ static bool virtio_transport_space_update(struct sock *sk, spin_lock_bh(&vvs->tx_lock); vvs->peer_buf_alloc = le32_to_cpu(hdr->buf_alloc); vvs->peer_fwd_cnt = le32_to_cpu(hdr->fwd_cnt); - space_available = virtio_transport_has_space(vsk); + space_available = virtio_transport_has_space(vvs); spin_unlock_bh(&vvs->tx_lock); return space_available; } From 0a98de80136968bab7db37b16282b37f044694d3 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Wed, 21 Jan 2026 10:36:26 +0100 Subject: [PATCH 437/443] vsock/test: fix seqpacket message bounds test The test requires the sender (client) to send all messages before waking up the receiver (server). Since virtio-vsock had a bug and did not respect the size of the TX buffer, this test worked, but now that we are going to fix the bug, the test hangs because the sender would fill the TX buffer before waking up the receiver. Set the buffer size in the sender (client) as well, as we already do for the receiver (server). Fixes: 5c338112e48a ("test/vsock: rework message bounds test") Signed-off-by: Stefano Garzarella Link: https://patch.msgid.link/20260121093628.9941-3-sgarzare@redhat.com Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Abeni --- tools/testing/vsock/vsock_test.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c index 27e39354499a..668fbe9eb3cc 100644 --- a/tools/testing/vsock/vsock_test.c +++ b/tools/testing/vsock/vsock_test.c @@ -351,6 +351,7 @@ static void test_stream_msg_peek_server(const struct test_opts *opts) static void test_seqpacket_msg_bounds_client(const struct test_opts *opts) { + unsigned long long sock_buf_size; unsigned long curr_hash; size_t max_msg_size; int page_size; @@ -363,6 +364,16 @@ static void test_seqpacket_msg_bounds_client(const struct test_opts *opts) exit(EXIT_FAILURE); } + sock_buf_size = SOCK_BUF_SIZE; + + setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE, + sock_buf_size, + "setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)"); + + setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, + sock_buf_size, + "setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)"); + /* Wait, until receiver sets buffer size. */ control_expectln("SRVREADY"); From 8ee784fdf006cbe8739cfa093f54d326cbf54037 Mon Sep 17 00:00:00 2001 From: Melbin K Mathew Date: Wed, 21 Jan 2026 10:36:27 +0100 Subject: [PATCH 438/443] vsock/virtio: cap TX credit to local buffer size The virtio transports derives its TX credit directly from peer_buf_alloc, which is set from the remote endpoint's SO_VM_SOCKETS_BUFFER_SIZE value. On the host side this means that the amount of data we are willing to queue for a connection is scaled by a guest-chosen buffer size, rather than the host's own vsock configuration. A malicious guest can advertise a large buffer and read slowly, causing the host to allocate a correspondingly large amount of sk_buff memory. The same thing would happen in the guest with a malicious host, since virtio transports share the same code base. Introduce a small helper, virtio_transport_tx_buf_size(), that returns min(peer_buf_alloc, buf_alloc), and use it wherever we consume peer_buf_alloc. This ensures the effective TX window is bounded by both the peer's advertised buffer and our own buf_alloc (already clamped to buffer_max_size via SO_VM_SOCKETS_BUFFER_MAX_SIZE), so a remote peer cannot force the other to queue more data than allowed by its own vsock settings. On an unpatched Ubuntu 22.04 host (~64 GiB RAM), running a PoC with 32 guest vsock connections advertising 2 GiB each and reading slowly drove Slab/SUnreclaim from ~0.5 GiB to ~57 GiB; the system only recovered after killing the QEMU process. That said, if QEMU memory is limited with cgroups, the maximum memory used will be limited. With this patch applied: Before: MemFree: ~61.6 GiB Slab: ~142 MiB SUnreclaim: ~117 MiB After 32 high-credit connections: MemFree: ~61.5 GiB Slab: ~178 MiB SUnreclaim: ~152 MiB Only ~35 MiB increase in Slab/SUnreclaim, no host OOM, and the guest remains responsive. Compatibility with non-virtio transports: - VMCI uses the AF_VSOCK buffer knobs to size its queue pairs per socket based on the local vsk->buffer_* values; the remote side cannot enlarge those queues beyond what the local endpoint configured. - Hyper-V's vsock transport uses fixed-size VMBus ring buffers and an MTU bound; there is no peer-controlled credit field comparable to peer_buf_alloc, and the remote endpoint cannot drive in-flight kernel memory above those ring sizes. - The loopback path reuses virtio_transport_common.c, so it naturally follows the same semantics as the virtio transport. This change is limited to virtio_transport_common.c and thus affects virtio-vsock, vhost-vsock, and loopback, bringing them in line with the "remote window intersected with local policy" behaviour that VMCI and Hyper-V already effectively have. Fixes: 06a8fc78367d ("VSOCK: Introduce virtio_vsock_common.ko") Suggested-by: Stefano Garzarella Signed-off-by: Melbin K Mathew [Stefano: small adjustments after changing the previous patch] [Stefano: tweak the commit message] Signed-off-by: Stefano Garzarella Reviewed-by: Luigi Leonardi Link: https://patch.msgid.link/20260121093628.9941-4-sgarzare@redhat.com Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Abeni --- net/vmw_vsock/virtio_transport_common.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c index 6175124d63d3..d3e26025ef58 100644 --- a/net/vmw_vsock/virtio_transport_common.c +++ b/net/vmw_vsock/virtio_transport_common.c @@ -821,6 +821,15 @@ virtio_transport_seqpacket_dequeue(struct vsock_sock *vsk, } EXPORT_SYMBOL_GPL(virtio_transport_seqpacket_dequeue); +static u32 virtio_transport_tx_buf_size(struct virtio_vsock_sock *vvs) +{ + /* The peer advertises its receive buffer via peer_buf_alloc, but we + * cap it to our local buf_alloc so a remote peer cannot force us to + * queue more data than our own buffer configuration allows. + */ + return min(vvs->peer_buf_alloc, vvs->buf_alloc); +} + int virtio_transport_seqpacket_enqueue(struct vsock_sock *vsk, struct msghdr *msg, @@ -830,7 +839,7 @@ virtio_transport_seqpacket_enqueue(struct vsock_sock *vsk, spin_lock_bh(&vvs->tx_lock); - if (len > vvs->peer_buf_alloc) { + if (len > virtio_transport_tx_buf_size(vvs)) { spin_unlock_bh(&vvs->tx_lock); return -EMSGSIZE; } @@ -884,7 +893,8 @@ static s64 virtio_transport_has_space(struct virtio_vsock_sock *vvs) * we have bytes in flight (tx_cnt - peer_fwd_cnt), the subtraction * does not underflow. */ - bytes = (s64)vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt); + bytes = (s64)virtio_transport_tx_buf_size(vvs) - + (vvs->tx_cnt - vvs->peer_fwd_cnt); if (bytes < 0) bytes = 0; From 2a689f76edd04a53137bd01d4618343f4cdd7e23 Mon Sep 17 00:00:00 2001 From: Melbin K Mathew Date: Wed, 21 Jan 2026 10:36:28 +0100 Subject: [PATCH 439/443] vsock/test: add stream TX credit bounds test Add a regression test for the TX credit bounds fix. The test verifies that a sender with a small local buffer size cannot queue excessive data even when the peer advertises a large receive buffer. The client: - Sets a small buffer size (64 KiB) - Connects to server (which advertises 2 MiB buffer) - Sends in non-blocking mode until EAGAIN - Verifies total queued data is bounded This guards against the original vulnerability where a remote peer could cause unbounded kernel memory allocation by advertising a large buffer and reading slowly. Suggested-by: Stefano Garzarella Signed-off-by: Melbin K Mathew [Stefano: use sock_buf_size to check the bytes sent + small fixes] Signed-off-by: Stefano Garzarella Link: https://patch.msgid.link/20260121093628.9941-5-sgarzare@redhat.com Acked-by: Michael S. Tsirkin Signed-off-by: Paolo Abeni --- tools/testing/vsock/vsock_test.c | 101 +++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c index 668fbe9eb3cc..5bd20ccd9335 100644 --- a/tools/testing/vsock/vsock_test.c +++ b/tools/testing/vsock/vsock_test.c @@ -347,6 +347,7 @@ static void test_stream_msg_peek_server(const struct test_opts *opts) } #define SOCK_BUF_SIZE (2 * 1024 * 1024) +#define SOCK_BUF_SIZE_SMALL (64 * 1024) #define MAX_MSG_PAGES 4 static void test_seqpacket_msg_bounds_client(const struct test_opts *opts) @@ -2230,6 +2231,101 @@ static void test_stream_accepted_setsockopt_server(const struct test_opts *opts) close(fd); } +static void test_stream_tx_credit_bounds_client(const struct test_opts *opts) +{ + unsigned long long sock_buf_size; + size_t total = 0; + char buf[4096]; + int fd; + + memset(buf, 'A', sizeof(buf)); + + fd = vsock_stream_connect(opts->peer_cid, opts->peer_port); + if (fd < 0) { + perror("connect"); + exit(EXIT_FAILURE); + } + + sock_buf_size = SOCK_BUF_SIZE_SMALL; + + setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE, + sock_buf_size, + "setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)"); + + setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, + sock_buf_size, + "setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)"); + + if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) { + perror("fcntl(F_SETFL)"); + exit(EXIT_FAILURE); + } + + control_expectln("SRVREADY"); + + for (;;) { + ssize_t sent = send(fd, buf, sizeof(buf), 0); + + if (sent == 0) { + fprintf(stderr, "unexpected EOF while sending bytes\n"); + exit(EXIT_FAILURE); + } + + if (sent < 0) { + if (errno == EINTR) + continue; + + if (errno == EAGAIN || errno == EWOULDBLOCK) + break; + + perror("send"); + exit(EXIT_FAILURE); + } + + total += sent; + } + + control_writeln("CLIDONE"); + close(fd); + + /* We should not be able to send more bytes than the value set as + * local buffer size. + */ + if (total > sock_buf_size) { + fprintf(stderr, + "TX credit too large: queued %zu bytes (expected <= %llu)\n", + total, sock_buf_size); + exit(EXIT_FAILURE); + } +} + +static void test_stream_tx_credit_bounds_server(const struct test_opts *opts) +{ + unsigned long long sock_buf_size; + int fd; + + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); + if (fd < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } + + sock_buf_size = SOCK_BUF_SIZE; + + setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE, + sock_buf_size, + "setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)"); + + setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, + sock_buf_size, + "setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)"); + + control_writeln("SRVREADY"); + control_expectln("CLIDONE"); + + close(fd); +} + static struct test_case test_cases[] = { { .name = "SOCK_STREAM connection reset", @@ -2419,6 +2515,11 @@ static struct test_case test_cases[] = { .run_client = test_stream_msgzcopy_mangle_client, .run_server = test_stream_msgzcopy_mangle_server, }, + { + .name = "SOCK_STREAM TX credit bounds", + .run_client = test_stream_tx_credit_bounds_client, + .run_server = test_stream_tx_credit_bounds_server, + }, {}, }; From fb2bb2a1ebf7b9514c32b03bb5c3be5d518d437b Mon Sep 17 00:00:00 2001 From: Fan Gong Date: Thu, 22 Jan 2026 17:41:55 +0800 Subject: [PATCH 440/443] hinic3: Fix netif_queue_set_napi queue_index input parameter error Incorrectly transmitted interrupt number instead of queue number when using netif_queue_set_napi. Besides, move this to appropriate code location to set napi. Remove redundant netif_stop_subqueue beacuase it is not part of the hinic3_send_one_skb process. Fixes: 17fcb3dc12bb ("hinic3: module initialization and tx/rx logic") Co-developed-by: Zhu Yikai Signed-off-by: Zhu Yikai Signed-off-by: Fan Gong Link: https://patch.msgid.link/7b8e4eb5c53cbd873ee9aaefeb3d9dbbaff52deb.1769070766.git.zhuyikai1@h-partners.com Signed-off-by: Jakub Kicinski --- .../net/ethernet/huawei/hinic3/hinic3_irq.c | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c index a69b361225e9..84bee5d6e638 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_irq.c @@ -43,21 +43,12 @@ static void qp_add_napi(struct hinic3_irq_cfg *irq_cfg) struct hinic3_nic_dev *nic_dev = netdev_priv(irq_cfg->netdev); netif_napi_add(nic_dev->netdev, &irq_cfg->napi, hinic3_poll); - netif_queue_set_napi(irq_cfg->netdev, irq_cfg->irq_id, - NETDEV_QUEUE_TYPE_RX, &irq_cfg->napi); - netif_queue_set_napi(irq_cfg->netdev, irq_cfg->irq_id, - NETDEV_QUEUE_TYPE_TX, &irq_cfg->napi); napi_enable(&irq_cfg->napi); } static void qp_del_napi(struct hinic3_irq_cfg *irq_cfg) { napi_disable(&irq_cfg->napi); - netif_queue_set_napi(irq_cfg->netdev, irq_cfg->irq_id, - NETDEV_QUEUE_TYPE_RX, NULL); - netif_queue_set_napi(irq_cfg->netdev, irq_cfg->irq_id, - NETDEV_QUEUE_TYPE_TX, NULL); - netif_stop_subqueue(irq_cfg->netdev, irq_cfg->irq_id); netif_napi_del(&irq_cfg->napi); } @@ -150,6 +141,11 @@ int hinic3_qps_irq_init(struct net_device *netdev) goto err_release_irqs; } + netif_queue_set_napi(irq_cfg->netdev, q_id, + NETDEV_QUEUE_TYPE_RX, &irq_cfg->napi); + netif_queue_set_napi(irq_cfg->netdev, q_id, + NETDEV_QUEUE_TYPE_TX, &irq_cfg->napi); + hinic3_set_msix_auto_mask_state(nic_dev->hwdev, irq_cfg->msix_entry_idx, HINIC3_SET_MSIX_AUTO_MASK); @@ -164,6 +160,10 @@ err_release_irqs: q_id--; irq_cfg = &nic_dev->q_params.irq_cfg[q_id]; qp_del_napi(irq_cfg); + netif_queue_set_napi(irq_cfg->netdev, q_id, + NETDEV_QUEUE_TYPE_RX, NULL); + netif_queue_set_napi(irq_cfg->netdev, q_id, + NETDEV_QUEUE_TYPE_TX, NULL); hinic3_set_msix_state(nic_dev->hwdev, irq_cfg->msix_entry_idx, HINIC3_MSIX_DISABLE); hinic3_set_msix_auto_mask_state(nic_dev->hwdev, @@ -184,6 +184,10 @@ void hinic3_qps_irq_uninit(struct net_device *netdev) for (q_id = 0; q_id < nic_dev->q_params.num_qps; q_id++) { irq_cfg = &nic_dev->q_params.irq_cfg[q_id]; qp_del_napi(irq_cfg); + netif_queue_set_napi(irq_cfg->netdev, q_id, + NETDEV_QUEUE_TYPE_RX, NULL); + netif_queue_set_napi(irq_cfg->netdev, q_id, + NETDEV_QUEUE_TYPE_TX, NULL); hinic3_set_msix_state(nic_dev->hwdev, irq_cfg->msix_entry_idx, HINIC3_MSIX_DISABLE); hinic3_set_msix_auto_mask_state(nic_dev->hwdev, From 27880b0b0d35ad1c98863d09788254e36f874968 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 21 Jan 2026 13:37:24 +0000 Subject: [PATCH 441/443] net/sched: act_ife: avoid possible NULL deref tcf_ife_encode() must make sure ife_encode() does not return NULL. syzbot reported: Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] RIP: 0010:ife_tlv_meta_encode+0x41/0xa0 net/ife/ife.c:166 CPU: 3 UID: 0 PID: 8990 Comm: syz.0.696 Not tainted syzkaller #0 PREEMPT(full) Call Trace: ife_encode_meta_u32+0x153/0x180 net/sched/act_ife.c:101 tcf_ife_encode net/sched/act_ife.c:841 [inline] tcf_ife_act+0x1022/0x1de0 net/sched/act_ife.c:877 tc_act include/net/tc_wrapper.h:130 [inline] tcf_action_exec+0x1c0/0xa20 net/sched/act_api.c:1152 tcf_exts_exec include/net/pkt_cls.h:349 [inline] mall_classify+0x1a0/0x2a0 net/sched/cls_matchall.c:42 tc_classify include/net/tc_wrapper.h:197 [inline] __tcf_classify net/sched/cls_api.c:1764 [inline] tcf_classify+0x7f2/0x1380 net/sched/cls_api.c:1860 multiq_classify net/sched/sch_multiq.c:39 [inline] multiq_enqueue+0xe0/0x510 net/sched/sch_multiq.c:66 dev_qdisc_enqueue+0x45/0x250 net/core/dev.c:4147 __dev_xmit_skb net/core/dev.c:4262 [inline] __dev_queue_xmit+0x2998/0x46c0 net/core/dev.c:4798 Fixes: 295a6e06d21e ("net/sched: act_ife: Change to use ife module") Reported-by: syzbot+5cf914f193dffde3bd3c@syzkaller.appspotmail.com Closes: https://lore.kernel.org/netdev/6970d61d.050a0220.706b.0010.GAE@google.com/T/#u Signed-off-by: Eric Dumazet Cc: Yotam Gigi Reviewed-by: Jamal Hadi Salim Link: https://patch.msgid.link/20260121133724.3400020-1-edumazet@google.com Signed-off-by: Jakub Kicinski --- net/sched/act_ife.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c index 1dfdda6c2d4c..8e8f6af731d5 100644 --- a/net/sched/act_ife.c +++ b/net/sched/act_ife.c @@ -821,6 +821,7 @@ static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a, /* could be stupid policy setup or mtu config * so lets be conservative.. */ if ((action == TC_ACT_SHOT) || exceed_mtu) { +drop: qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats)); return TC_ACT_SHOT; } @@ -829,6 +830,8 @@ static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a, skb_push(skb, skb->dev->hard_header_len); ife_meta = ife_encode(skb, metalen); + if (!ife_meta) + goto drop; spin_lock(&ife->tcf_lock); @@ -844,8 +847,7 @@ static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a, if (err < 0) { /* too corrupt to keep around if overwritten */ spin_unlock(&ife->tcf_lock); - qstats_drop_inc(this_cpu_ptr(ife->common.cpu_qstats)); - return TC_ACT_SHOT; + goto drop; } skboff += err; } From f3ddbaaaaf4d0633b40482f471753f9c71294a4a Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Wed, 21 Jan 2026 14:00:11 +0100 Subject: [PATCH 442/443] dpll: Prevent duplicate registrations Modify the internal registration helpers dpll_xa_ref_{dpll,pin}_add() to reject duplicate registration attempts. Previously, if a caller attempted to register the same pin multiple times (with the same ops, priv, and cookie) on the same device, the core silently increments the reference count and return success. This behavior is incorrect because if the caller makes these duplicate registrations then for the first one dpll_pin_registration is allocated and for others the associated dpll_pin_ref.refcount is incremented. During the first unregistration the associated dpll_pin_registration is freed and for others WARN is fired. Fix this by updating the logic to return `-EEXIST` if a matching registration is found to enforce a strict "register once" policy. Fixes: 9431063ad323 ("dpll: core: Add DPLL framework base functions") Signed-off-by: Ivan Vecera Reviewed-by: Arkadiusz Kubalewski Reviewed-by: Vadim Fedorenko Link: https://patch.msgid.link/20260121130012.112606-1-ivecera@redhat.com Signed-off-by: Jakub Kicinski --- drivers/dpll/dpll_core.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index a461095efd8a..8879a7235156 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -83,10 +83,8 @@ dpll_xa_ref_pin_add(struct xarray *xa_pins, struct dpll_pin *pin, if (ref->pin != pin) continue; reg = dpll_pin_registration_find(ref, ops, priv, cookie); - if (reg) { - refcount_inc(&ref->refcount); - return 0; - } + if (reg) + return -EEXIST; ref_exists = true; break; } @@ -164,10 +162,8 @@ dpll_xa_ref_dpll_add(struct xarray *xa_dplls, struct dpll_device *dpll, if (ref->dpll != dpll) continue; reg = dpll_pin_registration_find(ref, ops, priv, cookie); - if (reg) { - refcount_inc(&ref->refcount); - return 0; - } + if (reg) + return -EEXIST; ref_exists = true; break; } From 4a3dba48188208e4f66822800e042686784d29d1 Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Wed, 21 Jan 2026 15:18:19 +0530 Subject: [PATCH 443/443] Octeontx2-af: Add proper checks for fwdata firmware populates MAC address, link modes (supported, advertised) and EEPROM data in shared firmware structure which kernel access via MAC block(CGX/RPM). Accessing fwdata, on boards booted with out MAC block leading to kernel panics. Internal error: Oops: 0000000096000005 [#1] SMP [ 10.460721] Modules linked in: [ 10.463779] CPU: 0 UID: 0 PID: 174 Comm: kworker/0:3 Not tainted 6.19.0-rc5-00154-g76ec646abdf7-dirty #3 PREEMPT [ 10.474045] Hardware name: Marvell OcteonTX CN98XX board (DT) [ 10.479793] Workqueue: events work_for_cpu_fn [ 10.484159] pstate: 80400009 (Nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 10.491124] pc : rvu_sdp_init+0x18/0x114 [ 10.495051] lr : rvu_probe+0xe58/0x1d18 Fixes: 997814491cee ("Octeontx2-af: Fetch MAC channel info from firmware") Fixes: 5f21226b79fd ("Octeontx2-pf: ethtool: support multi advertise mode") Signed-off-by: Hariprasad Kelam Link: https://patch.msgid.link/20260121094819.2566786-1-hkelam@marvell.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c | 3 +++ drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c index 3abd750a4bd7..3d91a34f8b57 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c @@ -1222,6 +1222,9 @@ int rvu_mbox_handler_cgx_set_link_mode(struct rvu *rvu, u8 cgx_idx, lmac; void *cgxd; + if (!rvu->fwdata) + return LMAC_AF_ERR_FIRMWARE_DATA_NOT_MAPPED; + if (!is_cgx_config_permitted(rvu, req->hdr.pcifunc)) return -EPERM; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c index e4a5f9fa6fd4..bbfd8231aed5 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_sdp.c @@ -56,7 +56,7 @@ int rvu_sdp_init(struct rvu *rvu) struct rvu_pfvf *pfvf; u32 i = 0; - if (rvu->fwdata->channel_data.valid) { + if (rvu->fwdata && rvu->fwdata->channel_data.valid) { sdp_pf_num[0] = 0; pfvf = &rvu->pf[sdp_pf_num[0]]; pfvf->sdp_info = &rvu->fwdata->channel_data.info;